‪TYPO3CMS  9.5
DefaultTcaSchema.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
3 
5 
6 /*
7  * This file is part of the TYPO3 CMS project.
8  *
9  * It is free software; you can redistribute it and/or modify it under
10  * the terms of the GNU General Public License, either version 2
11  * of the License, or any later version.
12  *
13  * For the full copyright and license information, please read the
14  * LICENSE.txt file that was distributed with this source code.
15  *
16  * The TYPO3 project - inspiring people to share!
17  */
18 
19 use Doctrine\DBAL\Schema\Table;
20 
35 {
46  public function ‪enrich(array $tables): array
47  {
48  foreach (‪$GLOBALS['TCA'] as $tableName => $tableDefinition) {
49  $isTableDefined = $this->‪isTableDefined($tables, $tableName);
50  if (!$isTableDefined) {
51  continue;
52  }
53 
54  // If the table is given in existing $tables list, add all fields to the first
55  // position of that table - in case it is in there multiple times which happens
56  // if extensions add single fields to tables that have been defined in
57  // other ext_tables.sql, too.
58  $tablePosition = $this->‪getTableFirstPosition($tables, $tableName);
59 
60  // uid column and primary key if uid is not defined
61  if (!$this->‪isColumnDefinedForTable($tables, $tableName, 'uid')) {
62  $tables[$tablePosition]->addColumn(
63  $this->‪quote('uid'),
64  'integer',
65  [
66  'notnull' => true,
67  'unsigned' => true,
68  'autoincrement' => true,
69  ]
70  );
71  $tables[$tablePosition]->setPrimaryKey(['uid']);
72  }
73 
74  // pid column and prepare parent key if pid is not defined
75  $pidColumnAdded = false;
76  if (!$this->‪isColumnDefinedForTable($tables, $tableName, 'pid')) {
77  $options = [
78  'default' => 0,
79  'notnull' => true,
80  'unsigned' => false,
81  ];
82  if (empty($tableDefinition['ctrl']['versioningWS'])) {
83  // We need negative pid's (-1) if table is workspace aware
84  $options['unsigned'] = true;
85  }
86  $tables[$tablePosition]->addColumn($this->‪quote('pid'), 'integer', $options);
87  $pidColumnAdded = true;
88  }
89 
90  // tstamp column
91  if (!empty($tableDefinition['ctrl']['tstamp'])
92  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['tstamp'])
93  ) {
94  $tables[$tablePosition]->addColumn(
95  $this->‪quote($tableDefinition['ctrl']['tstamp']),
96  'integer',
97  [
98  'default' => 0,
99  'notnull' => true,
100  'unsigned' => true,
101  ]
102  );
103  }
104 
105  // crdate column
106  if (!empty($tableDefinition['ctrl']['crdate'])
107  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['crdate'])
108  ) {
109  $tables[$tablePosition]->addColumn(
110  $this->‪quote($tableDefinition['ctrl']['crdate']),
111  'integer',
112  [
113  'default' => 0,
114  'notnull' => true,
115  'unsigned' => true,
116  ]
117  );
118  }
119 
120  // cruser_id column
121  if (!empty($tableDefinition['ctrl']['cruser_id'])
122  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['cruser_id'])
123  ) {
124  $tables[$tablePosition]->addColumn(
125  $this->‪quote($tableDefinition['ctrl']['cruser_id']),
126  'integer',
127  [
128  'default' => 0,
129  'notnull' => true,
130  'unsigned' => true,
131  ]
132  );
133  }
134 
135  // deleted column - soft delete
136  if (!empty($tableDefinition['ctrl']['delete'])
137  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['delete'])
138  ) {
139  $tables[$tablePosition]->addColumn(
140  $this->‪quote($tableDefinition['ctrl']['delete']),
141  'smallint',
142  [
143  'default' => 0,
144  'notnull' => true,
145  'unsigned' => true,
146  ]
147  );
148  }
149 
150  // disabled column
151  if (!empty($tableDefinition['ctrl']['enablecolumns']['disabled'])
152  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['enablecolumns']['disabled'])
153  ) {
154  $tables[$tablePosition]->addColumn(
155  $this->‪quote($tableDefinition['ctrl']['enablecolumns']['disabled']),
156  'smallint',
157  [
158  'default' => 0,
159  'notnull' => true,
160  'unsigned' => true,
161  ]
162  );
163  }
164 
165  // starttime column
166  if (!empty($tableDefinition['ctrl']['enablecolumns']['starttime'])
167  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['enablecolumns']['starttime'])
168  ) {
169  $tables[$tablePosition]->addColumn(
170  $this->‪quote($tableDefinition['ctrl']['enablecolumns']['starttime']),
171  'integer',
172  [
173  'default' => 0,
174  'notnull' => true,
175  'unsigned' => true,
176  ]
177  );
178  }
179 
180  // endtime column
181  if (!empty($tableDefinition['ctrl']['enablecolumns']['endtime'])
182  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['enablecolumns']['endtime'])
183  ) {
184  $tables[$tablePosition]->addColumn(
185  $this->‪quote($tableDefinition['ctrl']['enablecolumns']['endtime']),
186  'integer',
187  [
188  'default' => 0,
189  'notnull' => true,
190  'unsigned' => true,
191  ]
192  );
193  }
194 
195  // fe_group column
196  if (!empty($tableDefinition['ctrl']['enablecolumns']['fe_group'])
197  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['enablecolumns']['fe_group'])
198  ) {
199  $tables[$tablePosition]->addColumn(
200  $this->‪quote($tableDefinition['ctrl']['enablecolumns']['fe_group']),
201  'string',
202  [
203  'default' => '0',
204  'notnull' => true,
205  'length' => 255,
206  ]
207  );
208  }
209 
210  // sorting column
211  if (!empty($tableDefinition['ctrl']['sortby'])
212  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['sortby'])
213  ) {
214  $tables[$tablePosition]->addColumn(
215  $this->‪quote($tableDefinition['ctrl']['sortby']),
216  'integer',
217  [
218  'default' => 0,
219  'notnull' => true,
220  'unsigned' => false,
221  ]
222  );
223  }
224 
225  // index on pid column and maybe others - only if pid has not been defined via ext_tables.sql before
226  if ($pidColumnAdded && !$this->‪isIndexDefinedForTable($tables, $tableName, 'parent')) {
227  $parentIndexFields = ['pid'];
228  if (!empty($tableDefinition['ctrl']['delete'])) {
229  $parentIndexFields[] = (string)$tableDefinition['ctrl']['delete'];
230  }
231  if (!empty($tableDefinition['ctrl']['enablecolumns']['disabled'])) {
232  $parentIndexFields[] = (string)$tableDefinition['ctrl']['enablecolumns']['disabled'];
233  }
234  $tables[$tablePosition]->addIndex($parentIndexFields, 'parent');
235  }
236 
237  // description column
238  if (!empty($tableDefinition['ctrl']['descriptionColumn'])
239  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['descriptionColumn'])
240  ) {
241  $tables[$tablePosition]->addColumn(
242  $this->‪quote($tableDefinition['ctrl']['descriptionColumn']),
243  'text',
244  [
245  'notnull' => false,
246  'length' => 65535,
247  ]
248  );
249  }
250 
251  // editlock column
252  if (!empty($tableDefinition['ctrl']['editlock'])
253  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['editlock'])
254  ) {
255  $tables[$tablePosition]->addColumn(
256  $this->‪quote($tableDefinition['ctrl']['editlock']),
257  'smallint',
258  [
259  'default' => 0,
260  'notnull' => true,
261  'unsigned' => true,
262  ]
263  );
264  }
265 
266  // sys_language_uid column
267  if (!empty($tableDefinition['ctrl']['languageField'])
268  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['languageField'])
269  ) {
270  $tables[$tablePosition]->addColumn(
271  $this->‪quote((string)$tableDefinition['ctrl']['languageField']),
272  'integer',
273  [
274  'default' => 0,
275  'notnull' => true,
276  'unsigned' => false,
277  ]
278  );
279  }
280 
281  // l10n_parent column
282  if (!empty($tableDefinition['ctrl']['languageField'])
283  && !empty($tableDefinition['ctrl']['transOrigPointerField'])
284  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['transOrigPointerField'])
285  ) {
286  $tables[$tablePosition]->addColumn(
287  $this->‪quote((string)$tableDefinition['ctrl']['transOrigPointerField']),
288  'integer',
289  [
290  'default' => 0,
291  'notnull' => true,
292  'unsigned' => true,
293  ]
294  );
295  }
296 
297  // l10n_source column
298  if (!empty($tableDefinition['ctrl']['languageField'])
299  && !empty($tableDefinition['ctrl']['translationSource'])
300  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['translationSource'])
301  ) {
302  $tables[$tablePosition]->addColumn(
303  $this->‪quote((string)$tableDefinition['ctrl']['translationSource']),
304  'integer',
305  [
306  'default' => 0,
307  'notnull' => true,
308  'unsigned' => true,
309  ]
310  );
311  $tables[$tablePosition]->addIndex([$tableDefinition['ctrl']['translationSource']], 'translation_source');
312  }
313 
314  // l10n_state column
315  if (!empty($tableDefinition['ctrl']['languageField'])
316  && !empty($tableDefinition['ctrl']['transOrigPointerField'])
317  && !$this->‪isColumnDefinedForTable($tables, $tableName, 'l10n_state')
318  ) {
319  $tables[$tablePosition]->addColumn(
320  $this->‪quote('l10n_state'),
321  'text',
322  [
323  'notnull' => false,
324  'length' => 65535,
325  ]
326  );
327  }
328 
329  // t3_origuid column
330  if (!empty($tableDefinition['ctrl']['origUid'])
331  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['origUid'])
332  ) {
333  $tables[$tablePosition]->addColumn(
334  $this->‪quote($tableDefinition['ctrl']['origUid']),
335  'integer',
336  [
337  'default' => 0,
338  'notnull' => true,
339  'unsigned' => true,
340  ]
341  );
342  }
343 
344  // l18n_diffsource column
345  if (!empty($tableDefinition['ctrl']['transOrigDiffSourceField'])
346  && !$this->‪isColumnDefinedForTable($tables, $tableName, $tableDefinition['ctrl']['transOrigDiffSourceField'])
347  ) {
348  $tables[$tablePosition]->addColumn(
349  $this->‪quote($tableDefinition['ctrl']['transOrigDiffSourceField']),
350  'blob',
351  [
352  // mediumblob (16MB) on mysql
353  'length' => 16777215,
354  'notnull' => false,
355  ]
356  );
357  }
358 
359  // workspaces t3ver_oid column
360  if (!empty($tableDefinition['ctrl']['versioningWS'])
361  && (bool)$tableDefinition['ctrl']['versioningWS'] === true
362  && !$this->‪isColumnDefinedForTable($tables, $tableName, 't3ver_oid')
363  ) {
364  $tables[$tablePosition]->addColumn(
365  $this->‪quote('t3ver_oid'),
366  'integer',
367  [
368  'default' => 0,
369  'notnull' => true,
370  'unsigned' => true,
371  ]
372  );
373  }
374 
375  // workspaces t3ver_id column
376  if (!empty($tableDefinition['ctrl']['versioningWS'])
377  && (bool)$tableDefinition['ctrl']['versioningWS'] === true
378  && !$this->‪isColumnDefinedForTable($tables, $tableName, 't3ver_id')
379  ) {
380  $tables[$tablePosition]->addColumn(
381  $this->‪quote('t3ver_id'),
382  'integer',
383  [
384  'default' => 0,
385  'notnull' => true,
386  'unsigned' => true,
387  ]
388  );
389  }
390 
391  // workspaces t3ver_label column
392  if (!empty($tableDefinition['ctrl']['versioningWS'])
393  && (bool)$tableDefinition['ctrl']['versioningWS'] === true
394  && !$this->‪isColumnDefinedForTable($tables, $tableName, 't3ver_label')
395  ) {
396  $tables[$tablePosition]->addColumn(
397  $this->‪quote('t3ver_label'),
398  'string',
399  [
400  'default' => '',
401  'notnull' => true,
402  'length' => 255,
403  ]
404  );
405  }
406 
407  // workspaces t3ver_wsid column
408  if (!empty($tableDefinition['ctrl']['versioningWS'])
409  && (bool)$tableDefinition['ctrl']['versioningWS'] === true
410  && !$this->‪isColumnDefinedForTable($tables, $tableName, 't3ver_wsid')
411  ) {
412  $tables[$tablePosition]->addColumn(
413  $this->‪quote('t3ver_wsid'),
414  'integer',
415  [
416  'default' => 0,
417  'notnull' => true,
418  'unsigned' => true,
419  ]
420  );
421  }
422 
423  // workspaces t3ver_state column
424  if (!empty($tableDefinition['ctrl']['versioningWS'])
425  && (bool)$tableDefinition['ctrl']['versioningWS'] === true
426  && !$this->‪isColumnDefinedForTable($tables, $tableName, 't3ver_state')
427  ) {
428  $tables[$tablePosition]->addColumn(
429  $this->‪quote('t3ver_state'),
430  'smallint',
431  [
432  'default' => 0,
433  'notnull' => true,
434  'unsigned' => false,
435  ]
436  );
437  }
438 
439  // workspaces t3ver_stage column
440  if (!empty($tableDefinition['ctrl']['versioningWS'])
441  && (bool)$tableDefinition['ctrl']['versioningWS'] === true
442  && !$this->‪isColumnDefinedForTable($tables, $tableName, 't3ver_stage')
443  ) {
444  $tables[$tablePosition]->addColumn(
445  $this->‪quote('t3ver_stage'),
446  'integer',
447  [
448  'default' => 0,
449  'notnull' => true,
450  'unsigned' => false,
451  ]
452  );
453  }
454 
455  // workspaces t3ver_count column
456  if (!empty($tableDefinition['ctrl']['versioningWS'])
457  && (bool)$tableDefinition['ctrl']['versioningWS'] === true
458  && !$this->‪isColumnDefinedForTable($tables, $tableName, 't3ver_count')
459  ) {
460  $tables[$tablePosition]->addColumn(
461  $this->‪quote('t3ver_count'),
462  'integer',
463  [
464  'default' => 0,
465  'notnull' => true,
466  'unsigned' => true,
467  ]
468  );
469  }
470 
471  // workspaces t3ver_tstamp column
472  if (!empty($tableDefinition['ctrl']['versioningWS'])
473  && (bool)$tableDefinition['ctrl']['versioningWS'] === true
474  && !$this->‪isColumnDefinedForTable($tables, $tableName, 't3ver_tstamp')
475  ) {
476  $tables[$tablePosition]->addColumn(
477  $this->‪quote('t3ver_tstamp'),
478  'integer',
479  [
480  'default' => 0,
481  'notnull' => true,
482  'unsigned' => true,
483  ]
484  );
485  }
486 
487  // workspaces t3ver_move_id column
488  if (!empty($tableDefinition['ctrl']['versioningWS'])
489  && (bool)$tableDefinition['ctrl']['versioningWS'] === true
490  && !$this->‪isColumnDefinedForTable($tables, $tableName, 't3ver_move_id')
491  ) {
492  $tables[$tablePosition]->addColumn(
493  $this->‪quote('t3ver_move_id'),
494  'integer',
495  [
496  'default' => 0,
497  'notnull' => true,
498  'unsigned' => true,
499  ]
500  );
501  }
502 
503  // workspaces index on t3ver_oid and t3ver_wsid fields
504  if (!empty($tableDefinition['ctrl']['versioningWS'])
505  && (bool)$tableDefinition['ctrl']['versioningWS'] === true
506  && !$this->‪isIndexDefinedForTable($tables, $tableName, 't3ver_oid')
507  ) {
508  $tables[$tablePosition]->addIndex(['t3ver_oid', 't3ver_wsid'], 't3ver_oid');
509  }
510  }
511 
512  return $tables;
513  }
514 
521  public function ‪getPrioritizedFieldNames(string $tableName): array
522  {
523  if (!isset(‪$GLOBALS['TCA'][$tableName]['ctrl'])) {
524  return [];
525  }
526 
527  $prioritizedFieldNames = [
528  'uid',
529  'pid'
530  ];
531 
532  $tableDefinition = ‪$GLOBALS['TCA'][$tableName]['ctrl'];
533 
534  if (!empty($tableDefinition['crdate'])) {
535  $prioritizedFieldNames[] = $tableDefinition['crdate'];
536  }
537  if (!empty($tableDefinition['tstamp'])) {
538  $prioritizedFieldNames[] = $tableDefinition['tstamp'];
539  }
540  if (!empty($tableDefinition['cruser_id'])) {
541  $prioritizedFieldNames[] = $tableDefinition['cruser_id'];
542  }
543  if (!empty($tableDefinition['delete'])) {
544  $prioritizedFieldNames[] = $tableDefinition['delete'];
545  }
546  if (!empty($tableDefinition['enablecolumns']['disabled'])) {
547  $prioritizedFieldNames[] = $tableDefinition['enablecolumns']['disabled'];
548  }
549  if (!empty($tableDefinition['enablecolumns']['starttime'])) {
550  $prioritizedFieldNames[] = $tableDefinition['enablecolumns']['starttime'];
551  }
552  if (!empty($tableDefinition['enablecolumns']['endtime'])) {
553  $prioritizedFieldNames[] = $tableDefinition['enablecolumns']['endtime'];
554  }
555  if (!empty($tableDefinition['enablecolumns']['fe_group'])) {
556  $prioritizedFieldNames[] = $tableDefinition['enablecolumns']['fe_group'];
557  }
558  if (!empty($tableDefinition['languageField'])) {
559  $prioritizedFieldNames[] = $tableDefinition['languageField'];
560  if (!empty($tableDefinition['transOrigPointerField'])) {
561  $prioritizedFieldNames[] = $tableDefinition['transOrigPointerField'];
562  $prioritizedFieldNames[] = 'l10n_state';
563  }
564  if (!empty($tableDefinition['translationSource'])) {
565  $prioritizedFieldNames[] = $tableDefinition['translationSource'];
566  }
567  if (!empty($tableDefinition['transOrigDiffSourceField'])) {
568  $prioritizedFieldNames[] = $tableDefinition['transOrigDiffSourceField'];
569  }
570  }
571  if (!empty($tableDefinition['sortby'])) {
572  $prioritizedFieldNames[] = $tableDefinition['sortby'];
573  }
574  if (!empty($tableDefinition['descriptionColumn'])) {
575  $prioritizedFieldNames[] = $tableDefinition['descriptionColumn'];
576  }
577  if (!empty($tableDefinition['editlock'])) {
578  $prioritizedFieldNames[] = $tableDefinition['editlock'];
579  }
580  if (!empty($tableDefinition['origUid'])) {
581  $prioritizedFieldNames[] = $tableDefinition['origUid'];
582  }
583  if (!empty($tableDefinition['versioningWS'])) {
584  $prioritizedFieldNames[] = 't3ver_wsid';
585  $prioritizedFieldNames[] = 't3ver_oid';
586  $prioritizedFieldNames[] = 't3ver_state';
587  $prioritizedFieldNames[] = 't3ver_stage';
588  $prioritizedFieldNames[] = 't3ver_id';
589  $prioritizedFieldNames[] = 't3ver_move_id';
590  $prioritizedFieldNames[] = 't3ver_count';
591  $prioritizedFieldNames[] = 't3ver_tstamp';
592  $prioritizedFieldNames[] = 't3ver_label';
593  }
594 
595  return $prioritizedFieldNames;
596  }
597 
605  protected function ‪isTableDefined(array $tables, string $tableName): bool
606  {
607  foreach ($tables as $table) {
608  if ($table->getName() === $tableName) {
609  return true;
610  }
611  }
612  return false;
613  }
614 
624  protected function ‪isColumnDefinedForTable(array $tables, string $tableName, string $fieldName): bool
625  {
626  foreach ($tables as $table) {
627  if ($table->getName() !== $tableName) {
628  continue;
629  }
630  $columns = $table->getColumns();
631  foreach ($columns as $column) {
632  if ($column->getName() === $fieldName) {
633  return true;
634  }
635  }
636  }
637  return false;
638  }
639 
649  protected function ‪isIndexDefinedForTable(array $tables, string $tableName, string $indexName): bool
650  {
651  foreach ($tables as $table) {
652  if ($table->getName() !== $tableName) {
653  continue;
654  }
655  $indexes = $table->getIndexes();
656  foreach ($indexes as $index) {
657  if ($index->getName() === $indexName) {
658  return true;
659  }
660  }
661  }
662  return false;
663  }
664 
679  protected function ‪getTableFirstPosition(array $tables, string $tableName): int
680  {
681  foreach ($tables as $position => $table) {
682  if ($table->getName() === $tableName) {
683  return (int)$position;
684  }
685  }
686  throw new \RuntimeException('Table ' . $tableName . ' not found in schema list', 1527854474);
687  }
688 
693  protected function ‪quote(string $identifier): string
694  {
695  return '`' . $identifier . '`';
696  }
697 }
‪TYPO3\CMS\Core\Database\Schema\DefaultTcaSchema\isIndexDefinedForTable
‪bool isIndexDefinedForTable(array $tables, string $tableName, string $indexName)
Definition: DefaultTcaSchema.php:649
‪TYPO3\CMS\Core\Database\Schema\DefaultTcaSchema\getTableFirstPosition
‪int getTableFirstPosition(array $tables, string $tableName)
Definition: DefaultTcaSchema.php:679
‪TYPO3\CMS\Core\Database\Schema
Definition: Comparator.php:3
‪TYPO3\CMS\Core\Database\Schema\DefaultTcaSchema
Definition: DefaultTcaSchema.php:35
‪TYPO3\CMS\Core\Database\Schema\DefaultTcaSchema\isTableDefined
‪bool isTableDefined(array $tables, string $tableName)
Definition: DefaultTcaSchema.php:605
‪TYPO3\CMS\Core\Database\Schema\DefaultTcaSchema\isColumnDefinedForTable
‪bool isColumnDefinedForTable(array $tables, string $tableName, string $fieldName)
Definition: DefaultTcaSchema.php:624
‪TYPO3\CMS\Core\Database\Schema\DefaultTcaSchema\quote
‪string quote(string $identifier)
Definition: DefaultTcaSchema.php:693
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Database\Schema\DefaultTcaSchema\getPrioritizedFieldNames
‪string[] getPrioritizedFieldNames(string $tableName)
Definition: DefaultTcaSchema.php:521
‪TYPO3\CMS\Core\Database\Schema\DefaultTcaSchema\enrich
‪Table[] enrich(array $tables)
Definition: DefaultTcaSchema.php:46