Completed
Push — master ( 585287...decea2 )
by
unknown
42:21
created

DefaultTcaSchema::tableRunsOnSqlite()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types = 1);
3
4
namespace TYPO3\CMS\Core\Database\Schema;
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
21
/**
22
 * This class is called by the SchemaMigrator after all extension's ext_tables.sql
23
 * files have been parsed and processed to the doctrine Table/Column/Index objects.
24
 *
25
 * Method enrich() goes through all $GLOBALS['TCA'] tables and adds fields like
26
 * 'uid', 'sorting', 'deleted' and friends if the feature is enabled in TCA and the
27
 * field has not been defined in ext_tables.sql files.
28
 *
29
 * This allows extension developers to leave out the TYPO3 DB management fields
30
 * and reduce ext_tables.sql of extensions down to the business fields.
31
 *
32
 * @internal
33
 */
34
class DefaultTcaSchema
35
{
36
    /**
37
     * Add fields to $tables array that has been created from ext_tables.sql files.
38
     * This goes through all tables defined in TCA, looks for 'ctrl' features like
39
     * "soft delete" ['ctrl']['delete'] and adds the field if it has not been
40
     * defined in ext_tables.sql, yet.
41
     *
42
     *
43
     * @param Table[] $tables
44
     * @return Table[]
45
     */
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_wsid column
376
            if (!empty($tableDefinition['ctrl']['versioningWS'])
377
                && (bool)$tableDefinition['ctrl']['versioningWS'] === true
378
                && !$this->isColumnDefinedForTable($tables, $tableName, 't3ver_wsid')
379
            ) {
380
                $tables[$tablePosition]->addColumn(
381
                    $this->quote('t3ver_wsid'),
382
                    'integer',
383
                    [
384
                        'default' => 0,
385
                        'notnull' => true,
386
                        'unsigned' => true,
387
                    ]
388
                );
389
            }
390
391
            // workspaces t3ver_state column
392
            if (!empty($tableDefinition['ctrl']['versioningWS'])
393
                && (bool)$tableDefinition['ctrl']['versioningWS'] === true
394
                && !$this->isColumnDefinedForTable($tables, $tableName, 't3ver_state')
395
            ) {
396
                $tables[$tablePosition]->addColumn(
397
                    $this->quote('t3ver_state'),
398
                    'smallint',
399
                    [
400
                        'default' => 0,
401
                        'notnull' => true,
402
                        'unsigned' => false,
403
                    ]
404
                );
405
            }
406
407
            // workspaces t3ver_stage column
408
            if (!empty($tableDefinition['ctrl']['versioningWS'])
409
                && (bool)$tableDefinition['ctrl']['versioningWS'] === true
410
                && !$this->isColumnDefinedForTable($tables, $tableName, 't3ver_stage')
411
            ) {
412
                $tables[$tablePosition]->addColumn(
413
                    $this->quote('t3ver_stage'),
414
                    'integer',
415
                    [
416
                        'default' => 0,
417
                        'notnull' => true,
418
                        'unsigned' => false,
419
                    ]
420
                );
421
            }
422
423
            // workspaces t3ver_count column
424
            if (!empty($tableDefinition['ctrl']['versioningWS'])
425
                && (bool)$tableDefinition['ctrl']['versioningWS'] === true
426
                && !$this->isColumnDefinedForTable($tables, $tableName, 't3ver_count')
427
            ) {
428
                $tables[$tablePosition]->addColumn(
429
                    $this->quote('t3ver_count'),
430
                    'integer',
431
                    [
432
                        'default' => 0,
433
                        'notnull' => true,
434
                        'unsigned' => true,
435
                    ]
436
                );
437
            }
438
439
            // workspaces t3ver_tstamp column
440
            if (!empty($tableDefinition['ctrl']['versioningWS'])
441
                && (bool)$tableDefinition['ctrl']['versioningWS'] === true
442
                && !$this->isColumnDefinedForTable($tables, $tableName, 't3ver_tstamp')
443
            ) {
444
                $tables[$tablePosition]->addColumn(
445
                    $this->quote('t3ver_tstamp'),
446
                    'integer',
447
                    [
448
                        'default' => 0,
449
                        'notnull' => true,
450
                        'unsigned' => true,
451
                    ]
452
                );
453
            }
454
455
            // workspaces t3ver_move_id column
456
            if (!empty($tableDefinition['ctrl']['versioningWS'])
457
                && (bool)$tableDefinition['ctrl']['versioningWS'] === true
458
                && !$this->isColumnDefinedForTable($tables, $tableName, 't3ver_move_id')
459
            ) {
460
                $tables[$tablePosition]->addColumn(
461
                    $this->quote('t3ver_move_id'),
462
                    'integer',
463
                    [
464
                        'default' => 0,
465
                        'notnull' => true,
466
                        'unsigned' => true,
467
                    ]
468
                );
469
            }
470
471
            // workspaces index on t3ver_oid and t3ver_wsid fields
472
            if (!empty($tableDefinition['ctrl']['versioningWS'])
473
                && (bool)$tableDefinition['ctrl']['versioningWS'] === true
474
                && !$this->isIndexDefinedForTable($tables, $tableName, 't3ver_oid')
475
            ) {
476
                $tables[$tablePosition]->addIndex(['t3ver_oid', 't3ver_wsid'], 't3ver_oid');
477
            }
478
        }
479
480
        return $tables;
481
    }
482
483
    /**
484
     * If the enrich() method adds fields, they should be added in the beginning of a table.
485
     *
486
     * @param string $tableName
487
     * @return string[]
488
     */
489
    public function getPrioritizedFieldNames(string $tableName): array
490
    {
491
        if (!isset($GLOBALS['TCA'][$tableName]['ctrl'])) {
492
            return [];
493
        }
494
495
        $prioritizedFieldNames = [
496
            'uid',
497
            'pid'
498
        ];
499
500
        $tableDefinition = $GLOBALS['TCA'][$tableName]['ctrl'];
501
502
        if (!empty($tableDefinition['crdate'])) {
503
            $prioritizedFieldNames[] = $tableDefinition['crdate'];
504
        }
505
        if (!empty($tableDefinition['tstamp'])) {
506
            $prioritizedFieldNames[] = $tableDefinition['tstamp'];
507
        }
508
        if (!empty($tableDefinition['cruser_id'])) {
509
            $prioritizedFieldNames[] = $tableDefinition['cruser_id'];
510
        }
511
        if (!empty($tableDefinition['delete'])) {
512
            $prioritizedFieldNames[] = $tableDefinition['delete'];
513
        }
514
        if (!empty($tableDefinition['enablecolumns']['disabled'])) {
515
            $prioritizedFieldNames[] = $tableDefinition['enablecolumns']['disabled'];
516
        }
517
        if (!empty($tableDefinition['enablecolumns']['starttime'])) {
518
            $prioritizedFieldNames[] = $tableDefinition['enablecolumns']['starttime'];
519
        }
520
        if (!empty($tableDefinition['enablecolumns']['endtime'])) {
521
            $prioritizedFieldNames[] = $tableDefinition['enablecolumns']['endtime'];
522
        }
523
        if (!empty($tableDefinition['enablecolumns']['fe_group'])) {
524
            $prioritizedFieldNames[] = $tableDefinition['enablecolumns']['fe_group'];
525
        }
526
        if (!empty($tableDefinition['languageField'])) {
527
            $prioritizedFieldNames[] = $tableDefinition['languageField'];
528
            if (!empty($tableDefinition['transOrigPointerField'])) {
529
                $prioritizedFieldNames[] = $tableDefinition['transOrigPointerField'];
530
                $prioritizedFieldNames[] = 'l10n_state';
531
            }
532
            if (!empty($tableDefinition['translationSource'])) {
533
                $prioritizedFieldNames[] = $tableDefinition['translationSource'];
534
            }
535
            if (!empty($tableDefinition['transOrigDiffSourceField'])) {
536
                $prioritizedFieldNames[] = $tableDefinition['transOrigDiffSourceField'];
537
            }
538
        }
539
        if (!empty($tableDefinition['sortby'])) {
540
            $prioritizedFieldNames[] = $tableDefinition['sortby'];
541
        }
542
        if (!empty($tableDefinition['descriptionColumn'])) {
543
            $prioritizedFieldNames[] = $tableDefinition['descriptionColumn'];
544
        }
545
        if (!empty($tableDefinition['editlock'])) {
546
            $prioritizedFieldNames[] = $tableDefinition['editlock'];
547
        }
548
        if (!empty($tableDefinition['origUid'])) {
549
            $prioritizedFieldNames[] = $tableDefinition['origUid'];
550
        }
551
        if (!empty($tableDefinition['versioningWS'])) {
552
            $prioritizedFieldNames[] = 't3ver_wsid';
553
            $prioritizedFieldNames[] = 't3ver_oid';
554
            $prioritizedFieldNames[] = 't3ver_state';
555
            $prioritizedFieldNames[] = 't3ver_stage';
556
            $prioritizedFieldNames[] = 't3ver_move_id';
557
            $prioritizedFieldNames[] = 't3ver_count';
558
            $prioritizedFieldNames[] = 't3ver_tstamp';
559
        }
560
561
        return $prioritizedFieldNames;
562
    }
563
564
    /**
565
     * True if table with given table name is defined within incoming $tables array
566
     *
567
     * @param Table[] $tables
568
     * @param string $tableName
569
     * @return bool
570
     */
571
    protected function isTableDefined(array $tables, string $tableName): bool
572
    {
573
        foreach ($tables as $table) {
574
            if ($table->getName() === $tableName) {
575
                return true;
576
            }
577
        }
578
        return false;
579
    }
580
581
    /**
582
     * True if a column with a given name is defined within the incoming
583
     * array of Table's.
584
     *
585
     * @param Table[] $tables
586
     * @param string $tableName
587
     * @param string $fieldName
588
     * @return bool
589
     */
590
    protected function isColumnDefinedForTable(array $tables, string $tableName, string $fieldName): bool
591
    {
592
        foreach ($tables as $table) {
593
            if ($table->getName() !== $tableName) {
594
                continue;
595
            }
596
            $columns = $table->getColumns();
597
            foreach ($columns as $column) {
598
                if ($column->getName() === $fieldName) {
599
                    return true;
600
                }
601
            }
602
        }
603
        return false;
604
    }
605
606
    /**
607
     * True if an index with a given name is defined within the incoming
608
     * array of Table's.
609
     *
610
     * @param Table[] $tables
611
     * @param string $tableName
612
     * @param string $indexName
613
     * @return bool
614
     */
615
    protected function isIndexDefinedForTable(array $tables, string $tableName, string $indexName): bool
616
    {
617
        foreach ($tables as $table) {
618
            if ($table->getName() !== $tableName) {
619
                continue;
620
            }
621
            $indexes = $table->getIndexes();
622
            foreach ($indexes as $index) {
623
                if ($index->getName() === $indexName) {
624
                    return true;
625
                }
626
            }
627
        }
628
        return false;
629
    }
630
631
    /**
632
     * The incoming $tables array can contain Table objects for the same table
633
     * multiple times. This can happen if an extension has the main CREATE TABLE
634
     * statement in its ext_tables.sql and another extension adds or changes further
635
     * fields in an own CREATE TABLE statement.
636
     *
637
     * @todo It would be better if the incoming $tables structure would be cleaned
638
     * @todo to contain a table only once before this class is entered.
639
     *
640
     * @param Table[] $tables
641
     * @param string $tableName
642
     * @return int
643
     * @throws \RuntimeException
644
     */
645
    protected function getTableFirstPosition(array $tables, string $tableName): int
646
    {
647
        foreach ($tables as $position => $table) {
648
            if ($table->getName() === $tableName) {
649
                return (int)$position;
650
            }
651
        }
652
        throw new \RuntimeException('Table ' . $tableName . ' not found in schema list', 1527854474);
653
    }
654
655
    /**
656
     * @param string $identifier
657
     * @return string
658
     */
659
    protected function quote(string $identifier): string
660
    {
661
        return '`' . $identifier . '`';
662
    }
663
}
664