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