[TASK] Re-work/simplify copyright header in PHP files - Part 2
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Controller / Action / Tool / UpgradeWizard.php
1 <?php
2 namespace TYPO3\CMS\Install\Controller\Action\Tool;
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 use TYPO3\CMS\Install\Controller\Action;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19
20 /**
21 * Handle update wizards
22 */
23 class UpgradeWizard extends Action\AbstractAction {
24
25 /**
26 * There are tables and fields missing in the database
27 *
28 * @var bool
29 */
30 protected $needsInitialUpdateDatabaseSchema = FALSE;
31
32 /**
33 * Executes the tool
34 *
35 * @return string Rendered content
36 */
37 protected function executeAction() {
38 // ext_localconf, db and ext_tables must be loaded for the upgrade wizards
39 $this->loadExtLocalconfDatabaseAndExtTables();
40
41 // To make sure initialUpdateDatabaseSchema is first wizard, it is added here instead of ext_localconf.php
42 $initialUpdateDatabaseSchemaUpdateObject = $this->getUpgradeObjectInstance('TYPO3\\CMS\\Install\\Updates\\InitialDatabaseSchemaUpdate', 'initialUpdateDatabaseSchema');
43 if ($initialUpdateDatabaseSchemaUpdateObject->shouldRenderWizard()) {
44 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] = array_merge(
45 array('initialUpdateDatabaseSchema' => 'TYPO3\\CMS\\Install\\Updates\\InitialDatabaseSchemaUpdate'),
46 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']
47 );
48 $this->needsInitialUpdateDatabaseSchema = TRUE;
49 }
50
51 // To make sure finalUpdateDatabaseSchema is last wizard, it is added here instead of ext_localconf.php
52 $finalUpdateDatabaseSchemaUpdateObject = $this->getUpgradeObjectInstance('TYPO3\\CMS\\Install\\Updates\\FinalDatabaseSchemaUpdate', 'finalUpdateDatabaseSchema');
53 if ($finalUpdateDatabaseSchemaUpdateObject->shouldRenderWizard()) {
54 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['finalUpdateDatabaseSchema'] = 'TYPO3\\CMS\\Install\\Updates\\FinalDatabaseSchemaUpdate';
55 }
56
57 // Perform silent cache framework table upgrades
58 $this->silentCacheFrameworkTableSchemaMigration();
59
60 $actionMessages = array();
61
62 if (isset($this->postValues['set']['getUserInput'])) {
63 $actionMessages[] = $this->getUserInputForUpgradeWizard();
64 $this->view->assign('updateAction', 'getUserInput');
65 } elseif (isset($this->postValues['set']['performUpdate'])) {
66 $actionMessages[] = $this->performUpdate();
67 $this->view->assign('updateAction', 'performUpdate');
68 } else {
69 $actionMessages[] = $this->listUpdates();
70 $this->view->assign('updateAction', 'listUpdates');
71 }
72
73 $this->view->assign('actionMessages', $actionMessages);
74
75 return $this->view->render();
76 }
77
78 /**
79 * List of available updates
80 *
81 * @return \TYPO3\CMS\Install\Status\StatusInterface
82 */
83 protected function listUpdates() {
84 if (empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'])) {
85 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
86 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\WarningStatus');
87 $message->setTitle('No update wizards registered');
88 return $message;
89 }
90
91 $availableUpdates = array();
92 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] as $identifier => $className) {
93 $updateObject = $this->getUpgradeObjectInstance($className, $identifier);
94 if ($updateObject->shouldRenderWizard()) {
95 // $explanation is changed by reference in upgrade objects!
96 $explanation = '';
97 $updateObject->checkForUpdate($explanation);
98 $availableUpdates[$identifier] = array(
99 'identifier' => $identifier,
100 'title' => $updateObject->getTitle(),
101 'explanation' => $explanation,
102 'renderNext' => FALSE,
103 );
104 if ($identifier === 'initialUpdateDatabaseSchema') {
105 $availableUpdates['initialUpdateDatabaseSchema']['renderNext'] = $this->needsInitialUpdateDatabaseSchema;
106 } elseif ($identifier === 'finalUpdateDatabaseSchema') {
107 // Okay to check here because finalUpdateDatabaseSchema is last element in array
108 $availableUpdates['finalUpdateDatabaseSchema']['renderNext'] = count($availableUpdates) === 1;
109 } elseif (!$this->needsInitialUpdateDatabaseSchema && $updateObject->shouldRenderNextButton()) {
110 // There are upgrade wizards that only show text and don't want to be executed
111 $availableUpdates[$identifier]['renderNext'] = TRUE;
112 }
113 }
114 }
115
116 $this->view->assign('availableUpdates', $availableUpdates);
117
118 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
119 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\OkStatus');
120 $message->setTitle('Show available update wizards');
121 return $message;
122 }
123
124 /**
125 * Get user input of update wizard
126 *
127 * @return \TYPO3\CMS\Install\Status\StatusInterface
128 */
129 protected function getUserInputForUpgradeWizard() {
130 $wizardIdentifier = $this->postValues['values']['identifier'];
131
132 $className = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][$wizardIdentifier];
133 $updateObject = $this->getUpgradeObjectInstance($className, $wizardIdentifier);
134 $wizardHtml = '';
135 if (method_exists($updateObject, 'getUserInput')) {
136 $wizardHtml = $updateObject->getUserInput('install[values][' . $wizardIdentifier . ']');
137 }
138
139 $upgradeWizardData = array(
140 'identifier' => $wizardIdentifier,
141 'title' => $updateObject->getTitle(),
142 'wizardHtml' => $wizardHtml,
143 );
144
145 $this->view->assign('upgradeWizardData', $upgradeWizardData);
146
147 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
148 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\OkStatus');
149 $message->setTitle('Show wizard options');
150 return $message;
151 }
152
153 /**
154 * Perform update of a specific wizard
155 *
156 * @throws \TYPO3\CMS\Install\Exception
157 * @return \TYPO3\CMS\Install\Status\StatusInterface
158 */
159 protected function performUpdate() {
160 $this->getDatabaseConnection()->store_lastBuiltQuery = TRUE;
161
162 $wizardIdentifier = $this->postValues['values']['identifier'];
163 $className = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][$wizardIdentifier];
164 $updateObject = $this->getUpgradeObjectInstance($className, $wizardIdentifier);
165
166 $wizardData = array(
167 'identifier' => $wizardIdentifier,
168 'title' => $updateObject->getTitle(),
169 );
170
171 // $wizardInputErrorMessage is given as reference to wizard object!
172 $wizardInputErrorMessage = '';
173 if (method_exists($updateObject, 'checkUserInput') && !$updateObject->checkUserInput($wizardInputErrorMessage)) {
174 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
175 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
176 $message->setTitle('Input parameter broken');
177 $message->setMessage($wizardInputErrorMessage ?: 'Something went wrong!');
178 $wizardData['wizardInputBroken'] = TRUE;
179 } else {
180 if (!method_exists($updateObject, 'performUpdate')) {
181 throw new \TYPO3\CMS\Install\Exception(
182 'No performUpdate method in update wizard with identifier ' . $wizardIdentifier,
183 1371035200
184 );
185 }
186
187 // Both variables are used by reference in performUpdate()
188 $customOutput = '';
189 $databaseQueries = array();
190 $performResult = $updateObject->performUpdate($databaseQueries, $customOutput);
191
192 if ($performResult) {
193 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
194 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\OkStatus');
195 $message->setTitle('Update successful');
196 } else {
197 /** @var $message \TYPO3\CMS\Install\Status\StatusInterface */
198 $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
199 $message->setTitle('Update failed!');
200 if ($customOutput) {
201 $message->setMessage($customOutput);
202 }
203 }
204
205 if ($this->postValues['values']['showDatabaseQueries'] == 1) {
206 $wizardData['queries'] = $databaseQueries;
207 }
208 }
209
210 $this->view->assign('wizardData', $wizardData);
211
212 $this->getDatabaseConnection()->store_lastBuiltQuery = FALSE;
213
214 // Next update wizard, if available
215 $nextUpgradeWizard = $this->getNextUpgradeWizardInstance($updateObject);
216 $nextUpgradeWizardIdentifier = '';
217 if ($nextUpgradeWizard) {
218 $nextUpgradeWizardIdentifier = $nextUpgradeWizard->getIdentifier();
219 }
220 $this->view->assign('nextUpgradeWizardIdentifier', $nextUpgradeWizardIdentifier);
221
222 return $message;
223 }
224
225 /**
226 * Creates instance of an upgrade object, setting the pObj, versionNumber and userInput
227 *
228 * @param string $className The class name
229 * @param string $identifier The identifier of upgrade object - needed to fetch user input
230 * @return object Newly instantiated upgrade object
231 */
232 protected function getUpgradeObjectInstance($className, $identifier) {
233 $formValues = $this->postValues;
234 $updateObject = GeneralUtility::getUserObj($className);
235 $updateObject->setIdentifier($identifier);
236 $updateObject->versionNumber = \TYPO3\CMS\Core\Utility\VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version);
237 $updateObject->pObj = $this;
238 $updateObject->userInput = $formValues['values'][$identifier];
239 return $updateObject;
240 }
241
242 /**
243 * Returns the next upgrade wizard object
244 * Used to show the link/button to the next upgrade wizard
245 *
246 * @param object $currentObj Current update wizard object
247 * @return mixed Upgrade wizard instance or FALSE
248 */
249 protected function getNextUpgradeWizardInstance($currentObj) {
250 $isPreviousRecord = TRUE;
251 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] as $identifier => $className) {
252 // Find the current update wizard, and then start validating the next ones
253 if ($currentObj->getIdentifier() == $identifier) {
254 $isPreviousRecord = FALSE;
255 // For the updateDatabaseSchema-wizards verify they do not have to be executed again
256 if ($identifier !== 'initialUpdateDatabaseSchema' && $identifier !== 'finalUpdateDatabaseSchema') {
257 continue;
258 }
259 }
260 if (!$isPreviousRecord) {
261 $nextUpgradeWizard = $this->getUpgradeObjectInstance($className, $identifier);
262 if ($nextUpgradeWizard->shouldRenderWizard()) {
263 return $nextUpgradeWizard;
264 }
265 }
266 }
267 return FALSE;
268 }
269
270 /**
271 * Force creation / update of caching framework tables that are needed by some update wizards
272 *
273 * @TODO: See also the other remarks on this topic in the abstract class, this whole area needs improvements
274 * @return void
275 */
276 protected function silentCacheFrameworkTableSchemaMigration() {
277 /** @var $sqlHandler \TYPO3\CMS\Install\Service\SqlSchemaMigrationService */
278 $sqlHandler = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\SqlSchemaMigrationService');
279
280 /** @var \TYPO3\CMS\Install\Service\CachingFrameworkDatabaseSchemaService $cachingFrameworkDatabaseSchemaService */
281 $cachingFrameworkDatabaseSchemaService = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\CachingFrameworkDatabaseSchemaService');
282 $expectedSchemaString = $cachingFrameworkDatabaseSchemaService->getCachingFrameworkRequiredDatabaseSchema();
283 $cleanedExpectedSchemaString = implode(LF, $sqlHandler->getStatementArray($expectedSchemaString, TRUE, '^CREATE TABLE '));
284 $neededTableDefinition = $sqlHandler->getFieldDefinitions_fileContent($cleanedExpectedSchemaString);
285 $currentTableDefinition = $sqlHandler->getFieldDefinitions_database();
286 $updateTableDefinition = $sqlHandler->getDatabaseExtra($neededTableDefinition, $currentTableDefinition);
287 $updateStatements = $sqlHandler->getUpdateSuggestions($updateTableDefinition);
288 if (isset($updateStatements['create_table']) && count($updateStatements['create_table']) > 0) {
289 $sqlHandler->performUpdateQueries($updateStatements['create_table'], $updateStatements['create_table']);
290 }
291 if (isset($updateStatements['add']) && count($updateStatements['add']) > 0) {
292 $sqlHandler->performUpdateQueries($updateStatements['add'], $updateStatements['add']);
293 }
294 if (isset($updateStatements['change']) && count($updateStatements['change']) > 0) {
295 $sqlHandler->performUpdateQueries($updateStatements['change'], $updateStatements['change']);
296 }
297 }
298
299 /**
300 * Overwrite getDatabase method of abstract!
301 *
302 * Returns $GLOBALS['TYPO3_DB'] directly, since this global is instantiated properly in update wizards
303 *
304 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
305 */
306 protected function getDatabaseConnection() {
307 return $GLOBALS['TYPO3_DB'];
308 }
309 }