Completed
Branch feature/pre-split (b5c37f)
by Anton
03:43
created

AbstractTable   C

Complexity

Total Complexity 63

Size/Duplication

Total Lines 713
Duplicated Lines 3.37 %

Coupling/Cohesion

Components 2
Dependencies 10

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 24
loc 713
rs 5
c 1
b 0
f 0
wmc 63
lcom 2
cbo 10

45 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 20 3
A getDriver() 0 4 1
A getComparator() 0 4 1
A hasChanges() 0 4 1
A exists() 0 4 2
A getStatus() 0 4 1
A getPrefix() 0 4 1
A setName() 0 6 1
A getName() 0 4 1
A getInitialName() 0 4 1
A declareDropped() 0 9 2
A setPrimaryKeys() 0 10 1
A getPrimaryKeys() 0 4 1
A hasColumn() 0 4 1
A getColumns() 0 4 1
A hasIndex() 0 4 1
A getIndexes() 0 4 1
A hasForeign() 0 4 1
A getForeigns() 0 4 1
A getDependencies() 0 9 2
A column() 0 12 2
A __get() 0 4 1
A __call() 0 7 1
B index() 0 20 5
A foreign() 0 20 3
A renameColumn() 0 11 2
A renameIndex() 0 13 2
A dropColumn() 11 11 2
A dropIndex() 0 13 2
A dropForeign() 13 13 2
A setStatus() 0 11 2
A resetState() 0 6 1
B save() 0 31 4
A __toString() 0 4 1
A __debugInfo() 0 10 1
A initSchema() 0 18 4
fetchColumns() 0 1 ?
fetchIndexes() 0 1 ?
fetchReferences() 0 1 ?
fetchPrimaryKeys() 0 1 ?
createColumn() 0 1 ?
createIndex() 0 1 ?
createForeign() 0 1 ?
A createIdentifier() 0 11 2
A iocContainer() 0 5 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like AbstractTable often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractTable, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * components
4
 *
5
 * @author    Wolfy-J
6
 */
7
namespace Spiral\Database\Schemas\Prototypes;
8
9
use Interop\Container\ContainerInterface;
10
use Psr\Log\LoggerAwareInterface;
11
use Psr\Log\LoggerInterface;
12
use Spiral\Core\Component;
13
use Spiral\Database\Entities\AbstractHandler;
14
use Spiral\Database\Entities\Driver;
15
use Spiral\Database\Exceptions\HandlerException;
16
use Spiral\Database\Exceptions\SchemaException;
17
use Spiral\Database\Schemas\ColumnInterface;
18
use Spiral\Database\Schemas\IndexInterface;
19
use Spiral\Database\Schemas\ReferenceInterface;
20
use Spiral\Database\Schemas\StateComparator;
21
use Spiral\Database\Schemas\Syncronizer;
22
use Spiral\Database\Schemas\TableInterface;
23
use Spiral\Database\Schemas\TableState;
24
use Spiral\Debug\Traits\LoggerTrait;
25
26
/**
27
 * AbstractTable class used to describe and manage state of specified table. It provides ability to
28
 * get table introspection, update table schema and automatically generate set of diff operations.
29
 *
30
 * Most of table operation like column, index or foreign key creation/altering will be applied when
31
 * save() method will be called.
32
 *
33
 * Column configuration shortcuts:
34
 *
35
 * @method AbstractColumn primary($column)
36
 * @method AbstractColumn bigPrimary($column)
37
 * @method AbstractColumn enum($column, array $values)
38
 * @method AbstractColumn string($column, $length = 255)
39
 * @method AbstractColumn decimal($column, $precision, $scale)
40
 * @method AbstractColumn boolean($column)
41
 * @method AbstractColumn integer($column)
42
 * @method AbstractColumn tinyInteger($column)
43
 * @method AbstractColumn bigInteger($column)
44
 * @method AbstractColumn text($column)
45
 * @method AbstractColumn tinyText($column)
46
 * @method AbstractColumn longText($column)
47
 * @method AbstractColumn double($column)
48
 * @method AbstractColumn float($column)
49
 * @method AbstractColumn datetime($column)
50
 * @method AbstractColumn date($column)
51
 * @method AbstractColumn time($column)
52
 * @method AbstractColumn timestamp($column)
53
 * @method AbstractColumn binary($column)
54
 * @method AbstractColumn tinyBinary($column)
55
 * @method AbstractColumn longBinary($column)
56
 */
57
abstract class AbstractTable extends Component implements TableInterface, LoggerAwareInterface
58
{
59
    use LoggerTrait;
60
61
    /**
62
     * Table states.
63
     */
64
    const STATUS_NEW     = 0;
65
    const STATUS_EXISTS  = 1;
66
    const STATUS_DROPPED = 2;
67
68
    /**
69
     * Indication that table is exists and current schema is fetched from database.
70
     *
71
     * @var int
72
     */
73
    private $status = self::STATUS_NEW;
74
75
    /**
76
     * Database specific tablePrefix. Required for table renames.
77
     *
78
     * @var string
79
     */
80
    private $prefix = '';
81
82
    /**
83
     * @invisible
84
     *
85
     * @var Driver
86
     */
87
    protected $driver = null;
88
89
    /**
90
     * Initial table state.
91
     *
92
     * @invisible
93
     * @var TableState
94
     */
95
    protected $initial = null;
96
97
    /**
98
     * Currently defined table state.
99
     *
100
     * @invisible
101
     * @var TableState
102
     */
103
    protected $current = null;
104
105
    /**
106
     * @param Driver $driver Parent driver.
107
     * @param string $name   Table name, must include table prefix.
108
     * @param string $prefix Database specific table prefix.
109
     */
110
    public function __construct(Driver $driver, string $name, string $prefix)
111
    {
112
        $this->driver = $driver;
113
        $this->prefix = $prefix;
114
115
        //Initializing states
116
        $this->initial = new TableState($this->prefix . $name);
117
        $this->current = new TableState($this->prefix . $name);
118
119
        if ($this->driver->hasTable($this->getName())) {
120
            $this->status = self::STATUS_EXISTS;
121
        }
122
123
        if ($this->exists()) {
124
            //Initiating table schema
125
            $this->initSchema($this->initial);
126
        }
127
128
        $this->setStatus($this->initial);
129
    }
130
131
    /**
132
     * Get instance of associated driver.
133
     *
134
     * @return Driver
135
     */
136
    public function getDriver(): Driver
137
    {
138
        return $this->driver;
139
    }
140
141
    /**
142
     * @return StateComparator
143
     */
144
    public function getComparator(): StateComparator
145
    {
146
        return new StateComparator($this->initial, $this->current);
147
    }
148
149
    /**
150
     * Check if table schema has been modified since synchronization.
151
     *
152
     * @return bool
153
     */
154
    protected function hasChanges(): bool
155
    {
156
        return $this->getComparator()->hasChanges();
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162
    public function exists(): bool
163
    {
164
        return $this->status == self::STATUS_EXISTS || $this->status == self::STATUS_DROPPED;
165
    }
166
167
    /**
168
     * Table status (see codes above).
169
     *
170
     * @return int
171
     */
172
    public function getStatus(): int
173
    {
174
        return $this->status;
175
    }
176
177
    /**
178
     * Return database specific table prefix.
179
     *
180
     * @return string
181
     */
182
    public function getPrefix(): string
183
    {
184
        return $this->prefix;
185
    }
186
187
    /**
188
     * Sets table name. Use this function in combination with save to rename table.
189
     *
190
     * @param string $name
191
     *
192
     * @return string Prefixed table name.
193
     */
194
    public function setName(string $name): string
195
    {
196
        $this->current->setName($this->prefix . $name);
197
198
        return $this->getName();
199
    }
200
201
    /**
202
     * {@inheritdoc}
203
     */
204
    public function getName(): string
205
    {
206
        return $this->current->getName();
207
    }
208
209
    /**
210
     * Table name before rename.
211
     *
212
     * @return string
213
     */
214
    public function getInitialName(): string
215
    {
216
        return $this->initial->getName();
217
    }
218
219
    /**
220
     * Declare table as dropped, you have to sync table using "save" method in order to apply this
221
     * change.
222
     */
223
    public function declareDropped()
224
    {
225
        if ($this->status == self::STATUS_NEW) {
226
            throw new SchemaException("Unable to drop non existed table");
227
        }
228
229
        //Declaring as dropper
230
        $this->status = self::STATUS_DROPPED;
231
    }
232
233
    /**
234
     * Set table primary keys. Operation can only be applied for newly created tables. Now every
235
     * database might support compound indexes.
236
     *
237
     * @param array $columns
238
     *
239
     * @return self
240
     */
241
    public function setPrimaryKeys(array $columns): AbstractTable
242
    {
243
        //Originally we were forcing an exception when primary key were changed, now we should
244
        //force it when table will be synced
245
246
        //Updating primary keys in current state
247
        $this->current->setPrimaryKeys($columns);
248
249
        return $this;
250
    }
251
252
    /**
253
     * {@inheritdoc}
254
     */
255
    public function getPrimaryKeys(): array
256
    {
257
        return $this->current->getPrimaryKeys();
258
    }
259
260
    /**
261
     * {@inheritdoc}
262
     */
263
    public function hasColumn(string $name): bool
264
    {
265
        return $this->current->hasColumn($name);
266
    }
267
268
    /**
269
     * {@inheritdoc}
270
     *
271
     * @return ColumnInterface[]|AbstractColumn[]
272
     */
273
    public function getColumns(): array
274
    {
275
        return $this->current->getColumns();
276
    }
277
278
    /**
279
     * {@inheritdoc}
280
     */
281
    public function hasIndex(array $columns = []): bool
282
    {
283
        return $this->current->hasIndex($columns);
284
    }
285
286
    /**
287
     * {@inheritdoc}
288
     *
289
     * @return IndexInterface[]|AbstractIndex[]
290
     */
291
    public function getIndexes(): array
292
    {
293
        return $this->current->getIndexes();
294
    }
295
296
    /**
297
     * {@inheritdoc}
298
     */
299
    public function hasForeign(string $column): bool
300
    {
301
        return $this->current->hasForeign($column);
302
    }
303
304
    /**
305
     * {@inheritdoc}
306
     *
307
     * @return ReferenceInterface[]|AbstractReference[]
308
     */
309
    public function getForeigns(): array
310
    {
311
        return $this->current->getForeigns();
312
    }
313
314
    /**
315
     * {@inheritdoc}
316
     */
317
    public function getDependencies(): array
318
    {
319
        $tables = [];
320
        foreach ($this->current->getForeigns() as $foreign) {
321
            $tables[] = $foreign->getForeignTable();
322
        }
323
324
        return $tables;
325
    }
326
327
    /**
328
     * Get/create instance of AbstractColumn associated with current table.
329
     *
330
     * Examples:
331
     * $table->column('name')->string();
332
     *
333
     * @param string $name
334
     *
335
     * @return AbstractColumn
336
     */
337
    public function column(string $name): AbstractColumn
338
    {
339
        if ($this->current->hasColumn($name)) {
340
            //Column already exists
341
            return $this->current->findColumn($name);
342
        }
343
344
        $column = $this->createColumn($name);
345
        $this->current->registerColumn($column);
346
347
        return $column;
348
    }
349
350
    /**
351
     * Shortcut for column() method.
352
     *
353
     * @param string $column
354
     *
355
     * @return AbstractColumn
356
     */
357
    public function __get(string $column)
358
    {
359
        return $this->column($column);
360
    }
361
362
    /**
363
     * Column creation/altering shortcut, call chain is identical to:
364
     * AbstractTable->column($name)->$type($arguments).
365
     *
366
     * Example:
367
     * $table->string("name");
368
     * $table->text("some_column");
369
     *
370
     * @param string $type
371
     * @param array  $arguments Type specific parameters.
372
     *
373
     * @return AbstractColumn
374
     */
375
    public function __call(string $type, array $arguments)
376
    {
377
        return call_user_func_array(
378
            [$this->column($arguments[0]), $type],
379
            array_slice($arguments, 1)
380
        );
381
    }
382
383
    /**
384
     * Get/create instance of AbstractIndex associated with current table based on list of forming
385
     * column names.
386
     *
387
     * Example:
388
     * $table->index('key');
389
     * $table->index('key', 'key2');
390
     * $table->index(['key', 'key2']);
391
     *
392
     * @param mixed $columns Column name, or array of columns.
393
     *
394
     * @return AbstractIndex
395
     *
396
     * @throws SchemaException
397
     */
398
    public function index($columns): AbstractIndex
399
    {
400
        $columns = is_array($columns) ? $columns : func_get_args();
401
402
        foreach ($columns as $column) {
403
            if (!$this->hasColumn($column)) {
404
                throw new SchemaException("Undefined column '{$column}' in '{$this->getName()}'");
405
            }
406
        }
407
408
        if ($this->hasIndex($columns)) {
409
            return $this->current->findIndex($columns);
410
        }
411
412
        $index = $this->createIndex($this->createIdentifier('index', $columns));
413
        $index->columns($columns);
414
        $this->current->registerIndex($index);
415
416
        return $index;
417
    }
418
419
    /**
420
     * Get/create instance of AbstractReference associated with current table based on local column
421
     * name.
422
     *
423
     * @param string $column
424
     *
425
     * @return AbstractReference
426
     *
427
     * @throws SchemaException
428
     */
429
    public function foreign(string $column): AbstractReference
430
    {
431
        if (!$this->hasColumn($column)) {
432
            throw new SchemaException("Undefined column '{$column}' in '{$this->getName()}'");
433
        }
434
435
        if ($this->hasForeign($column)) {
436
            return $this->current->findForeign($column);
437
        }
438
439
        $foreign = $this->createForeign($this->createIdentifier('foreign', [$column]));
440
        $foreign->column($column);
441
442
        $this->current->registerReference($foreign);
443
444
        //Let's ensure index existence to performance and compatibility reasons
445
        $this->index($column);
446
447
        return $foreign;
448
    }
449
450
    /**
451
     * Rename column (only if column exists).
452
     *
453
     * @param string $column
454
     * @param string $name New column name.
455
     *
456
     * @return self
457
     *
458
     * @throws SchemaException
459
     */
460
    public function renameColumn(string $column, string $name): AbstractTable
461
    {
462
        if (!$this->hasColumn($column)) {
463
            throw new SchemaException("Undefined column '{$column}' in '{$this->getName()}'");
464
        }
465
466
        //Rename operation is simple about declaring new name
467
        $this->column($column)->setName($name);
468
469
        return $this;
470
    }
471
472
    /**
473
     * Rename index (only if index exists).
474
     *
475
     * @param array  $columns Index forming columns.
476
     * @param string $name    New index name.
477
     *
478
     * @return self
479
     *
480
     * @throws SchemaException
481
     */
482
    public function renameIndex(array $columns, string $name): AbstractTable
483
    {
484
        if ($this->hasIndex($columns)) {
485
            throw new SchemaException(
486
                "Undefined index ['" . join("', '", $columns) . "'] in '{$this->getName()}'"
487
            );
488
        }
489
490
        //Declaring new index name
491
        $this->index($columns)->setName($name);
492
493
        return $this;
494
    }
495
496
    /**
497
     * Drop column by it's name.
498
     *
499
     * @param string $column
500
     *
501
     * @return self
502
     *
503
     * @throws SchemaException
504
     */
505 View Code Duplication
    public function dropColumn(string $column): AbstractTable
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...
506
    {
507
        if (empty($schema = $this->current->findColumn($column))) {
508
            throw new SchemaException("Undefined column '{$column}' in '{$this->getName()}'");
509
        }
510
511
        //Dropping column from current schema
512
        $this->current->forgetColumn($schema);
513
514
        return $this;
515
    }
516
517
    /**
518
     * Drop index by it's forming columns.
519
     *
520
     * @param array $columns
521
     *
522
     * @return self
523
     *
524
     * @throws SchemaException
525
     */
526
    public function dropIndex(array $columns): AbstractTable
527
    {
528
        if (empty($schema = $this->current->findIndex($columns))) {
529
            throw new SchemaException(
530
                "Undefined index ['" . join("', '", $columns) . "'] in '{$this->getName()}'"
531
            );
532
        }
533
534
        //Dropping index from current schema
535
        $this->current->forgetIndex($schema);
536
537
        return $this;
538
    }
539
540
    /**
541
     * Drop foreign key by it's name.
542
     *
543
     * @param string $column
544
     *
545
     * @return self
546
     *
547
     * @throws SchemaException
548
     */
549 View Code Duplication
    public function dropForeign($column): AbstractTable
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...
550
    {
551
        if (!empty($schema = $this->current->findForeign($column))) {
552
            throw new SchemaException(
553
                "Undefined FK on '{$column}' in '{$this->getName()}'"
554
            );
555
        }
556
557
        //Dropping foreign from current schema
558
        $this->current->forgetForeign($schema);
0 ignored issues
show
Documentation introduced by
$schema is of type null, but the function expects a object<Spiral\Database\S...ypes\AbstractReference>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
559
560
        return $this;
561
    }
562
563
    /**
564
     * Reset table state to new form.
565
     *
566
     * @param TableState $status Use null to flush table schema.
567
     *
568
     * @return self|$this
569
     */
570
    public function setStatus(TableState $status = null): AbstractTable
571
    {
572
        $this->current = new TableState($this->initial->getName());
573
574
        if (!empty($status)) {
575
            $this->current->setName($status->getName());
576
            $this->current->syncState($status);
0 ignored issues
show
Documentation introduced by
$status is of type object<Spiral\Database\Schemas\TableState>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
577
        }
578
579
        return $this;
580
    }
581
582
    /**
583
     * Reset table state to it initial form.
584
     *
585
     * @return self|$this
586
     */
587
    public function resetState(): AbstractTable
588
    {
589
        $this->setStatus($this->initial);
590
591
        return $this;
592
    }
593
594
    /**
595
     * Save table schema including every column, index, foreign key creation/altering. If table
596
     * does not exist it must be created. If table declared as dropped it will be removed from
597
     * the database.
598
     *
599
     * @param int             $behaviour Operation to be performed while table being saved. In some
600
     *                                   cases (when multiple tables are being updated) it is
601
     *                                   reasonable to drop foreing keys and indexes prior to
602
     *                                   dropping related columns. See sync bus class to get more
603
     *                                   details.
604
     * @param LoggerInterface $logger    Optional, aggregates messages for data syncing.
605
     *
606
     * @throws HandlerException
607
     */
608
    public function save(int $behaviour = AbstractHandler::DO_ALL, LoggerInterface $logger = null)
609
    {
610
        //We need an instance of Handler of dbal operations
611
        $handler = $this->driver->getHandler($logger);
612
613
        if ($this->status == self::STATUS_DROPPED) {
614
            //We don't need syncer for this operation
615
            $handler->dropTable($this);
616
617
            //Flushing status
618
            $this->status = self::STATUS_NEW;
619
620
            return;
621
        }
622
623
        if ($this->status == self::STATUS_NEW) {
624
            //Executing table creation
625
            $handler->createTable($this);
626
            $this->status = self::STATUS_EXISTS;
627
        } else {
628
            //Executing table syncing
629
            if ($this->hasChanges()) {
630
                $handler->syncTable($this, $behaviour);
631
            }
632
633
            $this->status = self::STATUS_EXISTS;
634
        }
635
636
        //Syncing our schemas
637
        $this->initial->syncState($this->current);
0 ignored issues
show
Documentation introduced by
$this->current is of type object<Spiral\Database\Schemas\TableState>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
638
    }
639
640
    /**
641
     * @return AbstractColumn|string
642
     */
643
    public function __toString(): string
644
    {
645
        return $this->getName();
646
    }
647
648
    /**
649
     * @return array
650
     */
651
    public function __debugInfo()
652
    {
653
        return [
654
            'name'        => $this->getName(),
655
            'primaryKeys' => $this->getPrimaryKeys(),
656
            'columns'     => array_values($this->getColumns()),
657
            'indexes'     => array_values($this->getIndexes()),
658
            'references'  => array_values($this->getForeigns()),
659
        ];
660
    }
661
662
    /**
663
     * Populate table schema with values from database.
664
     *
665
     * @param TableState $state
666
     */
667
    protected function initSchema(TableState $state)
668
    {
669
        foreach ($this->fetchColumns() as $column) {
670
            $state->registerColumn($column);
0 ignored issues
show
Compatibility introduced by
$column of type object<Spiral\Database\Schemas\ColumnInterface> is not a sub-type of object<Spiral\Database\S...totypes\AbstractColumn>. It seems like you assume a concrete implementation of the interface Spiral\Database\Schemas\ColumnInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
671
        }
672
673
        foreach ($this->fetchIndexes() as $index) {
674
            $state->registerIndex($index);
0 ignored issues
show
Compatibility introduced by
$index of type object<Spiral\Database\Schemas\IndexInterface> is not a sub-type of object<Spiral\Database\S...ototypes\AbstractIndex>. It seems like you assume a concrete implementation of the interface Spiral\Database\Schemas\IndexInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
675
        }
676
677
        foreach ($this->fetchReferences() as $foreign) {
678
            $state->registerReference($foreign);
0 ignored issues
show
Compatibility introduced by
$foreign of type object<Spiral\Database\S...mas\ReferenceInterface> is not a sub-type of object<Spiral\Database\S...ypes\AbstractReference>. It seems like you assume a concrete implementation of the interface Spiral\Database\Schemas\ReferenceInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
679
        }
680
681
        $state->setPrimaryKeys($this->fetchPrimaryKeys());
682
683
        //DBMS specific initialization can be placed here
684
    }
685
686
    /**
687
     * Fetch index declarations from database.
688
     *
689
     * @return ColumnInterface[]
690
     */
691
    abstract protected function fetchColumns(): array;
692
693
    /**
694
     * Fetch index declarations from database.
695
     *
696
     * @return IndexInterface[]
697
     */
698
    abstract protected function fetchIndexes(): array;
699
700
    /**
701
     * Fetch references declaration from database.
702
     *
703
     * @return ReferenceInterface[]
704
     */
705
    abstract protected function fetchReferences(): array;
706
707
    /**
708
     * Fetch names of primary keys from table.
709
     *
710
     * @return array
711
     */
712
    abstract protected function fetchPrimaryKeys(): array;
713
714
    /**
715
     * Create column with a given name.
716
     *
717
     * @param string $name
718
     *
719
     * @return AbstractColumn
720
     */
721
    abstract protected function createColumn(string $name): AbstractColumn;
722
723
    /**
724
     * Create index for a given set of columns.
725
     *
726
     * @param string $name
727
     *
728
     * @return AbstractIndex
729
     */
730
    abstract protected function createIndex(string $name): AbstractIndex;
731
732
    /**
733
     * Create reference on a given column set.
734
     *
735
     * @param string $name
736
     *
737
     * @return AbstractReference
738
     */
739
    abstract protected function createForeign(string $name): AbstractReference;
740
741
    /**
742
     * Generate unique name for indexes and foreign keys.
743
     *
744
     * @param string $type
745
     * @param array  $columns
746
     *
747
     * @return string
748
     */
749
    protected function createIdentifier(string $type, array $columns): string
750
    {
751
        $name = $this->getName() . '_' . $type . '_' . join('_', $columns) . '_' . uniqid();
752
753
        if (strlen($name) > 64) {
754
            //Many DBMS has limitations on identifier length
755
            $name = md5($name);
756
        }
757
758
        return $name;
759
    }
760
761
    /**
762
     * @return ContainerInterface
763
     */
764
    protected function iocContainer()
765
    {
766
        //Falling back to driver specific container
767
        return $this->driver->iocContainer();
0 ignored issues
show
Bug introduced by
The method iocContainer() cannot be called from this context as it is declared protected in class Spiral\Core\Component.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
768
    }
769
}