Completed
Push — master ( c7757e...39cb21 )
by Luís
16s
created

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

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Schema;
21
22
use Doctrine\DBAL\Types\Type;
23
use Doctrine\DBAL\Schema\Visitor\Visitor;
24
use Doctrine\DBAL\DBALException;
25
26
/**
27
 * Object Representation of a table.
28
 *
29
 * @link   www.doctrine-project.org
30
 * @since  2.0
31
 * @author Benjamin Eberlei <[email protected]>
32
 */
33
class Table extends AbstractAsset
34
{
35
    /**
36
     * @var string
37
     */
38
    protected $_name = null;
39
40
    /**
41
     * @var Column[]
42
     */
43
    protected $_columns = [];
44
45
    /**
46
     * @var Index[]
47
     */
48
    private $implicitIndexes = [];
49
50
    /**
51
     * @var Index[]
52
     */
53
    protected $_indexes = [];
54
55
    /**
56
     * @var string
57
     */
58
    protected $_primaryKeyName = false;
59
60
    /**
61
     * @var ForeignKeyConstraint[]
62
     */
63
    protected $_fkConstraints = [];
64
65
    /**
66
     * @var array
67
     */
68
    protected $_options = [];
69
70
    /**
71
     * @var SchemaConfig
72
     */
73
    protected $_schemaConfig = null;
74
75
    /**
76
     * @param string                 $tableName
77
     * @param Column[]               $columns
78
     * @param Index[]                $indexes
79
     * @param ForeignKeyConstraint[] $fkConstraints
80
     * @param integer                $idGeneratorType
81
     * @param array                  $options
82
     *
83
     * @throws DBALException
84
     */
85 755
    public function __construct($tableName, array $columns=[], array $indexes=[], array $fkConstraints=[], $idGeneratorType = 0, array $options=[])
86
    {
87 755
        if (strlen($tableName) == 0) {
88 1
            throw DBALException::invalidTableName($tableName);
89
        }
90
91 754
        $this->_setName($tableName);
92
93 754
        foreach ($columns as $column) {
94 72
            $this->_addColumn($column);
95
        }
96
97 753
        foreach ($indexes as $idx) {
98 30
            $this->_addIndex($idx);
99
        }
100
101 751
        foreach ($fkConstraints as $constraint) {
102 6
            $this->_addForeignKeyConstraint($constraint);
103
        }
104
105 751
        $this->_options = $options;
106 751
    }
107
108
    /**
109
     * @param SchemaConfig $schemaConfig
110
     *
111
     * @return void
112
     */
113 61
    public function setSchemaConfig(SchemaConfig $schemaConfig)
114
    {
115 61
        $this->_schemaConfig = $schemaConfig;
116 61
    }
117
118
    /**
119
     * @return integer
120
     */
121 144
    protected function _getMaxIdentifierLength()
122
    {
123 144
        if ($this->_schemaConfig instanceof SchemaConfig) {
124 8
            return $this->_schemaConfig->getMaxIdentifierLength();
125
        } else {
126 136
            return 63;
127
        }
128
    }
129
130
    /**
131
     * Sets the Primary Key.
132
     *
133
     * @param array          $columns
134
     * @param string|boolean $indexName
135
     *
136
     * @return self
137
     */
138 314
    public function setPrimaryKey(array $columns, $indexName = false)
139
    {
140 314
        $this->_addIndex($this->_createIndex($columns, $indexName ?: "primary", true, true));
141
142 314
        foreach ($columns as $columnName) {
143 314
            $column = $this->getColumn($columnName);
144 314
            $column->setNotnull(true);
145
        }
146
147 314
        return $this;
148
    }
149
150
    /**
151
     * @param array       $columnNames
152
     * @param string|null $indexName
153
     * @param array       $flags
154
     * @param array       $options
155
     *
156
     * @return self
157
     */
158 95 View Code Duplication
    public function addIndex(array $columnNames, $indexName = null, array $flags = [], array $options = [])
159
    {
160 95
        if ($indexName == null) {
161 26
            $indexName = $this->_generateIdentifierName(
162 26
                array_merge([$this->getName()], $columnNames), "idx", $this->_getMaxIdentifierLength()
163
            );
164
        }
165
166 95
        return $this->_addIndex($this->_createIndex($columnNames, $indexName, false, false, $flags, $options));
167
    }
168
169
    /**
170
     * Drops the primary key from this table.
171
     *
172
     * @return void
173
     */
174 13
    public function dropPrimaryKey()
175
    {
176 13
        $this->dropIndex($this->_primaryKeyName);
177 13
        $this->_primaryKeyName = false;
178 13
    }
179
180
    /**
181
     * Drops an index from this table.
182
     *
183
     * @param string $indexName The index name.
184
     *
185
     * @return void
186
     *
187
     * @throws SchemaException If the index does not exist.
188
     */
189 25 View Code Duplication
    public function dropIndex($indexName)
190
    {
191 25
        $indexName = $this->normalizeIdentifier($indexName);
192 25
        if ( ! $this->hasIndex($indexName)) {
193
            throw SchemaException::indexDoesNotExist($indexName, $this->_name);
194
        }
195 25
        unset($this->_indexes[$indexName]);
196 25
    }
197
198
    /**
199
     * @param array       $columnNames
200
     * @param string|null $indexName
201
     * @param array       $options
202
     *
203
     * @return self
204
     */
205 29 View Code Duplication
    public function addUniqueIndex(array $columnNames, $indexName = null, array $options = [])
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

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