‪TYPO3CMS  10.4
TableBuilder.php
Go to the documentation of this file.
1 <?php
2 
3 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 
19 
20 use Doctrine\DBAL\Platforms\AbstractPlatform;
21 use Doctrine\DBAL\Platforms\MySqlPlatform;
22 use Doctrine\DBAL\Schema\Column;
23 use Doctrine\DBAL\Schema\Index;
24 use Doctrine\DBAL\Schema\Table;
25 use Doctrine\DBAL\Types\Type;
26 use Doctrine\DBAL\Types\Types;
68 
74 {
78  protected ‪$table;
79 
83  protected ‪$platform;
84 
92  public function ‪__construct(AbstractPlatform ‪$platform = null)
93  {
94  // Register custom data types as no connection might have
95  // been established yet so the types would not be available
96  // when building tables/columns.
97  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
98 
99  foreach ($connectionPool->getCustomDoctrineTypes() as $type => $className) {
100  if (!Type::hasType($type)) {
101  Type::addType($type, $className);
102  }
103  }
104  $this->platform = ‪$platform ?: GeneralUtility::makeInstance(MySqlPlatform::class);
105  }
106 
116  public function ‪create(‪CreateTableStatement $tableStatement): Table
117  {
118  $this->table = GeneralUtility::makeInstance(
119  Table::class,
120  $tableStatement->tableName->getQuotedName(),
121  [],
122  [],
123  [],
124  0,
125  $this->buildTableOptions($tableStatement->tableOptions)
126  );
127 
128  foreach ($tableStatement->createDefinition->items as $item) {
129  switch (get_class($item)) {
130  case CreateColumnDefinitionItem::class:
131  $this->‪addColumn($item);
132  break;
133  case CreateIndexDefinitionItem::class:
134  $this->‪addIndex($item);
135  break;
136  case CreateForeignKeyDefinitionItem::class:
137  $this->‪addForeignKey($item);
138  break;
139  default:
140  throw new \RuntimeException(
141  'Unknown item definition of type "' . get_class($item) . '" encountered.',
142  1472044085
143  );
144  }
145  }
146 
147  return ‪$this->table;
148  }
149 
156  protected function ‪addColumn(‪CreateColumnDefinitionItem $item): Column
157  {
158  $column = $this->table->addColumn(
159  $item->columnName->getQuotedName(),
160  $this->getDoctrineColumnTypeName($item->dataType)
161  );
162 
163  $column->setNotnull(!$item->allowNull);
164  $column->setAutoincrement((bool)$item->autoIncrement);
165  $column->setComment($item->comment);
166 
167  // Set default value (unless it's an auto increment column)
168  if ($item->hasDefaultValue && !$column->getAutoincrement()) {
169  $column->setDefault($item->defaultValue);
170  }
171 
172  if ($item->dataType->getLength()) {
173  $column->setLength($item->dataType->getLength());
174  }
175 
176  if ($item->dataType->getPrecision() >= 0) {
177  $column->setPrecision($item->dataType->getPrecision());
178  }
179 
180  if ($item->dataType->getScale() >= 0) {
181  $column->setScale($item->dataType->getScale());
182  }
183 
184  if ($item->dataType->isUnsigned()) {
185  $column->setUnsigned(true);
186  }
187 
188  // Select CHAR/VARCHAR or BINARY/VARBINARY
189  if ($item->dataType->isFixed()) {
190  $column->setFixed(true);
191  }
192 
193  if ($item->dataType instanceof ‪EnumDataType
194  || $item->dataType instanceof ‪SetDataType
195  ) {
196  $column->setPlatformOption('unquotedValues', $item->dataType->getValues());
197  }
198 
199  if ($item->index) {
200  $this->table->addIndex([$item->columnName->getQuotedName()]);
201  }
202 
203  if ($item->unique) {
204  $this->table->addUniqueIndex([$item->columnName->getQuotedName()]);
205  }
206 
207  if ($item->primary) {
208  $this->table->setPrimaryKey([$item->columnName->getQuotedName()]);
209  }
210 
211  if ($item->reference !== null) {
213  [$item->columnName->getQuotedName()],
214  $item->reference
215  );
216  }
217 
218  return $column;
219  }
220 
227  protected function ‪addIndex(‪CreateIndexDefinitionItem $item): Index
228  {
229  $indexName = $item->indexName->getQuotedName();
230 
231  $columnNames = array_map(
232  function (‪IndexColumnName $columnName) {
233  if ($columnName->length) {
234  return $columnName->columnName->getQuotedName() . '(' . $columnName->length . ')';
235  }
236  return $columnName->columnName->getQuotedName();
237  },
238  $item->columnNames
239  );
240 
241  if ($item->isPrimary) {
242  $this->table->setPrimaryKey($columnNames);
243  $index = $this->table->getPrimaryKey();
244  } else {
245  $index = GeneralUtility::makeInstance(
246  Index::class,
247  $indexName,
248  $columnNames,
249  $item->isUnique,
250  $item->isPrimary
251  );
252 
253  if ($item->isFulltext) {
254  $index->addFlag('fulltext');
255  } elseif ($item->isSpatial) {
256  $index->addFlag('spatial');
257  }
258 
259  $this->table = GeneralUtility::makeInstance(
260  Table::class,
261  $this->table->getQuotedName($this->platform),
262  $this->table->getColumns(),
263  array_merge($this->table->getIndexes(), [strtolower($indexName) => $index]),
264  $this->table->getForeignKeys(),
265  0,
266  $this->table->getOptions()
267  );
268  }
269 
270  return $index;
271  }
272 
278  protected function ‪addForeignKey(‪CreateForeignKeyDefinitionItem $item)
279  {
280  $indexName = $item->indexName->getQuotedName() ?: null;
281  $localColumnNames = array_map(
282  function (‪IndexColumnName $columnName) {
283  return $columnName->columnName->getQuotedName();
284  },
285  $item->columnNames
286  );
287  $this->‪addForeignKeyConstraint($localColumnNames, $item->reference, $indexName);
288  }
289 
297  protected function ‪addForeignKeyConstraint(
298  array $localColumnNames,
299  ‪ReferenceDefinition $referenceDefinition,
300  string $indexName = null
301  ) {
302  $foreignTableName = $referenceDefinition->tableName->getQuotedName();
303  $foreignColumnNames = array_map(
304  function (‪IndexColumnName $columnName) {
305  return $columnName->columnName->getQuotedName();
306  },
307  $referenceDefinition->columnNames
308  );
309 
310  $options = [
311  'onDelete' => $referenceDefinition->onDelete,
312  'onUpdate' => $referenceDefinition->onUpdate,
313  ];
314 
315  $this->table->addForeignKeyConstraint(
316  $foreignTableName,
317  $localColumnNames,
318  $foreignColumnNames,
319  $options,
320  $indexName
321  );
322  }
323 
329  protected function ‪getDoctrineColumnTypeName(‪AbstractDataType $dataType): string
330  {
331  $doctrineType = null;
332  switch (get_class($dataType)) {
333  case TinyIntDataType::class:
334  // TINYINT is MySQL specific and mapped to a standard SMALLINT
335  case SmallIntDataType::class:
336  $doctrineType = Types::SMALLINT;
337  break;
338  case MediumIntDataType::class:
339  // MEDIUMINT is MySQL specific and mapped to a standard INT
340  case IntegerDataType::class:
341  $doctrineType = Types::INTEGER;
342  break;
343  case BigIntDataType::class:
344  $doctrineType = Types::BIGINT;
345  break;
346  case BinaryDataType::class:
347  case VarBinaryDataType::class:
348  // CHAR/VARCHAR is determined by "fixed" column property
349  $doctrineType = Types::BINARY;
350  break;
351  case TinyBlobDataType::class:
352  case MediumBlobDataType::class:
353  case BlobDataType::class:
354  case LongBlobDataType::class:
355  // Actual field type is determined by field length
356  $doctrineType = Types::BLOB;
357  break;
358  case DateDataType::class:
359  $doctrineType = Types::DATE_MUTABLE;
360  break;
361  case TimestampDataType::class:
362  case DateTimeDataType::class:
363  // TIMESTAMP or DATETIME are determined by "version" column property
364  $doctrineType = Types::DATETIME_MUTABLE;
365  break;
366  case NumericDataType::class:
367  case DecimalDataType::class:
368  $doctrineType = Types::DECIMAL;
369  break;
370  case RealDataType::class:
371  case FloatDataType::class:
372  case DoubleDataType::class:
373  $doctrineType = Types::FLOAT;
374  break;
375  case TimeDataType::class:
376  $doctrineType = Types::TIME_MUTABLE;
377  break;
378  case TinyTextDataType::class:
379  case MediumTextDataType::class:
380  case TextDataType::class:
381  case LongTextDataType::class:
382  $doctrineType = Types::TEXT;
383  break;
384  case CharDataType::class:
385  case VarCharDataType::class:
386  $doctrineType = Types::STRING;
387  break;
388  case EnumDataType::class:
389  $doctrineType = ‪EnumType::TYPE;
390  break;
391  case SetDataType::class:
392  $doctrineType = ‪SetType::TYPE;
393  break;
394  case JsonDataType::class:
395  // JSON is not supported in Doctrine 2.5, mapping to the more generic TEXT type
396  $doctrineType = Types::TEXT;
397  break;
398  case YearDataType::class:
399  // The YEAR data type is MySQL specific and offers little to no benefit.
400  // The two-digit year logic implemented in this data type (1-69 mapped to
401  // 2001-2069, 70-99 mapped to 1970-1999) can be easily implemented in the
402  // application and for all other accounts it's an integer with a valid
403  // range of 1901 to 2155.
404  // Using a SMALLINT covers the value range and ensures database compatibility.
405  $doctrineType = Types::SMALLINT;
406  break;
407  default:
408  throw new \RuntimeException(
409  'Unsupported data type: ' . get_class($dataType) . '!',
410  1472046376
411  );
412  }
413 
414  return $doctrineType;
415  }
416 
423  protected function ‪buildTableOptions(array $tableOptions): array
424  {
425  $options = [];
426 
427  if (!empty($tableOptions['engine'])) {
428  $options['engine'] = (string)$tableOptions['engine'];
429  }
430  if (!empty($tableOptions['character_set'])) {
431  $options['charset'] = (string)$tableOptions['character_set'];
432  }
433  if (!empty($tableOptions['collation'])) {
434  $options['collate'] = (string)$tableOptions['collation'];
435  }
436  if (!empty($tableOptions['auto_increment'])) {
437  $options['auto_increment'] = (string)$tableOptions['auto_increment'];
438  }
439  if (!empty($tableOptions['comment'])) {
440  $options['comment'] = (string)$tableOptions['comment'];
441  }
442  if (!empty($tableOptions['row_format'])) {
443  $options['row_format'] = (string)$tableOptions['row_format'];
444  }
445 
446  return $options;
447  }
448 }
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\BigIntDataType
Definition: BigIntDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\TimeDataType
Definition: TimeDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\VarCharDataType
Definition: VarCharDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\DateTimeDataType
Definition: DateTimeDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\JsonDataType
Definition: JsonDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\CreateTableStatement
Definition: CreateTableStatement.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\CreateColumnDefinitionItem
Definition: CreateColumnDefinitionItem.php:27
‪TYPO3\CMS\Core\Database\Schema\Types\SetType
Definition: SetType.php:27
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\CreateIndexDefinitionItem
Definition: CreateIndexDefinitionItem.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\TableBuilder\addIndex
‪Doctrine DBAL Schema Index addIndex(CreateIndexDefinitionItem $item)
Definition: TableBuilder.php:225
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\VarBinaryDataType
Definition: VarBinaryDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\RealDataType
Definition: RealDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\TinyTextDataType
Definition: TinyTextDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Types\EnumType
Definition: EnumType.php:27
‪TYPO3\CMS\Core\Database\Schema\Parser\TableBuilder
Definition: TableBuilder.php:74
‪TYPO3\CMS\Core\Database\Schema\Parser\TableBuilder\addForeignKey
‪addForeignKey(CreateForeignKeyDefinitionItem $item)
Definition: TableBuilder.php:276
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\CreateForeignKeyDefinitionItem
Definition: CreateForeignKeyDefinitionItem.php:24
‪TYPO3\CMS\Core\Database\Schema\Types\EnumType\TYPE
‪const TYPE
Definition: EnumType.php:28
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\TextDataType
Definition: TextDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\MediumTextDataType
Definition: MediumTextDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\TableBuilder\create
‪Doctrine DBAL Schema Table create(CreateTableStatement $tableStatement)
Definition: TableBuilder.php:114
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\TinyBlobDataType
Definition: TinyBlobDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\TableBuilder\getDoctrineColumnTypeName
‪string getDoctrineColumnTypeName(AbstractDataType $dataType)
Definition: TableBuilder.php:327
‪TYPO3\CMS\Core\Database\Schema\Parser\TableBuilder\__construct
‪__construct(AbstractPlatform $platform=null)
Definition: TableBuilder.php:90
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\CharDataType
Definition: CharDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\SetDataType
Definition: SetDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\IntegerDataType
Definition: IntegerDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\TableBuilder\buildTableOptions
‪array buildTableOptions(array $tableOptions)
Definition: TableBuilder.php:421
‪TYPO3\CMS\Core\Database\Schema\Parser\TableBuilder\addForeignKeyConstraint
‪addForeignKeyConstraint(array $localColumnNames, ReferenceDefinition $referenceDefinition, string $indexName=null)
Definition: TableBuilder.php:295
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\AbstractDataType
Definition: AbstractDataType.php:25
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\LongTextDataType
Definition: LongTextDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\MediumIntDataType
Definition: MediumIntDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\FloatDataType
Definition: FloatDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\DoubleDataType
Definition: DoubleDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\MediumBlobDataType
Definition: MediumBlobDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\TinyIntDataType
Definition: TinyIntDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\BinaryDataType
Definition: BinaryDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\DecimalDataType
Definition: DecimalDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\TableBuilder\$platform
‪AbstractPlatform $platform
Definition: TableBuilder.php:81
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\IndexColumnName
Definition: IndexColumnName.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\BlobDataType
Definition: BlobDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser
‪TYPO3\CMS\Core\Database\Schema\Parser\TableBuilder\$table
‪Table $table
Definition: TableBuilder.php:77
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\LongBlobDataType
Definition: LongBlobDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\DateDataType
Definition: DateDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\NumericDataType
Definition: NumericDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\SmallIntDataType
Definition: SmallIntDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\TableBuilder\addColumn
‪Doctrine DBAL Schema Column addColumn(CreateColumnDefinitionItem $item)
Definition: TableBuilder.php:154
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\EnumDataType
Definition: EnumDataType.php:24
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\ReferenceDefinition
Definition: ReferenceDefinition.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\YearDataType
Definition: YearDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\TimestampDataType
Definition: TimestampDataType.php:24
‪TYPO3\CMS\Core\Database\Schema\Types\SetType\TYPE
‪const TYPE
Definition: SetType.php:28