8c3a968185cdbf31531f45bc8ce7534e42f0a85d
[Packages/TYPO3.CMS.git] / typo3 / sysext / lowlevel / clmods / clmods / class.orphan_records.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2005 Kasper Skaarhoj (kasperYYYY@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Cleaner module: Orphan records
29 * User function called from tx_lowlevel_cleaner_core configured in ext_localconf.php
30 *
31 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
32 */
33 /**
34 * [CLASS/FUNCTION INDEX of SCRIPT]
35 *
36 *
37 *
38 * 56: class tx_lowlevel_orphan_records extends tx_lowlevel_cleaner_core
39 * 63: function tx_lowlevel_orphan_records()
40 * 96: function main()
41 * 151: function main_autoFix($resultArray)
42 *
43 * TOTAL FUNCTIONS: 3
44 * (This index is automatically created/updated by the extension "extdeveval")
45 *
46 */
47
48
49 /**
50 * Looking for Orphan Records
51 *
52 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
53 * @package TYPO3
54 * @subpackage tx_lowlevel
55 */
56 class tx_lowlevel_orphan_records extends tx_lowlevel_cleaner_core {
57
58 /**
59 * Constructor
60 *
61 * @return [type] ...
62 */
63 function tx_lowlevel_orphan_records() {
64 parent::tx_lowlevel_cleaner_core();
65
66 // Setting up help:
67 $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.');
68 $this->cli_help['name'] = 'orphan_records -- To find records that has lost their connection with the page tree';
69 $this->cli_help['description'] = trim('
70 Assumptions:
71 - That all actively used records on the website from TCA configured tables are located in the page tree exclusively.
72
73 All records managed by TYPO3 via the TCA array configuration has to belong to a page in the page tree, either directly or indirectly as a version of another record.
74 VERY TIME, CPU and MEMORY intensive operation since the full page tree is looked up!
75
76 Automatic Repair of Errors:
77 - Silently deleting the orphaned records. In theory they should not be used anywhere in the system, but there could be references. See below for more details on this matter.
78
79 Manual repair suggestions:
80 - Possibly re-connect orphaned records to page tree by setting their "pid" field to a valid page id. A lookup in the sys_refindex table can reveal if there are references to a orphaned record. If there are such references (from records that are not themselves orphans) you might consider to re-connect the record to the page tree, otherwise it should be safe to delete it.
81 ');
82 $this->cli_help['todo'] = trim('
83 - Implement a check for references to orphaned records and if a reference comes from a record that is not orphaned itself, we might rather like to re-connect the record to the page tree.
84 - Implement that orphans can be fixed by setting the PID to a certain page instead of deleting.');
85
86 $this->cli_help['examples'] = '/.../cli_dispatch.phpsh lowlevel_cleaner orphan_records -s -r
87 Will report orphan uids from TCA tables.';
88 }
89
90 /**
91 * Find orphan records
92 * VERY CPU and memory intensive since it will look up the whole page tree!
93 *
94 * @return array
95 */
96 function main() {
97 global $TYPO3_DB;
98
99 // Initialize result array:
100 $resultArray = array(
101 'message' => $this->cli_help['name'].chr(10).chr(10).$this->cli_help['description'],
102 'headers' => array(
103 'orphans' => array('Index of orphaned records','',3),
104 'misplaced_at_rootlevel' => array('Records that should not be at root level but are.','Fix manually by moving record into page tree',2),
105 'misplaced_inside_tree' => array('Records that should be at root level but are not.','Fix manually by moving record to tree root',2),
106 'illegal_record_under_versioned_page' => array('Records that cannot be attached to a versioned page','(Listed under orphaned records so is fixed along with orphans.)',2),
107 ),
108 'orphans' => array(),
109 'misplaced_at_rootlevel' => array(), // Subset of "all": Those that should not be at root level but are. [Warning: Fix by moving record into page tree]
110 'misplaced_inside_tree' => array(), // Subset of "all": Those that are inside page tree but should be at root level [Warning: Fix by setting PID to zero]
111 'illegal_record_under_versioned_page' => array(),
112 );
113
114 $startingPoint = 0; // zero = tree root, must use tree root if you wish to reverse selection to find orphans!
115 $pt = t3lib_div::milliseconds();
116
117 $this->genTree($startingPoint,1000,(int)$this->cli_argValue('--echotree'));
118
119 $resultArray['misplaced_at_rootlevel'] = $this->recStats['misplaced_at_rootlevel'];
120 $resultArray['misplaced_inside_tree'] = $this->recStats['misplaced_inside_tree'];
121 $resultArray['illegal_record_under_versioned_page'] = $this->recStats['illegal_record_under_versioned_page'];
122
123 // Find orphans:
124 foreach($GLOBALS['TCA'] as $tableName => $cfg) {
125
126 $idList = is_array($this->recStats['all'][$tableName]) && count($this->recStats['all'][$tableName]) ? implode(',',$this->recStats['all'][$tableName]) : 0;
127
128 // Select all records belonging to page:
129 $orphanRecords = array_keys($GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
130 'uid',
131 $tableName,
132 'uid NOT IN ('.$idList.')',
133 '','','','uid'
134 ));
135
136 if (count($orphanRecords)) {
137 $resultArray['orphans'][$tableName] = implode(',',$orphanRecords);
138 }
139 }
140
141 return $resultArray;
142 }
143
144 /**
145 * Mandatory autofix function
146 * Will run auto-fix on the result array. Echos status during processing.
147 *
148 * @param array Result array from main() function
149 * @return void
150 */
151 function main_autoFix($resultArray) {
152
153 // Putting "pages" table in the bottom:
154 if (isset($resultArray['orphans']['pages'])) {
155 $_pages = $resultArray['orphans']['pages'];
156 unset($resultArray['orphans']['pages']);
157 $resultArray['orphans']['pages'] = $_pages;
158 }
159
160 // Traversing records:
161 foreach($resultArray['orphans'] as $table => $list) {
162 echo 'Removing orphans from table "'.$table.'":'.chr(10);
163 $list = explode(',',$list);
164 foreach($list as $uid) {
165 echo ' Flushing orphan record "'.$table.':'.$uid.'": ';
166 if ($bypass = $this->cli_noExecutionCheck($table.':'.$uid)) {
167 echo $bypass;
168 } else {
169
170 // Execute CMD array:
171 $tce = t3lib_div::makeInstance('t3lib_TCEmain');
172 $tce->stripslashes_values = FALSE;
173 $tce->start(array(),array());
174 $tce->deleteRecord($table,$uid, TRUE, TRUE); // Notice, we are deleting pages with no regard to subpages/subrecords - we do this since they should also be included in the set of orphans of course!
175
176 // Return errors if any:
177 if (count($tce->errorLog)) {
178 echo ' ERROR from "TCEmain":'.chr(10).'TCEmain:'.implode(chr(10).'TCEmain:',$tce->errorLog);
179 } else echo 'DONE';
180 }
181 echo chr(10);
182 }
183 }
184 }
185 }
186
187 ?>