Completed
Branch feature/pre-split (7b42f5)
by Anton
03:44
created

AbstractTable::loadReferences()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
nc 1
dl 0
loc 1
c 0
b 0
f 0
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
9
namespace Spiral\Database\Schemas;
10
11
use Psr\Log\LoggerAwareInterface;
12
use Spiral\Database\Entities\Driver;
13
use Spiral\Database\Schemas\ColumnInterface;
14
use Spiral\Database\Schemas\TableInterface;
15
use Spiral\Debug\Traits\LoggerTrait;
16
use Spiral\ODM\Exceptions\SchemaException;
17
18
/**
19
 * AbstractTable class used to describe and manage state of specified table. It provides ability to
20
 * get table introspection, update table schema and automatically generate set of diff operations.
21
 *
22
 * Most of table operation like column, index or foreign key creation/altering will be applied when
23
 * save() method will be called.
24
 *
25
 * @todo Split operations and state representation.
26
 *
27
 * Column configuration shortcuts:
28
 *
29
 * @method AbstractColumn primary($column)
30
 * @method AbstractColumn bigPrimary($column)
31
 * @method AbstractColumn enum($column, array $values)
32
 * @method AbstractColumn string($column, $length = 255)
33
 * @method AbstractColumn decimal($column, $precision, $scale)
34
 * @method AbstractColumn boolean($column)
35
 * @method AbstractColumn integer($column)
36
 * @method AbstractColumn tinyInteger($column)
37
 * @method AbstractColumn bigInteger($column)
38
 * @method AbstractColumn text($column)
39
 * @method AbstractColumn tinyText($column)
40
 * @method AbstractColumn longText($column)
41
 * @method AbstractColumn double($column)
42
 * @method AbstractColumn float($column)
43
 * @method AbstractColumn datetime($column)
44
 * @method AbstractColumn date($column)
45
 * @method AbstractColumn time($column)
46
 * @method AbstractColumn timestamp($column)
47
 * @method AbstractColumn binary($column)
48
 * @method AbstractColumn tinyBinary($column)
49
 * @method AbstractColumn longBinary($column)
50
 */
51
abstract class AbstractTable extends TableState implements TableInterface, LoggerAwareInterface
52
{
53
    use LoggerTrait;
54
55
    /**
56
     * Indication that table is exists and current schema is fetched from database.
57
     *
58
     * @var bool
59
     */
60
    private $exists = false;
61
62
    /**
63
     * Database specific tablePrefix. Required for table renames.
64
     *
65
     * @var string
66
     */
67
    private $prefix = '';
68
69
    /**
70
     * We have to remember original schema state to create set of diff based commands.
71
     *
72
     * @invisible
73
     *
74
     * @var TableState
75
     */
76
    protected $initial = null;
77
78
    /**
79
     * Compares current and original states.
80
     *
81
     * @invisible
82
     *
83
     * @var Comparator
84
     */
85
    protected $comparator = null;
86
87
    /**
88
     * @invisible
89
     *
90
     * @var Driver
91
     */
92
    protected $driver = null;
93
94
    /**
95
     * Executes table operations.
96
     *
97
     * @var AbstractCommander
98
     */
99
    protected $commander = null;
100
101
    /**
102
     * @param Driver            $driver Parent driver.
103
     * @param AbstractCommander $commander
104
     * @param string            $name   Table name, must include table prefix.
105
     * @param string            $prefix Database specific table prefix.
106
     */
107
    public function __construct(Driver $driver, AbstractCommander $commander, $name, $prefix)
108
    {
109
        parent::__construct($name);
110
111
        $this->driver = $driver;
112
        $this->commander = $commander;
113
114
        $this->prefix = $prefix;
115
116
        //Locking down initial table state
117
        $this->initial = new TableState($name);
118
119
        //Needed to compare schemas
120
        $this->comparator = new Comparator($this->initial, $this);
121
122
        if (!$this->driver->hasTable($this->getName())) {
123
            //There is no need to load table schema when table does not exist
124
            return;
125
        }
126
127
        //Loading table information
128
        $this->loadColumns()->loadIndexes()->loadReferences();
129
130
        //Syncing schemas
131
        $this->initial->syncSchema($this);
132
133
        $this->exists = true;
134
    }
135
136
    /**
137
     * Get associated table driver.
138
     *
139
     * @return Driver
140
     */
141
    public function driver()
142
    {
143
        return $this->driver;
144
    }
145
146
    /**
147
     * Get table comparator.
148
     *
149
     * @return Comparator
150
     */
151
    public function comparator()
152
    {
153
        return $this->comparator;
154
    }
155
156
    /**
157
     * {@inheritdoc}
158
     */
159
    public function exists()
160
    {
161
        return $this->exists;
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     *
167
     * Automatically forces prefix value.
168
     */
169
    public function setName($name)
170
    {
171
        parent::setName($this->prefix . $name);
172
    }
173
174
    /**
175
     * {@inheritdoc}
176
     *
177
     * @param bool $quoted Quote name.
178
     */
179
    public function getName($quoted = false)
180
    {
181
        if (!$quoted) {
182
            return parent::getName();
183
        }
184
185
        return $this->driver->identifier(parent::getName());
186
    }
187
188
    /**
189
     * Return database specific table prefix.
190
     *
191
     * @return string
192
     */
193
    public function getPrefix()
194
    {
195
        return $this->prefix;
196
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201
    public function getDependencies()
202
    {
203
        $tables = [];
204
        foreach ($this->getForeigns() as $foreign) {
205
            $tables[] = $foreign->getForeignTable();
206
        }
207
208
        return $tables;
209
    }
210
211
    /**
212
     * Set table primary keys. Operation can only be applied for newly created tables. Now every
213
     * database might support compound indexes.
214
     *
215
     * @param array $columns
216
     *
217
     * @return $this
218
     *
219
     * @throws SchemaException
220
     */
221
    public function setPrimaryKeys(array $columns)
222
    {
223
        if ($this->exists() && $this->getPrimaryKeys() != $columns) {
224
            throw new SchemaException('Unable to change primary keys for already exists table');
225
        }
226
227
        parent::setPrimaryKeys($columns);
228
229
        return $this;
230
    }
231
232
    /**
233
     * Get/create instance of AbstractColumn associated with current table.
234
     *
235
     * Examples:
236
     * $table->column('name')->string();
237
     *
238
     * @param string $name
239
     *
240
     * @return AbstractColumn
241
     */
242
    public function column($name)
243
    {
244
        if (!empty($column = $this->findColumn($name))) {
245
            return $column->declared(true);
246
        }
247
248
        $column = $this->columnSchema($name)->declared(true);
249
250
        //Registering (without adding to initial schema)
251
        return $this->registerColumn($column);
252
    }
253
254
    /**
255
     * Get/create instance of AbstractIndex associated with current table based on list of forming
256
     * column names.
257
     *
258
     * Example:
259
     * $table->index('key');
260
     * $table->index('key', 'key2');
261
     * $table->index(['key', 'key2']);
262
     *
263
     * @param mixed $columns Column name, or array of columns.
264
     *
265
     * @return AbstractIndex
266
     */
267
    public function index($columns)
268
    {
269
        $columns = is_array($columns) ? $columns : func_get_args();
270
        if (!empty($index = $this->findIndex($columns))) {
271
            return $index->declared(true);
272
        }
273
274
        $index = $this->indexSchema(null)->declared(true);
275
        $index->columns($columns)->unique(false);
276
277
        return $this->registerIndex($index);
278
    }
279
280
    /**
281
     * Get/create instance of AbstractIndex associated with current table based on list of forming
282
     * column names. Index type must be forced as UNIQUE.
283
     *
284
     * Example:
285
     * $table->unique('key');
286
     * $table->unique('key', 'key2');
287
     * $table->unique(['key', 'key2']);
288
     *
289
     * @param mixed $columns Column name, or array of columns.
290
     *
291
     * @return AbstractColumn|null
292
     */
293
    public function unique($columns)
294
    {
295
        $columns = is_array($columns) ? $columns : func_get_args();
296
297
        return $this->index($columns)->unique(true);
298
    }
299
300
    /**
301
     * Get/create instance of AbstractReference associated with current table based on local column
302
     * name.
303
     *
304
     * @param string $column Column name.
305
     *
306
     * @return AbstractReference|null
307
     */
308
    public function foreign($column)
309
    {
310
        if (!empty($foreign = $this->findForeign($column))) {
311
            return $foreign->declared(true);
312
        }
313
314
        $foreign = $this->referenceSchema(null)->declared(true);
315
        $foreign->column($column);
316
317
        return $this->registerReference($foreign);
318
    }
319
320
    /**
321
     * Rename column (only if column exists).
322
     *
323
     * @param string $column
324
     * @param string $name New column name.
325
     *
326
     * @return $this
327
     */
328
    public function renameColumn($column, $name)
329
    {
330
        if (empty($column = $this->findColumn($column))) {
331
            return $this;
332
        }
333
334
        //Renaming automatically declares column
335
        $column->declared(true)->setName($name);
336
337
        return $this;
338
    }
339
340
    /**
341
     * Rename index (only if index exists).
342
     *
343
     * @param array  $columns Index forming columns.
344
     * @param string $name    New index name.
345
     *
346
     * @return $this
347
     */
348
    public function renameIndex(array $columns, $name)
349
    {
350
        if (empty($index = $this->findIndex($columns))) {
351
            return $this;
352
        }
353
354
        //Renaming automatically declares index
355
        $index->declared(true)->setName($name);
356
357
        return $this;
358
    }
359
360
    /**
361
     * Drop column by it's name.
362
     *
363
     * @param string $column
364
     *
365
     * @return $this
366
     */
367
    public function dropColumn($column)
368
    {
369
        if (!empty($column = $this->findColumn($column))) {
370
            $this->forgetColumn($column);
371
            $this->removeDependent($column);
372
        }
373
374
        return $this;
375
    }
376
377
    /**
378
     * Drop index by it's forming columns.
379
     *
380
     * @param array $columns
381
     *
382
     * @return $this
383
     */
384
    public function dropIndex(array $columns)
385
    {
386
        if (!empty($index = $this->findIndex($columns))) {
387
            $this->forgetIndex($index);
388
        }
389
390
        return $this;
391
    }
392
393
    /**
394
     * Drop foreign key by it's name.
395
     *
396
     * @param string $column
397
     *
398
     * @return $this
399
     */
400
    public function dropForeign($column)
401
    {
402
        if (!empty($foreign = $this->findForeign($column))) {
403
            $this->forgetForeign($foreign);
404
        }
405
406
        return $this;
407
    }
408
409
    /**
410
     * Shortcut for column() method.
411
     *
412
     * @param string $column
413
     *
414
     * @return AbstractColumn
415
     */
416
    public function __get($column)
417
    {
418
        return $this->column($column);
419
    }
420
421
    /**
422
     * Column creation/altering shortcut, call chain is identical to:
423
     * AbstractTable->column($name)->$type($arguments).
424
     *
425
     * Example:
426
     * $table->string("name");
427
     * $table->text("some_column");
428
     *
429
     * @param string $type
430
     * @param array  $arguments Type specific parameters.
431
     *
432
     * @return AbstractColumn
433
     */
434
    public function __call($type, array $arguments)
435
    {
436
        return call_user_func_array(
437
            [$this->column($arguments[0]), $type],
438
            array_slice($arguments, 1)
439
        );
440
    }
441
442
    /**
443
     * Declare every existed element. Method has to be called if table modification applied to
444
     * existed table to prevent dropping of existed elements.
445
     *
446
     * @return $this
447
     */
448
    public function declareExisted()
449
    {
450
        foreach ($this->getColumns() as $column) {
451
            $column->declared(true);
452
        }
453
454
        foreach ($this->getIndexes() as $index) {
455
            $index->declared(true);
456
        }
457
458
        foreach ($this->getForeigns() as $foreign) {
459
            $foreign->declared(true);
460
        }
461
462
        return $this;
463
    }
464
465
    /**
466
     * Calculate difference (removed columns, indexes and foreign keys).
467
     *
468
     * @param bool $forgetColumns
469
     * @param bool $forgetIndexes
470
     * @param bool $forgetForeigns
471
     */
472
    public function forgetUndeclared($forgetColumns, $forgetIndexes, $forgetForeigns)
473
    {
474
        //We don't need to worry about changed or created columns, indexes and foreign keys here
475
        //as it already handled, we only have to drop columns which were not listed in schema
476
477
        foreach ($this->getColumns() as $column) {
478
            if ($forgetColumns && !$column->isDeclared()) {
479
                $this->forgetColumn($column);
480
                $this->removeDependent($column);
481
            }
482
        }
483
484
        foreach ($this->getIndexes() as $index) {
485
            if ($forgetIndexes && !$index->isDeclared()) {
486
                $this->forgetIndex($index);
487
            }
488
        }
489
490
        foreach ($this->getForeigns() as $foreign) {
491
            if ($forgetForeigns && !$foreign->isDeclared()) {
492
                $this->forgetForeign($foreign);
493
            }
494
        }
495
    }
496
497
    /**
498
     * Save table schema including every column, index, foreign key creation/altering. If table does
499
     * not exist it must be created.
500
     *
501
     * @param bool $forgetColumns  Drop all non declared columns.
502
     * @param bool $forgetIndexes  Drop all non declared indexes.
503
     * @param bool $forgetForeigns Drop all non declared foreign keys.
504
     */
505
    public function save($forgetColumns = true, $forgetIndexes = true, $forgetForeigns = true)
506
    {
507
        if (!$this->exists()) {
508
            $this->createSchema();
509
        } else {
510
            //Let's remove from schema elements which wasn't declared
511
            $this->forgetUndeclared($forgetColumns, $forgetIndexes, $forgetForeigns);
512
513
            if ($this->hasChanges()) {
514
                $this->synchroniseSchema();
515
            }
516
        }
517
518
        //Syncing internal states
519
        $this->initial->syncSchema($this);
520
        $this->exists = true;
521
    }
522
523
    /**
524
     * Drop table schema in database. This operation must be applied immediately.
525
     */
526
    public function drop()
527
    {
528
        $this->forgetElements();
529
530
        //Re-syncing initial state
531
        $this->initial->syncSchema($this->forgetElements());
532
533
        if ($this->exists()) {
534
            $this->commander->dropTable($this->getName());
535
        }
536
537
        $this->exists = false;
538
    }
539
540
    /**
541
     * @return AbstractColumn|string
542
     */
543
    public function __toString()
544
    {
545
        return $this->getName();
546
    }
547
548
    /**
549
     * @return array
550
     */
551
    public function __debugInfo()
552
    {
553
        return [
554
            'name'        => $this->getName(),
555
            'primaryKeys' => $this->getPrimaryKeys(),
556
            'columns'     => array_values($this->getColumns()),
557
            'indexes'     => array_values($this->getIndexes()),
558
            'references'  => array_values($this->getForeigns()),
559
        ];
560
    }
561
562
    /**
563
     * Create table.
564
     */
565
    protected function createSchema()
566
    {
567
        $this->logger()->debug('Creating new table {table}.', ['table' => $this->getName(true)]);
568
569
        $this->commander->createTable($this);
570
    }
571
572
    /**
573
     * Execute schema update.
574
     */
575
    protected function synchroniseSchema()
576
    {
577
        if ($this->getName() != $this->initial->getName()) {
578
            //Executing renaming
579
            $this->commander->renameTable($this->initial->getName(), $this->getName());
580
        }
581
582
        //Some data has to be dropped before column updates
583
        $this->dropForeigns()->dropIndexes();
584
585
        //Generate update flow
586
        $this->synchroniseColumns()->synchroniseIndexes()->synchroniseForeigns();
587
    }
588
589
    /**
590
     * Synchronise columns.
591
     *
592
     * @todo Split or isolate.
593
     * @return $this
594
     */
595
    protected function synchroniseColumns()
596
    {
597
        foreach ($this->comparator->droppedColumns() as $column) {
598
            $this->logger()->debug('Dropping column [{statement}] from table {table}.', [
599
                'statement' => $column->sqlStatement(),
600
                'table'     => $this->getName(true),
601
            ]);
602
603
            $this->commander->dropColumn($this, $column);
604
        }
605
606
        foreach ($this->comparator->addedColumns() as $column) {
607
            $this->logger()->debug('Adding column [{statement}] into table {table}.', [
608
                'statement' => $column->sqlStatement(),
609
                'table'     => $this->getName(true),
610
            ]);
611
612
            $this->commander->addColumn($this, $column);
613
        }
614
615
        foreach ($this->comparator->alteredColumns() as $pair) {
616
            /**
617
             * @var AbstractColumn $initial
618
             * @var AbstractColumn $current
619
             */
620
            list($current, $initial) = $pair;
621
622
            $this->logger()->debug('Altering column [{statement}] to [{new}] in table {table}.', [
623
                'statement' => $initial->sqlStatement(),
624
                'new'       => $current->sqlStatement(),
625
                'table'     => $this->getName(true),
626
            ]);
627
628
            $this->commander->alterColumn($this, $initial, $current);
629
        }
630
631
        return $this;
632
    }
633
634
    /**
635
     * Drop needed indexes.
636
     *
637
     * @return $this
638
     */
639 View Code Duplication
    protected function dropIndexes()
0 ignored issues
show
Duplication introduced by
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...
640
    {
641
        foreach ($this->comparator->droppedIndexes() as $index) {
642
            $this->logger()->debug('Dropping index [{statement}] from table {table}.', [
643
                'statement' => $index->sqlStatement(),
644
                'table'     => $this->getName(true),
645
            ]);
646
647
            $this->commander->dropIndex($this, $index);
648
        }
649
650
        return $this;
651
    }
652
653
    /**
654
     * Synchronise indexes.
655
     *
656
     * @return $this
657
     */
658 View Code Duplication
    protected function synchroniseIndexes()
0 ignored issues
show
Duplication introduced by
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...
659
    {
660
        foreach ($this->comparator->addedIndexes() as $index) {
661
            $this->logger()->debug('Adding index [{statement}] into table {table}.', [
662
                'statement' => $index->sqlStatement(),
663
                'table'     => $this->getName(true),
664
            ]);
665
666
            $this->commander->addIndex($this, $index);
667
        }
668
669
        foreach ($this->comparator->alteredIndexes() as $pair) {
670
            /**
671
             * @var AbstractIndex $initial
672
             * @var AbstractIndex $current
673
             */
674
            list($current, $initial) = $pair;
675
676
            $this->logger()->debug('Altering index [{statement}] to [{new}] in table {table}.', [
677
                'statement' => $initial->sqlStatement(),
678
                'new'       => $current->sqlStatement(),
679
                'table'     => $this->getName(true),
680
            ]);
681
682
            $this->commander->alterIndex($this, $initial, $current);
683
        }
684
685
        return $this;
686
    }
687
688
    /**
689
     * Drop needed foreign keys.
690
     *
691
     * @return $this
692
     */
693 View Code Duplication
    protected function dropForeigns()
0 ignored issues
show
Duplication introduced by
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...
694
    {
695
        foreach ($this->comparator->droppedForeigns() as $foreign) {
696
            $this->logger()->debug('Dropping foreign key [{statement}] from table {table}.', [
697
                'statement' => $foreign->sqlStatement(),
698
                'table'     => $this->getName(true),
699
            ]);
700
701
            $this->commander->dropForeign($this, $foreign);
702
        }
703
704
        return $this;
705
    }
706
707
    /**
708
     * Synchronise foreign keys.
709
     *
710
     * @return $this
711
     */
712 View Code Duplication
    protected function synchroniseForeigns()
0 ignored issues
show
Duplication introduced by
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...
713
    {
714
        foreach ($this->comparator->addedForeigns() as $foreign) {
715
            $this->logger()->debug('Adding foreign key [{statement}] into table {table}.', [
716
                'statement' => $foreign->sqlStatement(),
717
                'table'     => $this->getName(true),
718
            ]);
719
720
            $this->commander->addForeign($this, $foreign);
721
        }
722
723
        foreach ($this->comparator->alteredForeigns() as $pair) {
724
            /**
725
             * @var AbstractReference $initial
726
             * @var AbstractReference $current
727
             */
728
            list($current, $initial) = $pair;
729
730
            $this->logger()->debug('Altering foreign key [{statement}] to [{new}] in {table}.', [
731
                'statement' => $initial->sqlStatement(),
732
                'table'     => $this->getName(true),
733
            ]);
734
735
            $this->commander->alterForeign($this, $initial, $current);
736
        }
737
738
        return $this;
739
    }
740
741
    /**
742
     * Driver specific column schema.
743
     *
744
     * @param string $name
745
     * @param mixed  $schema
746
     *
747
     * @return AbstractColumn
748
     */
749
    abstract protected function columnSchema($name, $schema = null);
750
751
    /**
752
     * Driver specific index schema.
753
     *
754
     * @param string $name
755
     * @param mixed  $schema
756
     *
757
     * @return AbstractIndex
758
     */
759
    abstract protected function indexSchema($name, $schema = null);
760
761
    /**
762
     * Driver specific reference schema.
763
     *
764
     * @param string $name
765
     * @param mixed  $schema
766
     *
767
     * @return AbstractReference
768
     */
769
    abstract protected function referenceSchema($name, $schema = null);
770
771
    /**
772
     * Must load table columns.
773
     *
774
     * @see registerColumn()
775
     *
776
     * @return self
777
     */
778
    abstract protected function loadColumns();
779
780
    /**
781
     * Must load table indexes.
782
     *
783
     * @see registerIndex()
784
     *
785
     * @return self
786
     */
787
    abstract protected function loadIndexes();
788
789
    /**
790
     * Must load table references.
791
     *
792
     * @see registerReference()
793
     *
794
     * @return self
795
     */
796
    abstract protected function loadReferences();
797
798
    /**
799
     * Check if table schema has been modified. Attention, you have to execute dropUndeclared first
800
     * to get valid results.
801
     *
802
     * @return bool
803
     */
804
    protected function hasChanges()
805
    {
806
        return $this->comparator->hasChanges();
807
    }
808
809
    /**
810
     * Remove dependent indexes and foreign keys.
811
     *
812
     * @param ColumnInterface $column
813
     */
814
    private function removeDependent(ColumnInterface $column)
815
    {
816
        if ($this->hasForeign($column->getName())) {
817
            $this->forgetForeign($this->foreign($column->getName()));
0 ignored issues
show
Bug introduced by
It seems like $this->foreign($column->getName()) can be null; however, forgetForeign() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
818
        }
819
820
        foreach ($this->getIndexes() as $index) {
821
            if (in_array($column->getName(), $index->getColumns())) {
822
                //Dropping related indexes
823
                $this->forgetIndex($index);
824
            }
825
        }
826
    }
827
828
    /**
829
     * Forget all elements.
830
     *
831
     * @return $this
832
     */
833
    private function forgetElements()
834
    {
835
        foreach ($this->getColumns() as $column) {
836
            $this->forgetColumn($column);
837
        }
838
839
        foreach ($this->getIndexes() as $index) {
840
            $this->forgetIndex($index);
841
        }
842
843
        foreach ($this->getForeigns() as $foreign) {
844
            $this->forgetForeign($foreign);
845
        }
846
847
        return $this;
848
    }
849
}
850