Completed
Push — master ( 9b88bf...94cec7 )
by Marco
31s queued 15s
created

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

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 preg_match;
13
use function strlen;
14
use function strtolower;
15
16
/**
17
 * Object Representation of a table.
18
 */
19
class Table extends AbstractAsset
20
{
21
    /** @var string */
22
    protected $_name = null;
23
24
    /** @var Column[] */
25
    protected $_columns = [];
26
27
    /** @var Index[] */
28
    private $implicitIndexes = [];
29
30
    /** @var Index[] */
31
    protected $_indexes = [];
32
33
    /** @var string */
34
    protected $_primaryKeyName = false;
35
36
    /** @var ForeignKeyConstraint[] */
37
    protected $_fkConstraints = [];
38
39
    /** @var mixed[] */
40
    protected $_options = [];
41
42
    /** @var SchemaConfig|null */
43
    protected $_schemaConfig = null;
44
45
    /**
46
     * @param string                 $tableName
47
     * @param Column[]               $columns
48
     * @param Index[]                $indexes
49
     * @param ForeignKeyConstraint[] $fkConstraints
50
     * @param int                    $idGeneratorType
51
     * @param mixed[]                $options
52
     *
53
     * @throws DBALException
54
     */
55 24291
    public function __construct($tableName, array $columns = [], array $indexes = [], array $fkConstraints = [], $idGeneratorType = 0, array $options = [])
0 ignored issues
show
The parameter $idGeneratorType is not used and could be removed. ( Ignorable by Annotation )

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

55
    public function __construct($tableName, array $columns = [], array $indexes = [], array $fkConstraints = [], /** @scrutinizer ignore-unused */ $idGeneratorType = 0, array $options = [])

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

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