[TASK] Re-work/simplify copyright header in PHP files - Part 1
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Updates / ReferenceIntegrityUpdateWizard.php
1 <?php
2 namespace TYPO3\CMS\Install\Updates;
3
4 /**
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 /**
18 * Performs certain DB updates in order to ensure that the DB fields
19 * are set properly.
20 * 1) Ensure that there are no sys_file_reference records with PID=0
21 * where the connected parent records (e.g. a tt_content record) are
22 * not on PID=0.
23 * 2) Make sure that all sys_file_references point to tables that still
24 * exist.
25 *
26 * @author Benni Mack <benni@typo3.org>
27 */
28 class ReferenceIntegrityUpdateWizard extends AbstractUpdate {
29
30 /**
31 * @var string
32 */
33 protected $title = 'Ensures the database integrity for File Abstraction records';
34
35 /**
36 * Checks if an update is needed
37 *
38 * @param string &$description The description for the update
39 * @return boolean TRUE if an update is needed, FALSE otherwise
40 */
41 public function checkForUpdate(&$description) {
42 $description = 'Checks if there are file references that are on the root level. ' .
43 'This could have happened due to a misconfigured previous migration. ' .
44 'This migration will also remove references to tables that no longer exist.';
45 return count($this->getRequiredUpdates()) > 0;
46 }
47
48 /**
49 * Performs the database update.
50 *
51 * @param array &$dbQueries Queries done in this update
52 * @param mixed &$customMessages Custom messages
53 * @return boolean TRUE on success, FALSE on error
54 */
55 public function performUpdate(array &$dbQueries, &$customMessages) {
56 $updates = $this->getRequiredUpdates();
57 if (isset($updates['referenceToMissingTables'])) {
58 foreach ($updates['referenceToMissingTables'] as $missingTable) {
59 $deleteQuery = $GLOBALS['TYPO3_DB']->DELETEquery(
60 'sys_file_reference',
61 'tablenames=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($missingTable, 'sys_file_reference')
62 );
63 $GLOBALS['TYPO3_DB']->sql_query($deleteQuery);
64 $dbQueries[] = $deleteQuery;
65 }
66 }
67 if (isset($updates['improperConnectedFileReferences'])) {
68 foreach ($updates['improperConnectedFileReferences'] as $fileReferenceRecord) {
69 if ($fileReferenceRecord['newpid'] > 0) {
70 $updateQuery = $GLOBALS['TYPO3_DB']->UPDATEquery(
71 'sys_file_reference',
72 'uid=' . (int)$fileReferenceRecord['uid'],
73 array('pid' => $fileReferenceRecord['newpid'])
74 );
75 $GLOBALS['TYPO3_DB']->sql_query($updateQuery);
76 $dbQueries[] = $updateQuery;
77 }
78 }
79 }
80 return TRUE;
81 }
82
83 /**
84 * Determine all DB updates that need to be done
85 *
86 * @return array
87 */
88 protected function getRequiredUpdates() {
89 $requiredUpdates = array();
90 $referenceToMissingTables = $this->getFileReferencesPointingToMissingTables();
91 if (count($referenceToMissingTables) > 0) {
92 $requiredUpdates['referenceToMissingTables'] = $referenceToMissingTables;
93 }
94 $improperConnectedFileReferences = $this->getImproperConnectedFileReferences($referenceToMissingTables);
95 if (count($improperConnectedFileReferences) > 0) {
96 $requiredUpdates['improperConnectedFileReferences'] = $improperConnectedFileReferences;
97 }
98 return $requiredUpdates;
99 }
100
101 /**
102 * A list of tables that are referenced by sys_file_reference that are no longer existing
103 *
104 * @return array
105 */
106 protected function getFileReferencesPointingToMissingTables() {
107 $existingTables = array_flip(array_keys($GLOBALS['TYPO3_DB']->admin_get_tables()));
108 $missingTables = array();
109 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('DISTINCT tablenames', 'sys_file_reference', '');
110 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
111 $thisTablename = $row['tablenames'];
112 if (!isset($existingTables[$thisTablename])) {
113 $missingTables[] = $thisTablename;
114 }
115 }
116 return $missingTables;
117 }
118
119 /**
120 * Fetches a list of all sys_file_references that have PID=0
121 *
122 * @return mixed
123 */
124 protected function getFileReferencesOnRootlevel() {
125 return $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
126 'uid, pid, uid_local AS fileuid, uid_foreign AS targetuid, tablenames AS targettable',
127 'sys_file_reference',
128 'pid=0 AND deleted=0'
129 );
130 }
131
132 /**
133 * Fetches all sys_file_reference records that are on PID=0 BUT their counter parts (the target record)
134 * is NOT on pid=0
135 *
136 * @param array $skipTables Table names to skip checking
137 * @return array
138 */
139 protected function getImproperConnectedFileReferences(array $skipTables = array()) {
140 $improperConnectedReferences = array();
141 // fetch all references on root level
142 $sysFileReferences = $this->getFileReferencesOnRootlevel();
143 foreach ($sysFileReferences as $fileReferenceRecord) {
144 $tableName = $fileReferenceRecord['targettable'];
145 if (in_array($tableName, $skipTables)) {
146 continue;
147 }
148 // if the target table is pages (e.g. when adding a file reference to the pages->media
149 // record, then the
150 $whereClause = 'uid=' . (int)$fileReferenceRecord['targetuid'];
151 if ($fileReferenceRecord['targettable'] === 'pages') {
152 $isPageReference = TRUE;
153 } else {
154 $isPageReference = FALSE;
155 $whereClause .= ' AND pid<>0';
156 }
157 // check the target table, if the target record is NOT on the rootlevel
158 $targetRecord = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
159 'uid, pid',
160 $tableName,
161 $whereClause
162 );
163 // only add the file reference if the target record is not on PID=0
164 if ($targetRecord !== NULL) {
165 $fileReferenceRecord['newpid'] = ($isPageReference ? $targetRecord['uid'] : $targetRecord['pid']);
166 $improperConnectedReferences[] = $fileReferenceRecord;
167 }
168 }
169 return $improperConnectedReferences;
170 }
171 }