Completed
Push — master ( 5dd66e...5b5c2c )
by Marco
114:19 queued 111:15
created

lib/Doctrine/DBAL/Schema/Table.php (2 issues)

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 Column[] */
22
    protected $_columns = [];
23
24
    /** @var Index[] */
25
    private $implicitIndexes = [];
26
27
    /** @var Index[] */
28
    protected $_indexes = [];
29
30
    /** @var string */
31
    protected $_primaryKeyName = false;
32
33
    /** @var ForeignKeyConstraint[] */
34
    protected $_fkConstraints = [];
35
36
    /** @var mixed[] */
37
    protected $_options = [];
38
39
    /** @var SchemaConfig|null */
40
    protected $_schemaConfig = null;
41
42
    /**
43
     * @param string                 $tableName
44
     * @param Column[]               $columns
45
     * @param Index[]                $indexes
46
     * @param ForeignKeyConstraint[] $fkConstraints
47
     * @param int                    $idGeneratorType
48
     * @param mixed[]                $options
49
     *
50
     * @throws DBALException
51
     */
52 24472
    public function __construct($tableName, array $columns = [], array $indexes = [], array $fkConstraints = [], $idGeneratorType = 0, array $options = [])
53
    {
54 24472
        if (strlen($tableName) === 0) {
55 1627
            throw DBALException::invalidTableName($tableName);
56
        }
57
58 24470
        $this->_setName($tableName);
59
60 24470
        foreach ($columns as $column) {
61 21988
            $this->_addColumn($column);
62
        }
63
64 24468
        foreach ($indexes as $idx) {
65 21857
            $this->_addIndex($idx);
66
        }
67
68 24464
        foreach ($fkConstraints as $constraint) {
69 21064
            $this->_addForeignKeyConstraint($constraint);
70
        }
71
72 24464
        $this->_options = $options;
73 24464
    }
74
75
    /**
76
     * @return void
77
     */
78 22485
    public function setSchemaConfig(SchemaConfig $schemaConfig)
79
    {
80 22485
        $this->_schemaConfig = $schemaConfig;
81 22485
    }
82
83
    /**
84
     * @return int
85
     */
86 22746
    protected function _getMaxIdentifierLength()
87
    {
88 22746
        if ($this->_schemaConfig instanceof SchemaConfig) {
89 22281
            return $this->_schemaConfig->getMaxIdentifierLength();
90
        }
91
92 22685
        return 63;
93
    }
94
95
    /**
96
     * Sets the Primary Key.
97
     *
98
     * @param string[]     $columnNames
99
     * @param string|false $indexName
100
     *
101
     * @return self
102
     */
103 23434
    public function setPrimaryKey(array $columnNames, $indexName = false)
104
    {
105 23434
        $this->_addIndex($this->_createIndex($columnNames, $indexName ?: 'primary', true, true));
106
107 23434
        foreach ($columnNames as $columnName) {
108 23434
            $column = $this->getColumn($columnName);
109 23434
            $column->setNotnull(true);
110
        }
111
112 23434
        return $this;
113
    }
114
115
    /**
116
     * @param string[]    $columnNames
117
     * @param string|null $indexName
118
     * @param string[]    $flags
119
     * @param mixed[]     $options
120
     *
121
     * @return self
122
     */
123 21536
    public function addIndex(array $columnNames, $indexName = null, array $flags = [], array $options = [])
124
    {
125 21536
        if ($indexName === null) {
126 21019
            $indexName = $this->_generateIdentifierName(
127 21019
                array_merge([$this->getName()], $columnNames),
128 21019
                'idx',
129 21019
                $this->_getMaxIdentifierLength()
130
            );
131
        }
132
133 21536
        return $this->_addIndex($this->_createIndex($columnNames, $indexName, false, false, $flags, $options));
134
    }
135
136
    /**
137
     * Drops the primary key from this table.
138
     *
139
     * @return void
140
     */
141 20138
    public function dropPrimaryKey()
142
    {
143 20138
        $this->dropIndex($this->_primaryKeyName);
144 20138
        $this->_primaryKeyName = false;
0 ignored issues
show
Documentation Bug introduced by
The property $_primaryKeyName was declared of type string, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
145 20138
    }
146
147
    /**
148
     * Drops an index from this table.
149
     *
150
     * @param string $indexName The index name.
151
     *
152
     * @return void
153
     *
154
     * @throws SchemaException If the index does not exist.
155
     */
156 20175
    public function dropIndex($indexName)
157
    {
158 20175
        $indexName = $this->normalizeIdentifier($indexName);
159 20175
        if (! $this->hasIndex($indexName)) {
160
            throw SchemaException::indexDoesNotExist($indexName, $this->_name);
161
        }
162 20175
        unset($this->_indexes[$indexName]);
163 20175
    }
164
165
    /**
166
     * @param string[]    $columnNames
167
     * @param string|null $indexName
168
     * @param mixed[]     $options
169
     *
170
     * @return self
171
     */
172 22339
    public function addUniqueIndex(array $columnNames, $indexName = null, array $options = [])
173
    {
174 22339
        if ($indexName === null) {
175 21993
            $indexName = $this->_generateIdentifierName(
176 21993
                array_merge([$this->getName()], $columnNames),
177 21993
                'uniq',
178 21993
                $this->_getMaxIdentifierLength()
179
            );
180
        }
181
182 22339
        return $this->_addIndex($this->_createIndex($columnNames, $indexName, true, false, [], $options));
183
    }
184
185
    /**
186
     * Renames an index.
187
     *
188
     * @param string      $oldIndexName The name of the index to rename from.
189
     * @param string|null $newIndexName The name of the index to rename to.
190
     *                                  If null is given, the index name will be auto-generated.
191
     *
192
     * @return self This table instance.
193
     *
194
     * @throws SchemaException If no index exists for the given current name
195
     *                         or if an index with the given new name already exists on this table.
196
     */
197 19884
    public function renameIndex($oldIndexName, $newIndexName = null)
198
    {
199 19884
        $oldIndexName           = $this->normalizeIdentifier($oldIndexName);
200 19884
        $normalizedNewIndexName = $this->normalizeIdentifier($newIndexName);
201
202 19884
        if ($oldIndexName === $normalizedNewIndexName) {
203 468
            return $this;
204
        }
205
206 19884
        if (! $this->hasIndex($oldIndexName)) {
207 377
            throw SchemaException::indexDoesNotExist($oldIndexName, $this->_name);
208
        }
209
210 19882
        if ($this->hasIndex($normalizedNewIndexName)) {
211 352
            throw SchemaException::indexAlreadyExists($normalizedNewIndexName, $this->_name);
212
        }
213
214 19880
        $oldIndex = $this->_indexes[$oldIndexName];
215
216 19880
        if ($oldIndex->isPrimary()) {
217 452
            $this->dropPrimaryKey();
218
219 452
            return $this->setPrimaryKey($oldIndex->getColumns(), $newIndexName ?? false);
220
        }
221
222 19880
        unset($this->_indexes[$oldIndexName]);
223
224 19880
        if ($oldIndex->isUnique()) {
225 454
            return $this->addUniqueIndex($oldIndex->getColumns(), $newIndexName, $oldIndex->getOptions());
226
        }
227
228 19878
        return $this->addIndex($oldIndex->getColumns(), $newIndexName, $oldIndex->getFlags(), $oldIndex->getOptions());
229
    }
230
231
    /**
232
     * Checks if an index begins in the order of the given columns.
233
     *
234
     * @param string[] $columnNames
235
     *
236
     * @return bool
237
     */
238 20060
    public function columnsAreIndexed(array $columnNames)
239
    {
240 20060
        foreach ($this->getIndexes() as $index) {
241
            /** @var $index Index */
242 20060
            if ($index->spansColumns($columnNames)) {
243 20060
                return true;
244
            }
245
        }
246
247
        return false;
248
    }
249
250
    /**
251
     * @param string[] $columnNames
252
     * @param string   $indexName
253
     * @param bool     $isUnique
254
     * @param bool     $isPrimary
255
     * @param string[] $flags
256
     * @param mixed[]  $options
257
     *
258
     * @return Index
259
     *
260
     * @throws SchemaException
261
     */
262 23732
    private function _createIndex(array $columnNames, $indexName, $isUnique, $isPrimary, array $flags = [], array $options = [])
263
    {
264 23732
        if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) {
265 1152
            throw SchemaException::indexNameInvalid($indexName);
266
        }
267
268 23730
        foreach ($columnNames as $columnName) {
269 23728
            if (! $this->hasColumn($columnName)) {
270 2121
                throw SchemaException::columnDoesNotExist($columnName, $this->_name);
271
            }
272
        }
273
274 23728
        return new Index($indexName, $columnNames, $isUnique, $isPrimary, $flags, $options);
275
    }
276
277
    /**
278
     * @param string  $columnName
279
     * @param string  $typeName
280
     * @param mixed[] $options
281
     *
282
     * @return Column
283
     */
284 24152
    public function addColumn($columnName, $typeName, array $options = [])
285
    {
286 24152
        $column = new Column($columnName, Type::getType($typeName), $options);
287
288 24152
        $this->_addColumn($column);
289
290 24152
        return $column;
291
    }
292
293
    /**
294
     * Renames a Column.
295
     *
296
     * @deprecated
297
     *
298
     * @param string $oldColumnName
299
     * @param string $newColumnName
300
     *
301
     * @throws DBALException
302
     */
303
    public function renameColumn($oldColumnName, $newColumnName)
304
    {
305
        throw new DBALException('Table#renameColumn() was removed, because it drops and recreates ' .
306
            'the column instead. There is no fix available, because a schema diff cannot reliably detect if a ' .
307
            'column was renamed or one column was created and another one dropped.');
308
    }
309
310
    /**
311
     * Change Column Details.
312
     *
313
     * @param string  $columnName
314
     * @param mixed[] $options
315
     *
316
     * @return self
317
     */
318 20510
    public function changeColumn($columnName, array $options)
319
    {
320 20510
        $column = $this->getColumn($columnName);
321 20510
        $column->setOptions($options);
322
323 20510
        return $this;
324
    }
325
326
    /**
327
     * Drops a Column from the Table.
328
     *
329
     * @param string $columnName
330
     *
331
     * @return self
332
     */
333 1518
    public function dropColumn($columnName)
334
    {
335 1518
        $columnName = $this->normalizeIdentifier($columnName);
336 1518
        unset($this->_columns[$columnName]);
337
338 1518
        return $this;
339
    }
340
341
    /**
342
     * Adds a foreign key constraint.
343
     *
344
     * Name is inferred from the local columns.
345
     *
346
     * @param Table|string $foreignTable       Table schema instance or table name
347
     * @param string[]     $localColumnNames
348
     * @param string[]     $foreignColumnNames
349
     * @param mixed[]      $options
350
     * @param string|null  $constraintName
351
     *
352
     * @return self
353
     */
354 22510
    public function addForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = [], $constraintName = null)
355
    {
356 22510
        $constraintName = $constraintName ?: $this->_generateIdentifierName(array_merge((array) $this->getName(), $localColumnNames), 'fk', $this->_getMaxIdentifierLength());
357
358 22510
        return $this->addNamedForeignKeyConstraint($constraintName, $foreignTable, $localColumnNames, $foreignColumnNames, $options);
1 ignored issue
show
Deprecated Code introduced by
The function Doctrine\DBAL\Schema\Tab...dForeignKeyConstraint() has been deprecated: Use {@link addForeignKeyConstraint} ( Ignorable by Annotation )

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

358
        return /** @scrutinizer ignore-deprecated */ $this->addNamedForeignKeyConstraint($constraintName, $foreignTable, $localColumnNames, $foreignColumnNames, $options);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
359
    }
360
361
    /**
362
     * Adds a foreign key constraint.
363
     *
364
     * Name is to be generated by the database itself.
365
     *
366
     * @deprecated Use {@link addForeignKeyConstraint}
367
     *
368
     * @param Table|string $foreignTable       Table schema instance or table name
369
     * @param string[]     $localColumnNames
370
     * @param string[]     $foreignColumnNames
371
     * @param mixed[]      $options
372
     *
373
     * @return self
374
     */
375 16018
    public function addUnnamedForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = [])
376
    {
377 16018
        return $this->addForeignKeyConstraint($foreignTable, $localColumnNames, $foreignColumnNames, $options);
378
    }
379
380
    /**
381
     * Adds a foreign key constraint with a given name.
382
     *
383
     * @deprecated Use {@link addForeignKeyConstraint}
384
     *
385
     * @param string       $name
386
     * @param Table|string $foreignTable       Table schema instance or table name
387
     * @param string[]     $localColumnNames
388
     * @param string[]     $foreignColumnNames
389
     * @param mixed[]      $options
390
     *
391
     * @return self
392
     *
393
     * @throws SchemaException
394
     */
395 22512
    public function addNamedForeignKeyConstraint($name, $foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = [])
396
    {
397 22512
        if ($foreignTable instanceof Table) {
398 22033
            foreach ($foreignColumnNames as $columnName) {
399 22033
                if (! $foreignTable->hasColumn($columnName)) {
400 1166
                    throw SchemaException::columnDoesNotExist($columnName, $foreignTable->getName());
401
                }
402
            }
403
        }
404
405 22510
        foreach ($localColumnNames as $columnName) {
406 22510
            if (! $this->hasColumn($columnName)) {
407 1301
                throw SchemaException::columnDoesNotExist($columnName, $this->_name);
408
            }
409
        }
410
411 22508
        $constraint = new ForeignKeyConstraint(
412 21677
            $localColumnNames,
413 224
            $foreignTable,
414 224
            $foreignColumnNames,
415 224
            $name,
416 1055
            $options
417
        );
418 22508
        $this->_addForeignKeyConstraint($constraint);
419
420 22508
        return $this;
421
    }
422
423
    /**
424
     * @param string $name
425
     * @param mixed  $value
426
     *
427
     * @return self
428
     */
429 20307
    public function addOption($name, $value)
430
    {
431 20307
        $this->_options[$name] = $value;
432
433 20307
        return $this;
434
    }
435
436
    /**
437
     * @return void
438
     *
439
     * @throws SchemaException
440
     */
441 24224
    protected function _addColumn(Column $column)
442
    {
443 24224
        $columnName = $column->getName();
444 24224
        $columnName = $this->normalizeIdentifier($columnName);
445
446 24224
        if (isset($this->_columns[$columnName])) {
447 1452
            throw SchemaException::columnAlreadyExists($this->getName(), $columnName);
448
        }
449
450 24224
        $this->_columns[$columnName] = $column;
451 24224
    }
452
453
    /**
454
     * Adds an index to the table.
455
     *
456
     * @return self
457
     *
458
     * @throws SchemaException
459
     */
460 23742
    protected function _addIndex(Index $indexCandidate)
461
    {
462 23742
        $indexName               = $indexCandidate->getName();
463 23742
        $indexName               = $this->normalizeIdentifier($indexName);
464 23742
        $replacedImplicitIndexes = [];
465
466 23742
        foreach ($this->implicitIndexes as $name => $implicitIndex) {
467 19038
            if (! $implicitIndex->isFullfilledBy($indexCandidate) || ! isset($this->_indexes[$name])) {
468 19030
                continue;
469
            }
470
471 758
            $replacedImplicitIndexes[] = $name;
472
        }
473
474 23742
        if ((isset($this->_indexes[$indexName]) && ! in_array($indexName, $replacedImplicitIndexes, true)) ||
475 23742
            ($this->_primaryKeyName !== false && $indexCandidate->isPrimary())
476
        ) {
477 1329
            throw SchemaException::indexAlreadyExists($indexName, $this->_name);
478
        }
479
480 23742
        foreach ($replacedImplicitIndexes as $name) {
481 758
            unset($this->_indexes[$name], $this->implicitIndexes[$name]);
482
        }
483
484 23742
        if ($indexCandidate->isPrimary()) {
485 23438
            $this->_primaryKeyName = $indexName;
486
        }
487
488 23742
        $this->_indexes[$indexName] = $indexCandidate;
489
490 23742
        return $this;
491
    }
492
493
    /**
494
     * @return void
495
     */
496 22597
    protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint)
497
    {
498 22597
        $constraint->setLocalTable($this);
499
500 22597
        if (strlen($constraint->getName())) {
501 22516
            $name = $constraint->getName();
502
        } else {
503 2049
            $name = $this->_generateIdentifierName(
504 2049
                array_merge((array) $this->getName(), $constraint->getLocalColumns()),
505 2049
                'fk',
506 2049
                $this->_getMaxIdentifierLength()
507
            );
508
        }
509 22597
        $name = $this->normalizeIdentifier($name);
510
511 22597
        $this->_fkConstraints[$name] = $constraint;
512
513
        // add an explicit index on the foreign key columns. If there is already an index that fulfils this requirements drop the request.
514
        // In the case of __construct calling this method during hydration from schema-details all the explicitly added indexes
515
        // lead to duplicates. This creates computation overhead in this case, however no duplicate indexes are ever added (based on columns).
516 22597
        $indexName      = $this->_generateIdentifierName(
517 22597
            array_merge([$this->getName()], $constraint->getColumns()),
518 22597
            'idx',
519 22597
            $this->_getMaxIdentifierLength()
520
        );
521 22597
        $indexCandidate = $this->_createIndex($constraint->getColumns(), $indexName, false, false);
522
523 22597
        foreach ($this->_indexes as $existingIndex) {
524 22545
            if ($indexCandidate->isFullfilledBy($existingIndex)) {
525 21143
                return;
526
            }
527
        }
528
529 22537
        $this->_addIndex($indexCandidate);
530 22537
        $this->implicitIndexes[$this->normalizeIdentifier($indexName)] = $indexCandidate;
531 22537
    }
532
533
    /**
534
     * Returns whether this table has a foreign key constraint with the given name.
535
     *
536
     * @param string $constraintName
537
     *
538
     * @return bool
539
     */
540 19875
    public function hasForeignKey($constraintName)
541
    {
542 19875
        $constraintName = $this->normalizeIdentifier($constraintName);
543
544 19875
        return isset($this->_fkConstraints[$constraintName]);
545
    }
546
547
    /**
548
     * Returns the foreign key constraint with the given name.
549
     *
550
     * @param string $constraintName The constraint name.
551
     *
552
     * @return ForeignKeyConstraint
553
     *
554
     * @throws SchemaException If the foreign key does not exist.
555
     */
556 343
    public function getForeignKey($constraintName)
557
    {
558 343
        $constraintName = $this->normalizeIdentifier($constraintName);
559 343
        if (! $this->hasForeignKey($constraintName)) {
560
            throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name);
561
        }
562
563 343
        return $this->_fkConstraints[$constraintName];
564
    }
565
566
    /**
567
     * Removes the foreign key constraint with the given name.
568
     *
569
     * @param string $constraintName The constraint name.
570
     *
571
     * @return void
572
     *
573
     * @throws SchemaException
574
     */
575 345
    public function removeForeignKey($constraintName)
576
    {
577 345
        $constraintName = $this->normalizeIdentifier($constraintName);
578 345
        if (! $this->hasForeignKey($constraintName)) {
579
            throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name);
580
        }
581
582 345
        unset($this->_fkConstraints[$constraintName]);
583 345
    }
584
585
    /**
586
     * Returns ordered list of columns (primary keys are first, then foreign keys, then the rest)
587
     *
588
     * @return Column[]
589
     */
590 23806
    public function getColumns()
591
    {
592 23806
        $primaryKey        = $this->getPrimaryKey();
593 23806
        $primaryKeyColumns = [];
594
595 23806
        if ($primaryKey !== null) {
596 23198
            $primaryKeyColumns = $this->filterColumns($primaryKey->getColumns());
597
        }
598
599 23806
        return array_merge($primaryKeyColumns, $this->getForeignKeyColumns(), $this->_columns);
600
    }
601
602
    /**
603
     * Returns foreign key columns
604
     *
605
     * @return Column[]
606
     */
607 23806
    private function getForeignKeyColumns()
608
    {
609 23806
        $foreignKeyColumns = [];
610 23806
        foreach ($this->getForeignKeys() as $foreignKey) {
611 22473
            $foreignKeyColumns = array_merge($foreignKeyColumns, $foreignKey->getColumns());
612
        }
613 23806
        return $this->filterColumns($foreignKeyColumns);
614
    }
615
616
    /**
617
     * Returns only columns that have specified names
618
     *
619
     * @param string[] $columnNames
620
     *
621
     * @return Column[]
622
     */
623 23806
    private function filterColumns(array $columnNames)
624
    {
625
        return array_filter($this->_columns, static function ($columnName) use ($columnNames) {
626 23754
            return in_array($columnName, $columnNames, true);
627 23806
        }, ARRAY_FILTER_USE_KEY);
628
    }
629
630
    /**
631
     * Returns whether this table has a Column with the given name.
632
     *
633
     * @param string $columnName The column name.
634
     *
635
     * @return bool
636
     */
637 23896
    public function hasColumn($columnName)
638
    {
639 23896
        $columnName = $this->normalizeIdentifier($columnName);
640
641 23896
        return isset($this->_columns[$columnName]);
642
    }
643
644
    /**
645
     * Returns the Column with the given name.
646
     *
647
     * @param string $columnName The column name.
648
     *
649
     * @return Column
650
     *
651
     * @throws SchemaException If the column does not exist.
652
     */
653 23628
    public function getColumn($columnName)
654
    {
655 23628
        $columnName = $this->normalizeIdentifier($columnName);
656 23628
        if (! $this->hasColumn($columnName)) {
657 1477
            throw SchemaException::columnDoesNotExist($columnName, $this->_name);
658
        }
659
660 23626
        return $this->_columns[$columnName];
661
    }
662
663
    /**
664
     * Returns the primary key.
665
     *
666
     * @return Index|null The primary key, or null if this Table has no primary key.
667
     */
668 23816
    public function getPrimaryKey()
669
    {
670 23816
        if (! $this->hasPrimaryKey()) {
671 23041
            return null;
672
        }
673
674 23208
        return $this->getIndex($this->_primaryKeyName);
675
    }
676
677
    /**
678
     * Returns the primary key columns.
679
     *
680
     * @return string[]
681
     *
682
     * @throws DBALException
683
     */
684 20128
    public function getPrimaryKeyColumns()
685
    {
686 20128
        $primaryKey = $this->getPrimaryKey();
687
688 20128
        if ($primaryKey === null) {
689
            throw new DBALException('Table ' . $this->getName() . ' has no primary key.');
690
        }
691
692 20128
        return $primaryKey->getColumns();
693
    }
694
695
    /**
696
     * Returns whether this table has a primary key.
697
     *
698
     * @return bool
699
     */
700 23822
    public function hasPrimaryKey()
701
    {
702 23822
        return $this->_primaryKeyName && $this->hasIndex($this->_primaryKeyName);
703
    }
704
705
    /**
706
     * Returns whether this table has an Index with the given name.
707
     *
708
     * @param string $indexName The index name.
709
     *
710
     * @return bool
711
     */
712 23312
    public function hasIndex($indexName)
713
    {
714 23312
        $indexName = $this->normalizeIdentifier($indexName);
715
716 23312
        return isset($this->_indexes[$indexName]);
717
    }
718
719
    /**
720
     * Returns the Index with the given name.
721
     *
722
     * @param string $indexName The index name.
723
     *
724
     * @return Index
725
     *
726
     * @throws SchemaException If the index does not exist.
727
     */
728 23268
    public function getIndex($indexName)
729
    {
730 23268
        $indexName = $this->normalizeIdentifier($indexName);
731 23268
        if (! $this->hasIndex($indexName)) {
732 1352
            throw SchemaException::indexDoesNotExist($indexName, $this->_name);
733
        }
734
735 23266
        return $this->_indexes[$indexName];
736
    }
737
738
    /**
739
     * @return Index[]
740
     */
741 23750
    public function getIndexes()
742
    {
743 23750
        return $this->_indexes;
744
    }
745
746
    /**
747
     * Returns the foreign key constraints.
748
     *
749
     * @return ForeignKeyConstraint[]
750
     */
751 23842
    public function getForeignKeys()
752
    {
753 23842
        return $this->_fkConstraints;
754
    }
755
756
    /**
757
     * @param string $name
758
     *
759
     * @return bool
760
     */
761 20292
    public function hasOption($name)
762
    {
763 20292
        return isset($this->_options[$name]);
764
    }
765
766
    /**
767
     * @param string $name
768
     *
769
     * @return mixed
770
     */
771 19771
    public function getOption($name)
772
    {
773 19771
        return $this->_options[$name];
774
    }
775
776
    /**
777
     * @return mixed[]
778
     */
779 23536
    public function getOptions()
780
    {
781 23536
        return $this->_options;
782
    }
783
784
    /**
785
     * @return void
786
     */
787 22214
    public function visit(Visitor $visitor)
788
    {
789 22214
        $visitor->acceptTable($this);
790
791 22214
        foreach ($this->getColumns() as $column) {
792 22208
            $visitor->acceptColumn($this, $column);
793
        }
794
795 22214
        foreach ($this->getIndexes() as $index) {
796 20053
            $visitor->acceptIndex($this, $index);
797
        }
798
799 22214
        foreach ($this->getForeignKeys() as $constraint) {
800 158
            $visitor->acceptForeignKey($this, $constraint);
801
        }
802 22214
    }
803
804
    /**
805
     * Clone of a Table triggers a deep clone of all affected assets.
806
     *
807
     * @return void
808
     */
809 21569
    public function __clone()
810
    {
811 21569
        foreach ($this->_columns as $k => $column) {
812 21567
            $this->_columns[$k] = clone $column;
813
        }
814 21569
        foreach ($this->_indexes as $k => $index) {
815 21545
            $this->_indexes[$k] = clone $index;
816
        }
817 21569
        foreach ($this->_fkConstraints as $k => $fk) {
818 20550
            $this->_fkConstraints[$k] = clone $fk;
819 20550
            $this->_fkConstraints[$k]->setLocalTable($this);
820
        }
821 21569
    }
822
823
    /**
824
     * Normalizes a given identifier.
825
     *
826
     * Trims quotes and lowercases the given identifier.
827
     *
828
     * @param string|null $identifier The identifier to normalize.
829
     *
830
     * @return string The normalized identifier.
831
     */
832 24232
    private function normalizeIdentifier($identifier)
833
    {
834 24232
        if ($identifier === null) {
835 452
            return '';
836
        }
837
838 24232
        return $this->trimQuotes(strtolower($identifier));
839
    }
840
}
841