TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
UpgradeWizard.php
Go to the documentation of this file.
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 
24 use TYPO3\CMS\Install\Controller\Action;
27 
32 {
39 
45  protected function executeAction()
46  {
47  // ext_localconf, db and ext_tables must be loaded for the updates
49 
50  if (empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'])) {
51  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] = [];
52  }
53 
54  $actionMessages = [];
55 
56  try {
57  // To make sure DatabaseCharsetUpdate and initialUpdateDatabaseSchema are first wizards, they are added here instead of ext_localconf.php
58  $databaseCharsetUpdateObject = $this->getUpdateObjectInstance(\TYPO3\CMS\Install\Updates\DatabaseCharsetUpdate::class, 'databaseCharsetUpdate');
59  if ($databaseCharsetUpdateObject->shouldRenderWizard()) {
60  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] = array_merge(
61  ['databaseCharsetUpdate' => \TYPO3\CMS\Install\Updates\DatabaseCharsetUpdate::class],
62  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']
63  );
64  }
65  $initialUpdateDatabaseSchemaUpdateObject = $this->getUpdateObjectInstance(\TYPO3\CMS\Install\Updates\InitialDatabaseSchemaUpdate::class, 'initialUpdateDatabaseSchema');
66  if ($initialUpdateDatabaseSchemaUpdateObject->shouldRenderWizard()) {
67  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] = array_merge(
68  ['initialUpdateDatabaseSchema' => \TYPO3\CMS\Install\Updates\InitialDatabaseSchemaUpdate::class],
69  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']
70  );
71  $this->needsInitialUpdateDatabaseSchema = true;
72  }
73 
74  // To make sure finalUpdateDatabaseSchema is last wizard, it is added here instead of ext_localconf.php
75  $finalUpdateDatabaseSchemaUpdateObject = $this->getUpdateObjectInstance(\TYPO3\CMS\Install\Updates\FinalDatabaseSchemaUpdate::class, 'finalUpdateDatabaseSchema');
76  if ($finalUpdateDatabaseSchemaUpdateObject->shouldRenderWizard()) {
77  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['finalUpdateDatabaseSchema'] = \TYPO3\CMS\Install\Updates\FinalDatabaseSchemaUpdate::class;
78  }
79  } catch (StatementException $exception) {
81  $message = GeneralUtility::makeInstance(ErrorStatus::class);
82  $message->setTitle('SQL error');
83  $message->setMessage($exception->getMessage());
84  $actionMessages[] = $message;
85  }
86 
87  // Perform silent cache framework table upgrade
89 
90  if (isset($this->postValues['set']['getUserInput'])) {
91  $actionMessages[] = $this->getUserInputForUpdate();
92  $this->view->assign('updateAction', 'getUserInput');
93  } elseif (isset($this->postValues['set']['performUpdate'])) {
94  $actionMessages[] = $this->performUpdate();
95  $this->view->assign('updateAction', 'performUpdate');
96  } elseif (isset($this->postValues['set']['recheckWizards'])) {
97  $actionMessages[] = $this->recheckWizards();
98  $this->listUpdates();
99  $this->view->assign('updateAction', 'listUpdates');
100  } else {
101  $this->listUpdates();
102  $this->view->assign('updateAction', 'listUpdates');
103  }
104 
105  $this->view->assign('actionMessages', $actionMessages);
106 
107  return $this->view->render();
108  }
109 
115  protected function listUpdates()
116  {
117  if (empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'])) {
119  $message = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\WarningStatus::class);
120  $message->setTitle('No update wizards registered');
121  return $message;
122  }
123 
124  $availableUpdates = [];
125  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] as $identifier => $className) {
126  $updateObject = $this->getUpdateObjectInstance($className, $identifier);
127  if ($updateObject->shouldRenderWizard()) {
128  // $explanation is changed by reference in Update objects!
129  $explanation = '';
130  $updateObject->checkForUpdate($explanation);
131  $availableUpdates[$identifier] = [
132  'identifier' => $identifier,
133  'title' => $updateObject->getTitle(),
134  'explanation' => $explanation,
135  'renderNext' => false,
136  ];
137  if ($identifier === 'initialUpdateDatabaseSchema') {
138  $availableUpdates['initialUpdateDatabaseSchema']['renderNext'] = $this->needsInitialUpdateDatabaseSchema;
139  // initialUpdateDatabaseSchema is always the first update
140  // we stop immediately here as the remaining updates may
141  // require the new fields to be present in order to avoid SQL errors
142  break;
143  } elseif ($identifier === 'finalUpdateDatabaseSchema') {
144  // Okay to check here because finalUpdateDatabaseSchema is last element in array
145  $availableUpdates['finalUpdateDatabaseSchema']['renderNext'] = count($availableUpdates) === 1;
146  } elseif (!$this->needsInitialUpdateDatabaseSchema && $updateObject->shouldRenderNextButton()) {
147  // There are Updates that only show text and don't want to be executed
148  $availableUpdates[$identifier]['renderNext'] = true;
149  }
150  }
151  }
152 
153  $this->view->assign('availableUpdates', $availableUpdates);
154 
155  // compute done wizards for statistics
156  $wizardsDone = [];
157  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] as $identifier => $className) {
159  $updateObject = $this->getUpdateObjectInstance($className, $identifier);
160  if ($updateObject->shouldRenderWizard() !== true) {
161  $doneWizard = [
162  'identifier' => $identifier,
163  'title' => $updateObject->getTitle()
164  ];
165  $wizardsDone[] = $doneWizard;
166  }
167  }
168  $this->view->assign('wizardsDone', $wizardsDone);
169 
170  $wizardsTotal = (count($wizardsDone) + count($availableUpdates));
171  $this->view->assign('wizardsTotal', $wizardsTotal);
172 
173  $this->view->assign('wizardsPercentageDone', floor(($wizardsTotal - count($availableUpdates)) * 100 / $wizardsTotal));
174  }
175 
181  protected function getUserInputForUpdate()
182  {
183  $wizardIdentifier = $this->postValues['values']['identifier'];
184 
185  $className = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][$wizardIdentifier];
186  $updateObject = $this->getUpdateObjectInstance($className, $wizardIdentifier);
187  $wizardHtml = '';
188  if (method_exists($updateObject, 'getUserInput')) {
189  $wizardHtml = $updateObject->getUserInput('install[values][' . $wizardIdentifier . ']');
190  }
191 
192  $updateData = [
193  'identifier' => $wizardIdentifier,
194  'title' => $updateObject->getTitle(),
195  'wizardHtml' => $wizardHtml,
196  ];
197 
198  $this->view->assign('updateData', $updateData);
199 
201  $message = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\OkStatus::class);
202  $message->setTitle('Show wizard options');
203  return $message;
204  }
205 
211  protected function recheckWizards()
212  {
213  if (empty($this->postValues['values']['recheck'])) {
214  $message = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\NoticeStatus::class);
215  $message->setTitle('No wizards selected to recheck');
216  return $message;
217  }
218  foreach ($this->postValues['values']['recheck'] as $wizardIdentifier => $value) {
219  $className = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][$wizardIdentifier];
220  $updateObject = $this->getUpdateObjectInstance($className, $wizardIdentifier);
221  GeneralUtility::makeInstance(Registry::class)->set('installUpdate', get_class($updateObject), 0);
222  }
223  $message = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\OkStatus::class);
224  $message->setTitle('Successfully rechecked');
225  return $message;
226  }
227 
234  protected function performUpdate()
235  {
236  $this->getDatabaseConnection()->store_lastBuiltQuery = true;
237 
238  $wizardIdentifier = $this->postValues['values']['identifier'];
239  $className = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][$wizardIdentifier];
240  $updateObject = $this->getUpdateObjectInstance($className, $wizardIdentifier);
241 
242  $wizardData = [
243  'identifier' => $wizardIdentifier,
244  'title' => $updateObject->getTitle(),
245  ];
246 
247  // $wizardInputErrorMessage is given as reference to wizard object!
248  $wizardInputErrorMessage = '';
249  if (method_exists($updateObject, 'checkUserInput') && !$updateObject->checkUserInput($wizardInputErrorMessage)) {
251  $message = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\ErrorStatus::class);
252  $message->setTitle('Input parameter broken');
253  $message->setMessage($wizardInputErrorMessage ?: 'Something went wrong!');
254  $wizardData['wizardInputBroken'] = true;
255  } else {
256  if (!method_exists($updateObject, 'performUpdate')) {
257  throw new \TYPO3\CMS\Install\Exception(
258  'No performUpdate method in update wizard with identifier ' . $wizardIdentifier,
259  1371035200
260  );
261  }
262 
263  // Both variables are used by reference in performUpdate()
264  $customOutput = '';
265  $databaseQueries = [];
266  $performResult = $updateObject->performUpdate($databaseQueries, $customOutput);
267 
268  if ($performResult) {
270  $message = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\OkStatus::class);
271  $message->setTitle('Update successful');
272  } else {
274  $message = GeneralUtility::makeInstance(\TYPO3\CMS\Install\Status\ErrorStatus::class);
275  $message->setTitle('Update failed!');
276  if ($customOutput) {
277  $message->setMessage($customOutput);
278  }
279  }
280 
281  if ($this->postValues['values']['showDatabaseQueries'] == 1) {
282  $wizardData['queries'] = $databaseQueries;
283  }
284  }
285 
286  $this->view->assign('wizardData', $wizardData);
287 
288  $this->getDatabaseConnection()->store_lastBuiltQuery = false;
289 
290  // Next update wizard, if available
291  $nextUpdate = $this->getNextUpdateInstance($updateObject);
292  $nextUpdateIdentifier = '';
293  if ($nextUpdate) {
294  $nextUpdateIdentifier = $nextUpdate->getIdentifier();
295  }
296  $this->view->assign('nextUpdateIdentifier', $nextUpdateIdentifier);
297 
298  return $message;
299  }
300 
308  protected function getUpdateObjectInstance($className, $identifier)
309  {
310  $userInput = $this->postValues['values'][$identifier];
311  $versionAsInt = VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version);
312  return GeneralUtility::makeInstance($className, $identifier, $versionAsInt, $userInput, $this);
313  }
314 
322  protected function getNextUpdateInstance(AbstractUpdate $currentUpdate)
323  {
324  $isPreviousRecord = true;
325  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'] as $identifier => $className) {
326  // Find the current update wizard, and then start validating the next ones
327  if ($currentUpdate->getIdentifier() === $identifier) {
328  $isPreviousRecord = false;
329  // For the updateDatabaseSchema-wizards verify they do not have to be executed again
330  if ($identifier !== 'initialUpdateDatabaseSchema' && $identifier !== 'finalUpdateDatabaseSchema') {
331  continue;
332  }
333  }
334  if (!$isPreviousRecord) {
335  $nextUpdate = $this->getUpdateObjectInstance($className, $identifier);
336  if ($nextUpdate->shouldRenderWizard()) {
337  return $nextUpdate;
338  }
339  }
340  }
341  return null;
342  }
343 
359  {
360  $sqlReader = GeneralUtility::makeInstance(SqlReader::class);
361  $cachingFrameworkDatabaseSchemaService = GeneralUtility::makeInstance(DatabaseSchemaService::class);
362  $createTableStatements = $sqlReader->getStatementArray(
363  $cachingFrameworkDatabaseSchemaService->getCachingFrameworkRequiredDatabaseSchema()
364  );
365 
366  $schemaMigrationService = GeneralUtility::makeInstance(SchemaMigrator::class);
367  $schemaMigrationService->install($createTableStatements);
368  }
369 }
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)