2 declare(strict_types = 1);
19 use Doctrine\DBAL\Platforms\MySqlPlatform;
20 use Doctrine\DBAL\Schema\Column;
21 use Doctrine\DBAL\Schema\Table;
22 use Symfony\Component\Console\Output\Output;
23 use Symfony\Component\Console\Output\StreamOutput;
47 $this->output =
new StreamOutput(fopen(
'php://temp',
'wb'), Output::VERBOSITY_NORMAL,
false);
55 $wizardsDoneInRegistry = [];
56 $registry = GeneralUtility::makeInstance(Registry::class);
57 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'ext/install'][
'update'] as $identifier => $className) {
58 if ($registry->get(
'installUpdate', $className,
false)) {
59 $wizardInstance = GeneralUtility::makeInstance($className);
60 $wizardsDoneInRegistry[] = [
61 'class' => $className,
62 'identifier' => $identifier,
63 'title' => $wizardInstance->getTitle(),
67 return $wizardsDoneInRegistry;
76 $registry = GeneralUtility::makeInstance(Registry::class);
77 $rowUpdatersDoneClassNames = $registry->get(
'installUpdateRows',
'rowUpdatersDone', []);
78 $rowUpdatersDone = [];
79 foreach ($rowUpdatersDoneClassNames as $rowUpdaterClassName) {
81 if (!class_exists($rowUpdaterClassName)) {
85 $rowUpdater = GeneralUtility::makeInstance($rowUpdaterClassName);
87 throw new \RuntimeException(
88 'Row updater must implement RowUpdaterInterface',
92 $rowUpdatersDone[] = [
93 'class' => $rowUpdaterClassName,
94 'identifier' => $rowUpdaterClassName,
95 'title' => $rowUpdater->getTitle(),
98 return $rowUpdatersDone;
113 $registry = GeneralUtility::makeInstance(Registry::class);
114 $aWizardHasBeenMarkedUndone =
false;
116 if ($wizard[
'identifier'] === $identifier) {
117 $aWizardHasBeenMarkedUndone =
true;
118 $registry->set(
'installUpdate', $wizard[
'class'], 0);
121 if (!$aWizardHasBeenMarkedUndone) {
123 $registryArray = $registry->get(
'installUpdateRows',
'rowUpdatersDone', []);
124 foreach ($rowUpdatersDoneList as $rowUpdater) {
125 if ($rowUpdater[
'identifier'] === $identifier) {
126 $aWizardHasBeenMarkedUndone =
true;
127 foreach ($registryArray as $rowUpdaterMarkedAsDonePosition => $rowUpdaterMarkedAsDone) {
128 if ($rowUpdaterMarkedAsDone === $rowUpdater[
'class']) {
129 unset($registryArray[$rowUpdaterMarkedAsDonePosition]);
133 $registry->set(
'installUpdateRows',
'rowUpdatersDone', $registryArray);
137 return $aWizardHasBeenMarkedUndone;
147 $sqlReader = GeneralUtility::makeInstance(SqlReader::class);
148 $databaseDefinitions = $sqlReader->getCreateTableStatementArray($sqlReader->getTablesDefinitionString());
150 $schemaMigrator = GeneralUtility::makeInstance(SchemaMigrator::class);
151 $databaseDifferences = $schemaMigrator->getSchemaDiffs($databaseDefinitions);
154 foreach ($databaseDifferences as $schemaDiff) {
155 foreach ($schemaDiff->newTables as $newTable) {
157 if (!is_array($adds[
'tables'])) {
158 $adds[
'tables'] = [];
160 $adds[
'tables'][] = [
161 'table' => $newTable->getName(),
164 foreach ($schemaDiff->changedTables as $changedTable) {
165 foreach ($changedTable->addedColumns as $addedColumn) {
167 if (!is_array($adds[
'columns'])) {
168 $adds[
'columns'] = [];
170 $adds[
'columns'][] = [
171 'table' => $changedTable->name,
172 'field' => $addedColumn->getName(),
175 foreach ($changedTable->addedIndexes as $addedIndex) {
177 if (!is_array($adds[
'indexes'])) {
178 $adds[
'indexes'] = [];
180 $adds[
'indexes'][] = [
181 'table' => $changedTable->name,
182 'index' => $addedIndex->getName(),
196 $sqlReader = GeneralUtility::makeInstance(SqlReader::class);
197 $databaseDefinitions = $sqlReader->getCreateTableStatementArray($sqlReader->getTablesDefinitionString());
198 $schemaMigrator = GeneralUtility::makeInstance(SchemaMigrator::class);
199 return $schemaMigrator->install($databaseDefinitions,
true);
210 $connection = GeneralUtility::makeInstance(ConnectionPool::class)
213 $isDefaultConnectionMysql = ($connection->getDatabasePlatform() instanceof MySqlPlatform);
215 if (!$isDefaultConnectionMysql) {
219 $queryBuilder = $connection->createQueryBuilder();
220 $charset = (string)$queryBuilder->select(
'DEFAULT_CHARACTER_SET_NAME')
221 ->from(
'information_schema.SCHEMATA')
223 $queryBuilder->expr()->eq(
225 $queryBuilder->createNamedParameter($connection->getDatabase(), \PDO::PARAM_STR)
232 $charsetOk = strpos($charset,
'utf8') === 0;
243 $connection = GeneralUtility::makeInstance(ConnectionPool::class)
245 $sql =
'ALTER DATABASE ' . $connection->quoteIdentifier($connection->getDatabase()) .
' CHARACTER SET utf8';
246 $connection->exec($sql);
257 foreach (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'ext/install'][
'update'] as $identifier => $class) {
262 $wizardInstance = GeneralUtility::makeInstance($class);
266 $shouldRenderWizard =
false;
269 $wizardInstance->setOutput($this->output);
271 $shouldRenderWizard = $wizardInstance->updateNecessary();
272 $explanation = $wizardInstance->getDescription();
277 'identifier' => $identifier,
278 'title' => $wizardInstance->getTitle(),
279 'shouldRenderWizard' => $shouldRenderWizard,
280 'explanation' => $explanation,
297 $class =
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'ext/install'][
'update'][$identifier];
298 $updateObject = GeneralUtility::makeInstance($class);
300 if (method_exists($updateObject,
'getUserInput')) {
301 $wizardHtml = $updateObject->getUserInput(
'install[values][' . htmlspecialchars($identifier) .
']');
303 'Deprecated since TYPO3 v9, will be removed in TYPO3 v10.0, use ConfirmableInterface directly.',
310 'name' =>
'install[values][' . $updateObject->getIdentifier() .
'][install]',
313 $markup[] =
'<div class="panel panel-danger">';
314 $markup[] =
' <div class="panel-heading">';
315 $markup[] = htmlspecialchars($updateObject->getConfirmation()->getTitle());
316 $markup[] =
' </div>';
317 $markup[] =
' <div class="panel-body">';
318 $markup[] =
' <p>' . nl2br(htmlspecialchars($updateObject->getConfirmation()->getMessage())) .
'</p>';
319 $markup[] =
' <div class="btn-group" data-toggle="buttons">';
320 if (!$updateObject->getConfirmation()->isRequired()) {
321 $markup[] =
' <label class="btn btn-default active"><input ' . GeneralUtility::implodeAttributes($radioAttributes,
true) .
' checked="checked" />' . $updateObject->getConfirmation()->getDeny() .
'</label>';
323 $radioAttributes[
'value'] = 1;
324 $markup[] =
' <label class="btn btn-default"><input ' . GeneralUtility::implodeAttributes($radioAttributes,
true) .
' />' . $updateObject->getConfirmation()->getConfirm() .
'</label>';
325 $markup[] =
' </div>';
326 $markup[] =
' </div>';
327 $markup[] =
'</div>';
328 $wizardHtml = implode(
'', $markup);
332 'identifier' => $identifier,
333 'title' => $updateObject->getTitle(),
334 'wizardHtml' => $wizardHtml,
351 $class =
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'ext/install'][
'update'][$identifier];
352 $updateObject = GeneralUtility::makeInstance($class);
355 $updateObject->setOutput($this->output);
359 $wizardInputErrorMessage =
'';
360 if (method_exists($updateObject,
'checkUserInput') &&
361 !$updateObject->checkUserInput($wizardInputErrorMessage)) {
363 'Deprecated since TYPO3 v9, will be removed in TYPO3 v10.0, use ConfirmableInterface.',
368 $wizardInputErrorMessage ?:
'Something went wrong!',
369 'Input parameter broken',
375 $requestParams = GeneralUtility::_GP(
'install');
378 $isSetButEmpty = isset($requestParams[
'values'][$updateObject->getIdentifier()][
'install'])
379 && empty($requestParams[
'values'][$updateObject->getIdentifier()][
'install']);
381 $checkValue = (int)$requestParams[
'values'][$updateObject->getIdentifier()][
'install'];
383 if ($checkValue === 1) {
385 $performResult = $updateObject->executeUpdate();
386 } elseif ($updateObject->getConfirmation()->isRequired()) {
388 $performResult =
false;
389 } elseif ($isSetButEmpty) {
391 $this->output->writeln(
'No changes applied, marking wizard as done.');
393 $performResult =
true;
397 $performResult = $updateObject->executeUpdate();
401 $stream = $this->output->getStream();
403 if ($performResult) {
410 stream_get_contents($stream),
417 stream_get_contents($stream),
438 $class =
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'ext/install'][
'update'][$identifier];
439 GeneralUtility::makeInstance(Registry::class)->set(
'installUpdate', $class, 1);
453 $class =
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'ext/install'][
'update'][$identifier];
454 return (
bool)GeneralUtility::makeInstance(Registry::class)->get(
'installUpdate', $class,
false);
465 if ($identifier ===
'' || (!isset(
$GLOBALS[
'TYPO3_CONF_VARS'][
'SC_OPTIONS'][
'ext/install'][
'update'][$identifier]) && !is_subclass_of($identifier, RowUpdaterInterface::class))) {
466 throw new \RuntimeException(
'No valid wizard identifier given', 1502721731);