‪TYPO3CMS  9.5
SchemaMigrator.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
18 use Doctrine\DBAL\DBALException;
19 use Doctrine\DBAL\Schema\Schema;
20 use Doctrine\DBAL\Schema\SchemaDiff;
21 use Doctrine\DBAL\Schema\Table;
27 
35 {
39  protected ‪$schema = [];
40 
57  public function ‪getUpdateSuggestions(array $statements, bool $remove = false): array
58  {
59  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
60  $tables = $this->‪parseCreateTableStatements($statements);
61 
62  $updateSuggestions = [];
63 
64  foreach ($connectionPool->getConnectionNames() as $connectionName) {
65  $connectionMigrator = ‪ConnectionMigrator::create(
66  $connectionName,
67  $tables
68  );
69 
70  $updateSuggestions[$connectionName] =
71  $connectionMigrator->getUpdateSuggestions($remove);
72  }
73 
74  return $updateSuggestions;
75  }
76 
92  public function ‪getSchemaDiffs(array $statements): array
93  {
94  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
95  $tables = $this->‪parseCreateTableStatements($statements);
96 
97  $schemaDiffs = [];
98 
99  foreach ($connectionPool->getConnectionNames() as $connectionName) {
100  $connectionMigrator = ‪ConnectionMigrator::create(
101  $connectionName,
102  $tables
103  );
104  $schemaDiffs[$connectionName] = $connectionMigrator->getSchemaDiff();
105  }
106 
107  return $schemaDiffs;
108  }
109 
126  public function ‪migrate(array $statements, array $selectedStatements): array
127  {
128  $result = [];
129  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
130  $updateSuggestionsPerConnection = array_merge_recursive(
131  $this->‪getUpdateSuggestions($statements),
132  $this->‪getUpdateSuggestions($statements, true)
133  );
134 
135  foreach ($updateSuggestionsPerConnection as $connectionName => $updateSuggestions) {
136  unset($updateSuggestions['tables_count'], $updateSuggestions['change_currentValue']);
137  $updateSuggestions = array_merge(...array_values($updateSuggestions));
138  $statementsToExecute = array_intersect_key($updateSuggestions, $selectedStatements);
139  if (count($statementsToExecute) === 0) {
140  continue;
141  }
142 
143  $connection = $connectionPool->getConnectionByName($connectionName);
144  foreach ($statementsToExecute as $hash => $statement) {
145  try {
146  $connection->executeUpdate($statement);
147  } catch (DBALException $e) {
148  $result[$hash] = $e->getPrevious()->getMessage();
149  }
150  }
151  }
152 
153  return $result;
154  }
155 
173  public function ‪install(array $statements, bool $createOnly = false): array
174  {
175  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
176  $tables = $this->‪parseCreateTableStatements($statements);
177  $result = [];
178 
179  foreach ($connectionPool->getConnectionNames() as $connectionName) {
180  $connectionMigrator = ‪ConnectionMigrator::create(
181  $connectionName,
182  $tables
183  );
184 
185  $lastResult = $connectionMigrator->install($createOnly);
186  $result = array_merge($result, $lastResult);
187  }
188 
189  return $result;
190  }
191 
199  public function ‪importStaticData(array $statements, bool $truncate = false): array
200  {
201  $result = [];
202  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
203  $insertStatements = [];
204 
205  foreach ($statements as $statement) {
206  // Only handle insert statements and extract the table at the same time. Extracting
207  // the table name is required to perform the inserts on the right connection.
208  if (preg_match('/^INSERT\s+INTO\s+`?(\w+)`?(.*)/i', $statement, $matches)) {
209  list(, $tableName, $sqlFragment) = $matches;
210  $insertStatements[$tableName][] = sprintf(
211  'INSERT INTO %s %s',
212  $connectionPool->getConnectionForTable($tableName)->quoteIdentifier($tableName),
213  rtrim($sqlFragment, ';')
214  );
215  }
216  }
217 
218  foreach ($insertStatements as $tableName => $perTableStatements) {
219  $connection = $connectionPool->getConnectionForTable($tableName);
220 
221  if ($truncate) {
222  $connection->truncate($tableName);
223  }
224 
225  foreach ((array)$perTableStatements as $statement) {
226  try {
227  $connection->executeUpdate($statement);
228  $result[$statement] = '';
229  } catch (DBALException $e) {
230  $result[$statement] = $e->getPrevious()->getMessage();
231  }
232  }
233  }
234 
235  return $result;
236  }
237 
251  public function ‪parseCreateTableStatements(array $statements): array
252  {
253  $tables = [];
254  foreach ($statements as $statement) {
255  $createTableParser = GeneralUtility::makeInstance(Parser::class, $statement);
256 
257  // We need to keep multiple table definitions at this point so
258  // that Extensions can modify existing tables.
259  try {
260  $tables[] = $createTableParser->parse();
261  } catch (‪StatementException $statementException) {
262  // Enrich the error message with the full invalid statement
263  throw new ‪StatementException(
264  $statementException->getMessage() . ' in statement: ' . LF . $statement,
265  1476171315,
266  $statementException
267  );
268  }
269  }
270 
271  // Flatten the array of arrays by one level
272  $tables = array_merge(...$tables);
273 
274  // @deprecated (?!) Drop any definition of pages_language_overlay in SQL
275  // will be removed in TYPO3 v10.0 once the feature is enabled by default
276  $disabledPagesLanguageOverlay = GeneralUtility::makeInstance(Features::class)->isFeatureEnabled('unifiedPageTranslationHandling');
277 
278  // Add default TCA fields
279  $defaultTcaSchema = GeneralUtility::makeInstance(DefaultTcaSchema::class);
280  $tables = $defaultTcaSchema->enrich($tables);
281  // Ensure the default TCA fields are ordered
282  foreach ($tables as $k => $table) {
283  if ($disabledPagesLanguageOverlay && $table->getName() === 'pages_language_overlay') {
284  unset($tables[$k]);
285  continue;
286  }
287  $prioritizedColumnNames = $defaultTcaSchema->getPrioritizedFieldNames($table->getName());
288  // no TCA table
289  if (empty($prioritizedColumnNames)) {
290  continue;
291  }
292 
293  $prioritizedColumns = [];
294  $nonPrioritizedColumns = [];
295 
296  foreach ($table->getColumns() as $columnObject) {
297  if (in_array($columnObject->getName(), $prioritizedColumnNames, true)) {
298  $prioritizedColumns[] = $columnObject;
299  } else {
300  $nonPrioritizedColumns[] = $columnObject;
301  }
302  }
303 
304  $tables[$k] = new Table(
305  $table->getName(),
306  array_merge($prioritizedColumns, $nonPrioritizedColumns),
307  $table->getIndexes(),
308  $table->getForeignKeys(),
309  0,
310  $table->getOptions()
311  );
312  }
313 
314  return $tables;
315  }
316 }
‪TYPO3\CMS\Core\Database\Schema\ConnectionMigrator\create
‪static ConnectionMigrator create(string $connectionName, array $tables)
Definition: ConnectionMigrator.php:75
‪TYPO3\CMS\Core\Database\Schema\Exception\StatementException
Definition: StatementException.php:23
‪TYPO3\CMS\Core\Database\Schema\SchemaMigrator\importStaticData
‪array importStaticData(array $statements, bool $truncate=false)
Definition: SchemaMigrator.php:198
‪TYPO3\CMS\Core\Database\Schema\SchemaMigrator\$schema
‪Schema[] $schema
Definition: SchemaMigrator.php:38
‪TYPO3\CMS\Core\Database\Schema\SchemaMigrator\getSchemaDiffs
‪SchemaDiff[] getSchemaDiffs(array $statements)
Definition: SchemaMigrator.php:91
‪TYPO3\CMS\Core\Database\Schema
Definition: Comparator.php:3
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser
Definition: Parser.php:28
‪TYPO3\CMS\Core\Database\Schema\SchemaMigrator
Definition: SchemaMigrator.php:35
‪TYPO3\CMS\Core\Database\Schema\SchemaMigrator\getUpdateSuggestions
‪array[] getUpdateSuggestions(array $statements, bool $remove=false)
Definition: SchemaMigrator.php:56
‪TYPO3\CMS\Core\Database\Schema\SchemaMigrator\install
‪array[] install(array $statements, bool $createOnly=false)
Definition: SchemaMigrator.php:172
‪TYPO3\CMS\Core\Configuration\Features
Definition: Features.php:54
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:44
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Core\Database\Schema\SchemaMigrator\parseCreateTableStatements
‪Table[] parseCreateTableStatements(array $statements)
Definition: SchemaMigrator.php:250
‪TYPO3\CMS\Core\Database\Schema\SchemaMigrator\migrate
‪array migrate(array $statements, array $selectedStatements)
Definition: SchemaMigrator.php:125