Completed
Push — master ( 2b8513...e4b18a )
by Sergei
18s queued 13s
created

lib/Doctrine/DBAL/Schema/Table.php (1 issue)

Labels
Severity
1
<?php
2
3
namespace Doctrine\DBAL\Schema;
4
5
use Doctrine\DBAL\DBALException;
6
use Doctrine\DBAL\Schema\Visitor\Visitor;
7
use Doctrine\DBAL\Types\Type;
8
use const ARRAY_FILTER_USE_KEY;
9
use function array_filter;
10
use function array_merge;
11
use function in_array;
12
use function is_numeric;
13
use function is_string;
14
use function preg_match;
15
use function strlen;
16
use function strtolower;
17
18
/**
19
 * Object Representation of a table.
20
 */
21
class Table extends AbstractAsset
22
{
23
    /** @var string */
24
    protected $_name = null;
25
26
    /** @var Column[] */
27
    protected $_columns = [];
28
29
    /** @var Index[] */
30
    private $implicitIndexes = [];
31
32
    /** @var Index[] */
33
    protected $_indexes = [];
34
35
    /** @var string */
36
    protected $_primaryKeyName = false;
37
38
    /** @var ForeignKeyConstraint[] */
39
    protected $_fkConstraints = [];
40
41
    /** @var mixed[] */
42
    protected $_options = [];
43
44
    /** @var SchemaConfig|null */
45
    protected $_schemaConfig = null;
46
47
    /**
48
     * @param string                 $tableName
49
     * @param Column[]               $columns
50
     * @param Index[]                $indexes
51
     * @param ForeignKeyConstraint[] $fkConstraints
52
     * @param int                    $idGeneratorType
53
     * @param mixed[]                $options
54
     *
55
     * @throws DBALException
56
     */
57 24221
    public function __construct($tableName, array $columns = [], array $indexes = [], array $fkConstraints = [], $idGeneratorType = 0, array $options = [])
58
    {
59 24221
        if (strlen($tableName) === 0) {
60 27
            throw DBALException::invalidTableName($tableName);
61
        }
62
63 24194
        $this->_setName($tableName);
64
65 24194
        foreach ($columns as $column) {
66 2282
            $this->_addColumn($column);
67
        }
68
69 24167
        foreach ($indexes as $idx) {
70 798
            $this->_addIndex($idx);
71
        }
72
73 24113
        foreach ($fkConstraints as $constraint) {
74 312
            $this->_addForeignKeyConstraint($constraint);
75
        }
76
77 24113
        $this->_options = $options;
78 24113
    }
79
80
    /**
81
     * @return void
82
     */
83 1819
    public function setSchemaConfig(SchemaConfig $schemaConfig)
84
    {
85 1819
        $this->_schemaConfig = $schemaConfig;
86 1819
    }
87
88
    /**
89
     * @return int
90
     */
91 4554
    protected function _getMaxIdentifierLength()
92
    {
93 4554
        if ($this->_schemaConfig instanceof SchemaConfig) {
94 279
            return $this->_schemaConfig->getMaxIdentifierLength();
95
        }
96
97 4327
        return 63;
98
    }
99
100
    /**
101
     * Sets the Primary Key.
102
     *
103
     * @param mixed[][]   $columns
104
     * @param string|bool $indexName
105
     *
106
     * @return self
107
     */
108 9863
    public function setPrimaryKey(array $columns, $indexName = false)
109
    {
110 9863
        $this->_addIndex($this->_createIndex($columns, $indexName ?: 'primary', true, true));
111
112 9863
        foreach ($columns as $columnName) {
113 9863
            $column = $this->getColumn($columnName);
0 ignored issues
show
$columnName of type array<mixed,mixed> is incompatible with the type string expected by parameter $columnName of Doctrine\DBAL\Schema\Table::getColumn(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

113
            $column = $this->getColumn(/** @scrutinizer ignore-type */ $columnName);
Loading history...
114 9863
            $column->setNotnull(true);
115
        }
116
117 9863
        return $this;
118
    }
119
120
    /**
121
     * @param mixed[][]   $columnNames
122
     * @param string|null $indexName
123
     * @param string[]    $flags
124
     * @param mixed[]     $options
125
     *
126
     * @return self
127
     */
128 2967
    public function addIndex(array $columnNames, $indexName = null, array $flags = [], array $options = [])
129
    {
130 2967
        if ($indexName === null) {
131 779
            $indexName = $this->_generateIdentifierName(
132 779
                array_merge([$this->getName()], $columnNames),
133 779
                'idx',
134 779
                $this->_getMaxIdentifierLength()
135
            );
136
        }
137
138 2967
        return $this->_addIndex($this->_createIndex($columnNames, $indexName, false, false, $flags, $options));
139
    }
140
141
    /**
142
     * Drops the primary key from this table.
143
     *
144
     * @return void
145
     */
146 514
    public function dropPrimaryKey()
147
    {
148 514
        $this->dropIndex($this->_primaryKeyName);
149 514
        $this->_primaryKeyName = false;
150 514
    }
151
152
    /**
153
     * Drops an index from this table.
154
     *
155
     * @param string $indexName The index name.
156
     *
157
     * @return void
158
     *
159
     * @throws SchemaException If the index does not exist.
160
     */
161 879
    public function dropIndex($indexName)
162
    {
163 879
        $indexName = $this->normalizeIdentifier($indexName);
164 879
        if (! $this->hasIndex($indexName)) {
165
            throw SchemaException::indexDoesNotExist($indexName, $this->_name);
166
        }
167 879
        unset($this->_indexes[$indexName]);
168 879
    }
169
170
    /**
171
     * @param mixed[][]   $columnNames
172
     * @param string|null $indexName
173
     * @param mixed[]     $options
174
     *
175
     * @return self
176
     */
177 884
    public function addUniqueIndex(array $columnNames, $indexName = null, array $options = [])
178
    {
179 884
        if ($indexName === null) {
180 659
            $indexName = $this->_generateIdentifierName(
181 659
                array_merge([$this->getName()], $columnNames),
182 659
                'uniq',
183 659
                $this->_getMaxIdentifierLength()
184
            );
185
        }
186
187 884
        return $this->_addIndex($this->_createIndex($columnNames, $indexName, true, false, [], $options));
188
    }
189
190
    /**
191
     * Renames an index.
192
     *
193
     * @param string      $oldIndexName The name of the index to rename from.
194
     * @param string|null $newIndexName The name of the index to rename to.
195
     *                                  If null is given, the index name will be auto-generated.
196
     *
197
     * @return self This table instance.
198
     *
199
     * @throws SchemaException If no index exists for the given current name
200
     *                         or if an index with the given new name already exists on this table.
201
     */
202 377
    public function renameIndex($oldIndexName, $newIndexName = null)
203
    {
204 377
        $oldIndexName           = $this->normalizeIdentifier($oldIndexName);
205 377
        $normalizedNewIndexName = $this->normalizeIdentifier($newIndexName);
206
207 377
        if ($oldIndexName === $normalizedNewIndexName) {
208 243
            return $this;
209
        }
210
211 377
        if (! $this->hasIndex($oldIndexName)) {
212 27
            throw SchemaException::indexDoesNotExist($oldIndexName, $this->_name);
213
        }
214
215 350
        if ($this->hasIndex($normalizedNewIndexName)) {
216 27
            throw SchemaException::indexAlreadyExists($normalizedNewIndexName, $this->_name);
217
        }
218
219 323
        $oldIndex = $this->_indexes[$oldIndexName];
220
221 323
        if ($oldIndex->isPrimary()) {
222 27
            $this->dropPrimaryKey();
223
224 27
            return $this->setPrimaryKey($oldIndex->getColumns(), $newIndexName);
225
        }
226
227 323
        unset($this->_indexes[$oldIndexName]);
228
229 323
        if ($oldIndex->isUnique()) {
230 54
            return $this->addUniqueIndex($oldIndex->getColumns(), $newIndexName, $oldIndex->getOptions());
231
        }
232
233 296
        return $this->addIndex($oldIndex->getColumns(), $newIndexName, $oldIndex->getFlags(), $oldIndex->getOptions());
234
    }
235
236
    /**
237
     * Checks if an index begins in the order of the given columns.
238
     *
239
     * @param mixed[][] $columnsNames
240
     *
241
     * @return bool
242
     */
243 53
    public function columnsAreIndexed(array $columnsNames)
244
    {
245 53
        foreach ($this->getIndexes() as $index) {
246
            /** @var $index Index */
247 53
            if ($index->spansColumns($columnsNames)) {
248 53
                return true;
249
            }
250
        }
251
252
        return false;
253
    }
254
255
    /**
256
     * @param mixed[][] $columnNames
257
     * @param string    $indexName
258
     * @param bool      $isUnique
259
     * @param bool      $isPrimary
260
     * @param string[]  $flags
261
     * @param mixed[]   $options
262
     *
263
     * @return Index
264
     *
265
     * @throws SchemaException
266
     */
267 13914
    private function _createIndex(array $columnNames, $indexName, $isUnique, $isPrimary, array $flags = [], array $options = [])
268
    {
269 13914
        if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) {
270 27
            throw SchemaException::indexNameInvalid($indexName);
271
        }
272
273 13887
        foreach ($columnNames as $columnName => $indexColOptions) {
274 13860
            if (is_numeric($columnName) && is_string($indexColOptions)) {
275 13860
                $columnName = $indexColOptions;
276
            }
277
278 13860
            if (! $this->hasColumn($columnName)) {
279 13860
                throw SchemaException::columnDoesNotExist($columnName, $this->_name);
280
            }
281
        }
282
283 13860
        return new Index($indexName, $columnNames, $isUnique, $isPrimary, $flags, $options);
284
    }
285
286
    /**
287
     * @param string  $columnName
288
     * @param string  $typeName
289
     * @param mixed[] $options
290
     *
291
     * @return Column
292
     */
293 19844
    public function addColumn($columnName, $typeName, array $options = [])
294
    {
295 19844
        $column = new Column($columnName, Type::getType($typeName), $options);
296
297 19844
        $this->_addColumn($column);
298
299 19844
        return $column;
300
    }
301
302
    /**
303
     * Renames a Column.
304
     *
305
     * @deprecated
306
     *
307
     * @param string $oldColumnName
308
     * @param string $newColumnName
309
     *
310
     * @throws DBALException
311
     */
312
    public function renameColumn($oldColumnName, $newColumnName)
313
    {
314
        throw new DBALException('Table#renameColumn() was removed, because it drops and recreates ' .
315
            'the column instead. There is no fix available, because a schema diff cannot reliably detect if a ' .
316
            'column was renamed or one column was created and another one dropped.');
317
    }
318
319
    /**
320
     * Change Column Details.
321
     *
322
     * @param string  $columnName
323
     * @param mixed[] $options
324
     *
325
     * @return self
326
     */
327 326
    public function changeColumn($columnName, array $options)
328
    {
329 326
        $column = $this->getColumn($columnName);
330 326
        $column->setOptions($options);
331
332 326
        return $this;
333
    }
334
335
    /**
336
     * Drops a Column from the Table.
337
     *
338
     * @param string $columnName
339
     *
340
     * @return self
341
     */
342 243
    public function dropColumn($columnName)
343
    {
344 243
        $columnName = $this->normalizeIdentifier($columnName);
345 243
        unset($this->_columns[$columnName]);
346
347 243
        return $this;
348
    }
349
350
    /**
351
     * Adds a foreign key constraint.
352
     *
353
     * Name is inferred from the local columns.
354
     *
355
     * @param Table|string $foreignTable       Table schema instance or table name
356
     * @param string[]     $localColumnNames
357
     * @param string[]     $foreignColumnNames
358
     * @param mixed[]      $options
359
     * @param string|null  $constraintName
360
     *
361
     * @return self
362
     */
363 3036
    public function addForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = [], $constraintName = null)
364
    {
365 3036
        $constraintName = $constraintName ?: $this->_generateIdentifierName(array_merge((array) $this->getName(), $localColumnNames), 'fk', $this->_getMaxIdentifierLength());
366
367 3036
        return $this->addNamedForeignKeyConstraint($constraintName, $foreignTable, $localColumnNames, $foreignColumnNames, $options);
368
    }
369
370
    /**
371
     * Adds a foreign key constraint.
372
     *
373
     * Name is to be generated by the database itself.
374
     *
375
     * @deprecated Use {@link addForeignKeyConstraint}
376
     *
377
     * @param Table|string $foreignTable       Table schema instance or table name
378
     * @param string[]     $localColumnNames
379
     * @param string[]     $foreignColumnNames
380
     * @param mixed[]      $options
381
     *
382
     * @return self
383
     */
384 169
    public function addUnnamedForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = [])
385
    {
386 169
        return $this->addForeignKeyConstraint($foreignTable, $localColumnNames, $foreignColumnNames, $options);
387
    }
388
389
    /**
390
     * Adds a foreign key constraint with a given name.
391
     *
392
     * @deprecated Use {@link addForeignKeyConstraint}
393
     *
394
     * @param string       $name
395
     * @param Table|string $foreignTable       Table schema instance or table name
396
     * @param string[]     $localColumnNames
397
     * @param string[]     $foreignColumnNames
398
     * @param mixed[]      $options
399
     *
400
     * @return self
401
     *
402
     * @throws SchemaException
403
     */
404 3063
    public function addNamedForeignKeyConstraint($name, $foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = [])
405
    {
406 3063
        if ($foreignTable instanceof Table) {
407 1564
            foreach ($foreignColumnNames as $columnName) {
408 1564
                if (! $foreignTable->hasColumn($columnName)) {
409 1564
                    throw SchemaException::columnDoesNotExist($columnName, $foreignTable->getName());
410
                }
411
            }
412
        }
413
414 3036
        foreach ($localColumnNames as $columnName) {
415 3036
            if (! $this->hasColumn($columnName)) {
416 3036
                throw SchemaException::columnDoesNotExist($columnName, $this->_name);
417
            }
418
        }
419
420 3009
        $constraint = new ForeignKeyConstraint(
421 3009
            $localColumnNames,
422 3009
            $foreignTable,
423 3009
            $foreignColumnNames,
424 3009
            $name,
425 3009
            $options
426
        );
427 3009
        $this->_addForeignKeyConstraint($constraint);
428
429 3009
        return $this;
430
    }
431
432
    /**
433
     * @param string $name
434
     * @param string $value
435
     *
436
     * @return self
437
     */
438 1300
    public function addOption($name, $value)
439
    {
440 1300
        $this->_options[$name] = $value;
441
442 1300
        return $this;
443
    }
444
445
    /**
446
     * @return void
447
     *
448
     * @throws SchemaException
449
     */
450 20873
    protected function _addColumn(Column $column)
451
    {
452 20873
        $columnName = $column->getName();
453 20873
        $columnName = $this->normalizeIdentifier($columnName);
454
455 20873
        if (isset($this->_columns[$columnName])) {
456 27
            throw SchemaException::columnAlreadyExists($this->getName(), $columnName);
457
        }
458
459 20873
        $this->_columns[$columnName] = $column;
460 20873
    }
461
462
    /**
463
     * Adds an index to the table.
464
     *
465
     * @return self
466
     *
467
     * @throws SchemaException
468
     */
469 14070
    protected function _addIndex(Index $indexCandidate)
470
    {
471 14070
        $indexName               = $indexCandidate->getName();
472 14070
        $indexName               = $this->normalizeIdentifier($indexName);
473 14070
        $replacedImplicitIndexes = [];
474
475 14070
        foreach ($this->implicitIndexes as $name => $implicitIndex) {
476 894
            if (! $implicitIndex->isFullfilledBy($indexCandidate) || ! isset($this->_indexes[$name])) {
477 786
                continue;
478
            }
479
480 108
            $replacedImplicitIndexes[] = $name;
481
        }
482
483 14070
        if ((isset($this->_indexes[$indexName]) && ! in_array($indexName, $replacedImplicitIndexes, true)) ||
484 14070
            ($this->_primaryKeyName !== false && $indexCandidate->isPrimary())
485
        ) {
486 54
            throw SchemaException::indexAlreadyExists($indexName, $this->_name);
487
        }
488
489 14070
        foreach ($replacedImplicitIndexes as $name) {
490 108
            unset($this->_indexes[$name], $this->implicitIndexes[$name]);
491
        }
492
493 14070
        if ($indexCandidate->isPrimary()) {
494 9945
            $this->_primaryKeyName = $indexName;
495
        }
496
497 14070
        $this->_indexes[$indexName] = $indexCandidate;
498
499 14070
        return $this;
500
    }
501
502
    /**
503
     * @return void
504
     */
505 3139
    protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint)
506
    {
507 3139
        $constraint->setLocalTable($this);
508
509 3139
        if (strlen($constraint->getName())) {
510 3111
            $name = $constraint->getName();
511
        } else {
512 28
            $name = $this->_generateIdentifierName(
513 28
                array_merge((array) $this->getName(), $constraint->getLocalColumns()),
514 28
                'fk',
515 28
                $this->_getMaxIdentifierLength()
516
            );
517
        }
518 3139
        $name = $this->normalizeIdentifier($name);
519
520 3139
        $this->_fkConstraints[$name] = $constraint;
521
522
        // add an explicit index on the foreign key columns. If there is already an index that fulfils this requirements drop the request.
523
        // In the case of __construct calling this method during hydration from schema-details all the explicitly added indexes
524
        // lead to duplicates. This creates computation overhead in this case, however no duplicate indexes are ever added (based on columns).
525 3139
        $indexName      = $this->_generateIdentifierName(
526 3139
            array_merge([$this->getName()], $constraint->getColumns()),
527 3139
            'idx',
528 3139
            $this->_getMaxIdentifierLength()
529
        );
530 3139
        $indexCandidate = $this->_createIndex($constraint->getColumns(), $indexName, false, false);
531
532 3139
        foreach ($this->_indexes as $existingIndex) {
533 2428
            if ($indexCandidate->isFullfilledBy($existingIndex)) {
534 2428
                return;
535
            }
536
        }
537
538 2346
        $this->_addIndex($indexCandidate);
539 2346
        $this->implicitIndexes[$this->normalizeIdentifier($indexName)] = $indexCandidate;
540 2346
    }
541
542
    /**
543
     * Returns whether this table has a foreign key constraint with the given name.
544
     *
545
     * @param string $constraintName
546
     *
547
     * @return bool
548
     */
549 298
    public function hasForeignKey($constraintName)
550
    {
551 298
        $constraintName = $this->normalizeIdentifier($constraintName);
552
553 298
        return isset($this->_fkConstraints[$constraintName]);
554
    }
555
556
    /**
557
     * Returns the foreign key constraint with the given name.
558
     *
559
     * @param string $constraintName The constraint name.
560
     *
561
     * @return ForeignKeyConstraint
562
     *
563
     * @throws SchemaException If the foreign key does not exist.
564
     */
565 218
    public function getForeignKey($constraintName)
566
    {
567 218
        $constraintName = $this->normalizeIdentifier($constraintName);
568 218
        if (! $this->hasForeignKey($constraintName)) {
569
            throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name);
570
        }
571
572 218
        return $this->_fkConstraints[$constraintName];
573
    }
574
575
    /**
576
     * Removes the foreign key constraint with the given name.
577
     *
578
     * @param string $constraintName The constraint name.
579
     *
580
     * @return void
581
     *
582
     * @throws SchemaException
583
     */
584 270
    public function removeForeignKey($constraintName)
585
    {
586 270
        $constraintName = $this->normalizeIdentifier($constraintName);
587 270
        if (! $this->hasForeignKey($constraintName)) {
588
            throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name);
589
        }
590
591 270
        unset($this->_fkConstraints[$constraintName]);
592 270
    }
593
594
    /**
595
     * Returns ordered list of columns (primary keys are first, then foreign keys, then the rest)
596
     *
597
     * @return Column[]
598
     */
599 15124
    public function getColumns()
600
    {
601 15124
        $primaryKeyColumns = [];
602 15124
        if ($this->hasPrimaryKey()) {
603 6684
            $primaryKeyColumns = $this->filterColumns($this->getPrimaryKey()->getColumns());
604
        }
605
606 15124
        return array_merge($primaryKeyColumns, $this->getForeignKeyColumns(), $this->_columns);
607
    }
608
609
    /**
610
     * Returns foreign key columns
611
     *
612
     * @return Column[]
613
     */
614 15124
    private function getForeignKeyColumns()
615
    {
616 15124
        $foreignKeyColumns = [];
617 15124
        foreach ($this->getForeignKeys() as $foreignKey) {
618 1478
            $foreignKeyColumns = array_merge($foreignKeyColumns, $foreignKey->getColumns());
619
        }
620 15124
        return $this->filterColumns($foreignKeyColumns);
621
    }
622
623
    /**
624
     * Returns only columns that have specified names
625
     *
626
     * @param string[] $columnNames
627
     *
628
     * @return Column[]
629
     */
630 15124
    private function filterColumns(array $columnNames)
631
    {
632
        return array_filter($this->_columns, static function ($columnName) use ($columnNames) {
633 14422
            return in_array($columnName, $columnNames, true);
634 15124
        }, ARRAY_FILTER_USE_KEY);
635
    }
636
637
    /**
638
     * Returns whether this table has a Column with the given name.
639
     *
640
     * @param string $columnName The column name.
641
     *
642
     * @return bool
643
     */
644 16267
    public function hasColumn($columnName)
645
    {
646 16267
        $columnName = $this->normalizeIdentifier($columnName);
647
648 16267
        return isset($this->_columns[$columnName]);
649
    }
650
651
    /**
652
     * Returns the Column with the given name.
653
     *
654
     * @param string $columnName The column name.
655
     *
656
     * @return Column
657
     *
658
     * @throws SchemaException If the column does not exist.
659
     */
660 12628
    public function getColumn($columnName)
661
    {
662 12628
        $columnName = $this->normalizeIdentifier($columnName);
663 12628
        if (! $this->hasColumn($columnName)) {
664 27
            throw SchemaException::columnDoesNotExist($columnName, $this->_name);
665
        }
666
667 12601
        return $this->_columns[$columnName];
668
    }
669
670
    /**
671
     * Returns the primary key.
672
     *
673
     * @return Index|null The primary key, or null if this Table has no primary key.
674
     */
675 6819
    public function getPrimaryKey()
676
    {
677 6819
        if (! $this->hasPrimaryKey()) {
678
            return null;
679
        }
680
681 6819
        return $this->getIndex($this->_primaryKeyName);
682
    }
683
684
    /**
685
     * Returns the primary key columns.
686
     *
687
     * @return string[]
688
     *
689
     * @throws DBALException
690
     */
691 379
    public function getPrimaryKeyColumns()
692
    {
693 379
        if (! $this->hasPrimaryKey()) {
694
            throw new DBALException('Table ' . $this->getName() . ' has no primary key.');
695
        }
696 379
        return $this->getPrimaryKey()->getColumns();
697
    }
698
699
    /**
700
     * Returns whether this table has a primary key.
701
     *
702
     * @return bool
703
     */
704 15340
    public function hasPrimaryKey()
705
    {
706 15340
        return $this->_primaryKeyName && $this->hasIndex($this->_primaryKeyName);
707
    }
708
709
    /**
710
     * Returns whether this table has an Index with the given name.
711
     *
712
     * @param string $indexName The index name.
713
     *
714
     * @return bool
715
     */
716 8258
    public function hasIndex($indexName)
717
    {
718 8258
        $indexName = $this->normalizeIdentifier($indexName);
719
720 8258
        return isset($this->_indexes[$indexName]);
721
    }
722
723
    /**
724
     * Returns the Index with the given name.
725
     *
726
     * @param string $indexName The index name.
727
     *
728
     * @return Index
729
     *
730
     * @throws SchemaException If the index does not exist.
731
     */
732 7664
    public function getIndex($indexName)
733
    {
734 7664
        $indexName = $this->normalizeIdentifier($indexName);
735 7664
        if (! $this->hasIndex($indexName)) {
736 27
            throw SchemaException::indexDoesNotExist($indexName, $this->_name);
737
        }
738
739 7637
        return $this->_indexes[$indexName];
740
    }
741
742
    /**
743
     * @return Index[]
744
     */
745 14368
    public function getIndexes()
746
    {
747 14368
        return $this->_indexes;
748
    }
749
750
    /**
751
     * Returns the foreign key constraints.
752
     *
753
     * @return ForeignKeyConstraint[]
754
     */
755 15610
    public function getForeignKeys()
756
    {
757 15610
        return $this->_fkConstraints;
758
    }
759
760
    /**
761
     * @param string $name
762
     *
763
     * @return bool
764
     */
765 2261
    public function hasOption($name)
766
    {
767 2261
        return isset($this->_options[$name]);
768
    }
769
770
    /**
771
     * @param string $name
772
     *
773
     * @return mixed
774
     */
775 218
    public function getOption($name)
776
    {
777 218
        return $this->_options[$name];
778
    }
779
780
    /**
781
     * @return mixed[]
782
     */
783 11435
    public function getOptions()
784
    {
785 11435
        return $this->_options;
786
    }
787
788
    /**
789
     * @return void
790
     */
791 480
    public function visit(Visitor $visitor)
792
    {
793 480
        $visitor->acceptTable($this);
794
795 480
        foreach ($this->getColumns() as $column) {
796 399
            $visitor->acceptColumn($this, $column);
797
        }
798
799 480
        foreach ($this->getIndexes() as $index) {
800 291
            $visitor->acceptIndex($this, $index);
801
        }
802
803 480
        foreach ($this->getForeignKeys() as $constraint) {
804 108
            $visitor->acceptForeignKey($this, $constraint);
805
        }
806 480
    }
807
808
    /**
809
     * Clone of a Table triggers a deep clone of all affected assets.
810
     *
811
     * @return void
812
     */
813 1338
    public function __clone()
814
    {
815 1338
        foreach ($this->_columns as $k => $column) {
816 1311
            $this->_columns[$k] = clone $column;
817
        }
818 1338
        foreach ($this->_indexes as $k => $index) {
819 990
            $this->_indexes[$k] = clone $index;
820
        }
821 1338
        foreach ($this->_fkConstraints as $k => $fk) {
822 215
            $this->_fkConstraints[$k] = clone $fk;
823 215
            $this->_fkConstraints[$k]->setLocalTable($this);
824
        }
825 1338
    }
826
827
    /**
828
     * Normalizes a given identifier.
829
     *
830
     * Trims quotes and lowercases the given identifier.
831
     *
832
     * @param string $identifier The identifier to normalize.
833
     *
834
     * @return string The normalized identifier.
835
     */
836 20981
    private function normalizeIdentifier($identifier)
837
    {
838 20981
        return $this->trimQuotes(strtolower($identifier));
839
    }
840
}
841