[BUGFIX] Split jQuery and DataTables into separate files
[Packages/TYPO3.CMS.git] / typo3 / sysext / integrity / Classes / VersionsCommand.php
1 <?php
2 namespace TYPO3\CMS\Integrity;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Cleaner module: Versions of records
31 * User function called from tx_lowlevel_cleaner_core configured in ext_localconf.php
32 *
33 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
34 */
35 /**
36 * Looking for versions of records
37 *
38 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
39 * @package TYPO3
40 * @subpackage tx_lowlevel
41 */
42 class VersionsCommand extends \TYPO3\CMS\Integrity\CleanerCommand {
43
44 /**
45 * Constructor
46 *
47 * @todo Define visibility
48 */
49 public function __construct() {
50 parent::__construct();
51 // Setting up help:
52 $this->cli_options[] = array('--echotree level', 'When "level" is set to 1 or higher you will see the page of the page tree outputted as it is traversed. A value of 2 for "level" will show even more information.');
53 $this->cli_options[] = array('--pid id', 'Setting start page in page tree. Default is the page tree root, 0 (zero)');
54 $this->cli_options[] = array('--depth int', 'Setting traversal depth. 0 (zero) will only analyse start page (see --pid), 1 will traverse one level of subpages etc.');
55 $this->cli_options[] = array('--flush-live', 'If set, not only published versions from Live workspace are flushed, but ALL versions from Live workspace (which are offline of course)');
56 $this->cli_help['name'] = 'versions -- To find information about versions and workspaces in the system';
57 $this->cli_help['description'] = trim('
58 Traversing page tree and finding versions, categorizing them by various properties.
59 Published versions from the Live workspace are registered. So are all offline versions from Live workspace in general. Further, versions in non-existing workspaces are found.
60
61 Automatic Repair:
62 - Deleting (completely) published versions from LIVE workspace OR _all_ offline versions from Live workspace (toogle by --flush-live)
63 - Resetting workspace for versions where workspace is deleted. (You might want to run this tool again after this operation to clean out those new elements in the Live workspace)
64 - Deleting unused placeholders
65 ');
66 $this->cli_help['examples'] = '';
67 }
68
69 /**
70 * Find orphan records
71 * VERY CPU and memory intensive since it will look up the whole page tree!
72 *
73 * @return array
74 * @todo Define visibility
75 */
76 public function main() {
77 global $TYPO3_DB;
78 // Initialize result array:
79 $resultArray = array(
80 'message' => $this->cli_help['name'] . LF . LF . $this->cli_help['description'],
81 'headers' => array(
82 'versions' => array('All versions', 'Showing all versions of records found', 0),
83 'versions_published' => array('All published versions', 'This is all records that has been published and can therefore be removed permanently', 1),
84 'versions_liveWS' => array('All versions in Live workspace', 'This is all records that are offline versions in the Live workspace. You may wish to flush these if you only use workspaces for versioning since then you might find lots of versions piling up in the live workspace which have simply been disconnected from the workspace before they were published.', 1),
85 'versions_lost_workspace' => array('Versions outside a workspace', 'Versions that has lost their connection to a workspace in TYPO3.', 3),
86 'versions_inside_versioned_page' => array('Versions in versions', 'Versions inside an already versioned page. Something that is confusing to users and therefore should not happen but is technically possible.', 2),
87 'versions_unused_placeholders' => array('Unused placeholder records', 'Placeholder records which are not used anymore by offline versions.', 2),
88 'versions_move_placeholders_ok' => array('Move placeholders', 'Move-to placeholder records which has good integrity', 0),
89 'versions_move_placeholders_bad' => array('Move placeholders with bad integrity', 'Move-to placeholder records which has bad integrity', 2),
90 'versions_move_id_check' => array('Checking if t3ver_move_id is correct', 't3ver_move_id must only be set with online records having t3ver_state=3.', 2)
91 ),
92 'versions' => array()
93 );
94 $startingPoint = $this->cli_isArg('--pid') ? \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->cli_argValue('--pid'), 0) : 0;
95 $depth = $this->cli_isArg('--depth') ? \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->cli_argValue('--depth'), 0) : 1000;
96 $this->genTree($startingPoint, $depth, (int) $this->cli_argValue('--echotree'));
97 $resultArray['versions'] = $this->recStats['versions'];
98 $resultArray['versions_published'] = $this->recStats['versions_published'];
99 $resultArray['versions_liveWS'] = $this->recStats['versions_liveWS'];
100 $resultArray['versions_lost_workspace'] = $this->recStats['versions_lost_workspace'];
101 $resultArray['versions_inside_versioned_page'] = $this->recStats['versions_inside_versioned_page'];
102 // Finding all placeholders with no records attached!
103 $resultArray['versions_unused_placeholders'] = array();
104 foreach ($GLOBALS['TCA'] as $table => $cfg) {
105 if ($cfg['ctrl']['versioningWS']) {
106 $placeHolders = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,pid', $table, 't3ver_state=1 AND pid>=0' . \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause($table));
107 foreach ($placeHolders as $phrec) {
108 if (count(\TYPO3\CMS\Backend\Utility\BackendUtility::selectVersionsOfRecord($table, $phrec['uid'], 'uid')) <= 1) {
109 $resultArray['versions_unused_placeholders'][\TYPO3\CMS\Core\Utility\GeneralUtility::shortmd5($table . ':' . $phrec['uid'])] = $table . ':' . $phrec['uid'];
110 }
111 }
112 }
113 }
114 asort($resultArray['versions_unused_placeholders']);
115 // Finding all move placeholders with inconsistencies:
116 $resultArray['versions_move_placeholders_ok'] = array();
117 $resultArray['versions_move_placeholders_bad'] = array();
118 foreach ($GLOBALS['TCA'] as $table => $cfg) {
119 if ((int) $cfg['ctrl']['versioningWS'] >= 2) {
120 $placeHolders = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,pid,t3ver_move_id,t3ver_wsid,t3ver_state', $table, 't3ver_state=3 AND pid>=0' . \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause($table));
121 foreach ($placeHolders as $phrec) {
122 $shortID = \TYPO3\CMS\Core\Utility\GeneralUtility::shortmd5($table . ':' . $phrec['uid']);
123 if ((int) $phrec['t3ver_wsid'] != 0) {
124 $phrecCopy = $phrec;
125 if (\TYPO3\CMS\Backend\Utility\BackendUtility::movePlhOL($table, $phrec)) {
126 if ($wsAlt = \TYPO3\CMS\Backend\Utility\BackendUtility::getWorkspaceVersionOfRecord($phrecCopy['t3ver_wsid'], $table, $phrec['uid'], 'uid,pid,t3ver_state')) {
127 if ($wsAlt['t3ver_state'] != 4) {
128 $resultArray['versions_move_placeholders_bad'][$shortID] = array($table . ':' . $phrec['uid'], 'State for version was not "4" as it should be!', $phrecCopy);
129 } else {
130 $resultArray['versions_move_placeholders_ok'][$shortID] = array(
131 $table . ':' . $phrec['uid'],
132 'PLH' => $phrecCopy,
133 'online' => $phrec,
134 'PNT' => $wsAlt
135 );
136 }
137 } else {
138 $resultArray['versions_move_placeholders_bad'][$shortID] = array($table . ':' . $phrec['uid'], 'No version was found for online record to be moved. A version must exist.', $phrecCopy);
139 }
140 } else {
141 $resultArray['versions_move_placeholders_bad'][$shortID] = array($table . ':' . $phrec['uid'], 'Did not find online record for "t3ver_move_id" value ' . $phrec['t3ver_move_id'], $phrec);
142 }
143 } else {
144 $resultArray['versions_move_placeholders_bad'][$shortID] = array($table . ':' . $phrec['uid'], 'Placeholder was not assigned a workspace value in t3ver_wsid.', $phrec);
145 }
146 }
147 }
148 }
149 ksort($resultArray['versions_move_placeholders_ok']);
150 ksort($resultArray['versions_move_placeholders_bad']);
151 // Finding move_id_check inconsistencies:
152 $resultArray['versions_move_id_check'] = array();
153 foreach ($GLOBALS['TCA'] as $table => $cfg) {
154 if ((int) $cfg['ctrl']['versioningWS'] >= 2) {
155 $placeHolders = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,pid,t3ver_move_id,t3ver_wsid,t3ver_state', $table, 't3ver_move_id<>0' . \TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause($table));
156 foreach ($placeHolders as $phrec) {
157 if ((int) $phrec['t3ver_state'] == 3) {
158 if ($phrec['pid'] != -1) {
159
160 } else {
161 $resultArray['versions_move_id_check'][] = array($table . ':' . $phrec['uid'], 'Record was offline, must not be!', $phrec);
162 }
163 } else {
164 $resultArray['versions_move_id_check'][] = array($table . ':' . $phrec['uid'], 'Record had t3ver_move_id set to "' . $phrec['t3ver_move_id'] . '" while having t3ver_state=' . $phrec['t3ver_state'], $phrec);
165 }
166 }
167 }
168 }
169 return $resultArray;
170 }
171
172 /**
173 * Mandatory autofix function
174 * Will run auto-fix on the result array. Echos status during processing.
175 *
176 * @param array $resultArray Result array from main() function
177 * @return void
178 * @todo Define visibility
179 */
180 public function main_autoFix($resultArray) {
181 $kk = $this->cli_isArg('--flush-live') ? 'versions_liveWS' : 'versions_published';
182 // Putting "pages" table in the bottom:
183 if (isset($resultArray[$kk]['pages'])) {
184 $_pages = $resultArray[$kk]['pages'];
185 unset($resultArray[$kk]['pages']);
186 $resultArray[$kk]['pages'] = $_pages;
187 }
188 // Traversing records:
189 foreach ($resultArray[$kk] as $table => $list) {
190 echo 'Flushing published records from table "' . $table . '":' . LF;
191 foreach ($list as $uid) {
192 echo ' Flushing record "' . $table . ':' . $uid . '": ';
193 if ($bypass = $this->cli_noExecutionCheck($table . ':' . $uid)) {
194 echo $bypass;
195 } else {
196 // Execute CMD array:
197 $tce = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\DataHandling\\DataHandler');
198 $tce->stripslashes_values = FALSE;
199 $tce->start(array(), array());
200 $tce->deleteEl($table, $uid, TRUE, TRUE);
201 // Return errors if any:
202 if (count($tce->errorLog)) {
203 echo ' ERROR from "TCEmain":' . LF . 'TCEmain:' . implode((LF . 'TCEmain:'), $tce->errorLog);
204 } else {
205 echo 'DONE';
206 }
207 }
208 echo LF;
209 }
210 }
211 // Traverse workspace:
212 foreach ($resultArray['versions_lost_workspace'] as $table => $list) {
213 echo 'Resetting workspace to zero for records from table "' . $table . '":' . LF;
214 foreach ($list as $uid) {
215 echo ' Flushing record "' . $table . ':' . $uid . '": ';
216 if ($bypass = $this->cli_noExecutionCheck($table . ':' . $uid)) {
217 echo $bypass;
218 } else {
219 $fields_values = array(
220 't3ver_wsid' => 0
221 );
222 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($uid), $fields_values);
223 echo 'DONE';
224 }
225 echo LF;
226 }
227 }
228 // Delete unused placeholders
229 foreach ($resultArray['versions_unused_placeholders'] as $recID) {
230 list($table, $uid) = explode(':', $recID);
231 echo 'Deleting unused placeholder (soft) "' . $table . ':' . $uid . '": ';
232 if ($bypass = $this->cli_noExecutionCheck($table . ':' . $uid)) {
233 echo $bypass;
234 } else {
235 // Execute CMD array:
236 $tce = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\DataHandling\\DataHandler');
237 $tce->stripslashes_values = FALSE;
238 $tce->start(array(), array());
239 $tce->deleteAction($table, $uid);
240 // Return errors if any:
241 if (count($tce->errorLog)) {
242 echo ' ERROR from "TCEmain":' . LF . 'TCEmain:' . implode((LF . 'TCEmain:'), $tce->errorLog);
243 } else {
244 echo 'DONE';
245 }
246 }
247 echo LF;
248 }
249 }
250
251 }
252
253
254 ?>