Completed
Pull Request — master (#3189)
by Jarek
28:19 queued 25:37
created

AbstractSchemaManager::createView()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Doctrine\DBAL\Schema;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\ConnectionException;
7
use Doctrine\DBAL\DBALException;
8
use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs;
9
use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs;
10
use Doctrine\DBAL\Events;
11
use Doctrine\DBAL\Platforms\AbstractPlatform;
12
use Throwable;
13
use function array_filter;
14
use function array_intersect;
15
use function array_map;
16
use function array_values;
17
use function call_user_func_array;
18
use function count;
19
use function func_get_args;
20
use function is_array;
21
use function preg_match;
22
use function str_replace;
23
use function strtolower;
24
25
/**
26
 * Base class for schema managers. Schema managers are used to inspect and/or
27
 * modify the database schema/structure.
28
 */
29
abstract class AbstractSchemaManager
30
{
31
    /**
32
     * Holds instance of the Doctrine connection for this schema manager.
33
     *
34
     * @var Connection
35
     */
36
    protected $_conn;
37
38
    /**
39
     * Holds instance of the database platform used for this schema manager.
40
     *
41
     * @var AbstractPlatform
42
     */
43
    protected $_platform;
44
45
    /**
46
     * Constructor. Accepts the Connection instance to manage the schema for.
47
     */
48 1934
    public function __construct(Connection $conn, ?AbstractPlatform $platform = null)
49
    {
50 1934
        $this->_conn     = $conn;
51 1934
        $this->_platform = $platform ?: $this->_conn->getDatabasePlatform();
52 1934
    }
53
54
    /**
55
     * Returns the associated platform.
56
     *
57
     * @return AbstractPlatform
58
     */
59 559
    public function getDatabasePlatform()
60
    {
61 559
        return $this->_platform;
62
    }
63
64
    /**
65
     * Tries any method on the schema manager. Normally a method throws an
66
     * exception when your DBMS doesn't support it or if an error occurs.
67
     * This method allows you to try and method on your SchemaManager
68
     * instance and will return false if it does not work or is not supported.
69
     *
70
     * <code>
71
     * $result = $sm->tryMethod('dropView', 'view_name');
72
     * </code>
73
     *
74
     * @return mixed
75
     */
76 2827
    public function tryMethod()
77
    {
78 2827
        $args   = func_get_args();
79 2827
        $method = $args[0];
80 2827
        unset($args[0]);
81 2827
        $args = array_values($args);
82
83
        try {
84 2827
            return call_user_func_array([$this, $method], $args);
85 2136
        } catch (Throwable $e) {
86 2136
            return false;
87
        }
88
    }
89
90
    /**
91
     * Lists the available databases for this connection.
92
     *
93
     * @return string[]
94
     */
95 51
    public function listDatabases()
96
    {
97 51
        $sql = $this->_platform->getListDatabasesSQL();
98
99 50
        $databases = $this->_conn->fetchAll($sql);
100
101 50
        return $this->_getPortableDatabasesList($databases);
102
    }
103
104
    /**
105
     * Returns a list of all namespaces in the current database.
106
     *
107
     * @return string[]
108
     */
109 18
    public function listNamespaceNames()
110
    {
111 18
        $sql = $this->_platform->getListNamespacesSQL();
112
113 18
        $namespaces = $this->_conn->fetchAll($sql);
114
115 18
        return $this->getPortableNamespacesList($namespaces);
116
    }
117
118
    /**
119
     * Lists the available sequences for this connection.
120
     *
121
     * @param string|null $database
122
     *
123
     * @return Sequence[]
124
     */
125 63
    public function listSequences($database = null)
126
    {
127 63
        if ($database === null) {
128 63
            $database = $this->_conn->getDatabase();
129
        }
130 63
        $sql = $this->_platform->getListSequencesSQL($database);
131
132 63
        $sequences = $this->_conn->fetchAll($sql);
133
134 63
        return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
135
    }
136
137
    /**
138
     * Lists the columns for a given table.
139
     *
140
     * In contrast to other libraries and to the old version of Doctrine,
141
     * this column definition does try to contain the 'primary' field for
142
     * the reason that it is not portable across different RDBMS. Use
143
     * {@see listTableIndexes($tableName)} to retrieve the primary key
144
     * of a table. We're a RDBMS specifies more details these are held
145
     * in the platformDetails array.
146
     *
147
     * @param string      $table    The name of the table.
148
     * @param string|null $database
149
     *
150
     * @return Column[]
151
     */
152 1450
    public function listTableColumns($table, $database = null)
153
    {
154 1450
        if (! $database) {
155 1448
            $database = $this->_conn->getDatabase();
156
        }
157
158 1450
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
159
160 1450
        $tableColumns = $this->_conn->fetchAll($sql);
161
162 1450
        return $this->_getPortableTableColumnList($table, $database, $tableColumns);
163
    }
164
165
    /**
166
     * Lists the indexes for a given table returning an array of Index instances.
167
     *
168
     * Keys of the portable indexes list are all lower-cased.
169
     *
170
     * @param string $table The name of the table.
171
     *
172
     * @return Index[]
173
     */
174 1155
    public function listTableIndexes($table)
175
    {
176 1155
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
177
178 1155
        $tableIndexes = $this->_conn->fetchAll($sql);
179
180 1155
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
181
    }
182
183
    /**
184
     * Returns true if all the given tables exist.
185
     *
186
     * @param string[] $tableNames
187
     *
188
     * @return bool
189
     */
190 2134
    public function tablesExist($tableNames)
191
    {
192 2134
        $tableNames = array_map('strtolower', (array) $tableNames);
193
194 2134
        return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
195
    }
196
197
    /**
198
     * Returns a list of all tables in the current database.
199
     *
200
     * @return string[]
201
     */
202 2176
    public function listTableNames()
203
    {
204 2176
        $sql = $this->_platform->getListTablesSQL();
205
206 2176
        $tables     = $this->_conn->fetchAll($sql);
207 2176
        $tableNames = $this->_getPortableTablesList($tables);
208
209 2176
        return $this->filterAssetNames($tableNames);
210
    }
211
212
    /**
213
     * Filters asset names if they are configured to return only a subset of all
214
     * the found elements.
215
     *
216
     * @param mixed[] $assetNames
217
     *
218
     * @return mixed[]
219
     */
220 2239
    protected function filterAssetNames($assetNames)
221
    {
222 2239
        $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
223 2239
        if (! $filter) {
224 2239
            return $assetNames;
225
        }
226
227 7
        return array_values(array_filter($assetNames, $filter));
228
    }
229
230
    /**
231
     * @deprecated Use Configuration::getSchemaAssetsFilter() instead
232
     *
233
     * @return string|null
234
     */
235
    protected function getFilterSchemaAssetsExpression()
236
    {
237
        return $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression();
1 ignored issue
show
Deprecated Code introduced by
The function Doctrine\DBAL\Configurat...chemaAssetsExpression() has been deprecated: Use Configuration::getSchemaAssetsFilter() instead ( Ignorable by Annotation )

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

237
        return /** @scrutinizer ignore-deprecated */ $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression();

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...
238
    }
239
240
    /**
241
     * Lists the tables for this connection.
242
     *
243
     * @return Table[]
244
     */
245 158
    public function listTables()
246
    {
247 158
        $tableNames = $this->listTableNames();
248
249 158
        $tables = [];
250 158
        foreach ($tableNames as $tableName) {
251 131
            $tables[] = $this->listTableDetails($tableName);
252
        }
253
254 158
        return $tables;
255
    }
256
257
    /**
258
     * @param string $tableName
259
     *
260
     * @return Table
261
     */
262 1052
    public function listTableDetails($tableName)
263
    {
264 1052
        $columns     = $this->listTableColumns($tableName);
265 1052
        $foreignKeys = [];
266 1052
        if ($this->_platform->supportsForeignKeyConstraints()) {
267 969
            $foreignKeys = $this->listTableForeignKeys($tableName);
268
        }
269 1052
        $indexes = $this->listTableIndexes($tableName);
270
271 1052
        return new Table($tableName, $columns, $indexes, $foreignKeys);
272
    }
273
274
    /**
275
     * Lists the views this connection has.
276
     *
277
     * @return View[]
278
     */
279 27
    public function listViews()
280
    {
281 27
        $database = $this->_conn->getDatabase();
282 27
        $sql      = $this->_platform->getListViewsSQL($database);
283 27
        $views    = $this->_conn->fetchAll($sql);
284
285 27
        return $this->_getPortableViewsList($views);
286
    }
287
288
    /**
289
     * Lists the foreign keys for the given table.
290
     *
291
     * @param string      $table    The name of the table.
292
     * @param string|null $database
293
     *
294
     * @return ForeignKeyConstraint[]
295
     */
296 1057
    public function listTableForeignKeys($table, $database = null)
297
    {
298 1057
        if ($database === null) {
299 1057
            $database = $this->_conn->getDatabase();
300
        }
301 1057
        $sql              = $this->_platform->getListTableForeignKeysSQL($table, $database);
0 ignored issues
show
Unused Code introduced by
The call to Doctrine\DBAL\Platforms\...stTableForeignKeysSQL() has too many arguments starting with $database. ( Ignorable by Annotation )

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

301
        /** @scrutinizer ignore-call */ 
302
        $sql              = $this->_platform->getListTableForeignKeysSQL($table, $database);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
302 1057
        $tableForeignKeys = $this->_conn->fetchAll($sql);
303
304 1057
        return $this->_getPortableTableForeignKeysList($tableForeignKeys);
305
    }
306
307
    /* drop*() Methods */
308
309
    /**
310
     * Drops a database.
311
     *
312
     * NOTE: You can not drop the database this SchemaManager is currently connected to.
313
     *
314
     * @param string $database The name of the database to drop.
315
     *
316
     * @return void
317
     */
318 50
    public function dropDatabase($database)
319
    {
320 50
        $this->_execSql($this->_platform->getDropDatabaseSQL($database));
321 35
    }
322
323
    /**
324
     * Drops the given table.
325
     *
326
     * @param string $tableName The name of the table to drop.
327
     *
328
     * @return void
329
     */
330 3211
    public function dropTable($tableName)
331
    {
332 3211
        $this->_execSql($this->_platform->getDropTableSQL($tableName));
333 1525
    }
334
335
    /**
336
     * Drops the index from the given table.
337
     *
338
     * @param Index|string $index The name of the index.
339
     * @param Table|string $table The name of the table.
340
     *
341
     * @return void
342
     */
343 27
    public function dropIndex($index, $table)
344
    {
345 27
        if ($index instanceof Index) {
346
            $index = $index->getQuotedName($this->_platform);
347
        }
348
349 27
        $this->_execSql($this->_platform->getDropIndexSQL($index, $table));
350 27
    }
351
352
    /**
353
     * Drops the constraint from the given table.
354
     *
355
     * @param Table|string $table The name of the table.
356
     *
357
     * @return void
358
     */
359
    public function dropConstraint(Constraint $constraint, $table)
360
    {
361
        $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table));
362
    }
363
364
    /**
365
     * Drops a foreign key from a table.
366
     *
367
     * @param ForeignKeyConstraint|string $foreignKey The name of the foreign key.
368
     * @param Table|string                $table      The name of the table with the foreign key.
369
     *
370
     * @return void
371
     */
372
    public function dropForeignKey($foreignKey, $table)
373
    {
374
        $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table));
375
    }
376
377
    /**
378
     * Drops a sequence with a given name.
379
     *
380
     * @param string $name The name of the sequence to drop.
381
     *
382
     * @return void
383
     */
384 22
    public function dropSequence($name)
385
    {
386 22
        $this->_execSql($this->_platform->getDropSequenceSQL($name));
387
    }
388
389
    /**
390
     * Drops a view.
391
     *
392
     * @param string $name The name of the view.
393
     *
394
     * @return void
395
     */
396 34
    public function dropView($name)
397
    {
398 34
        $this->_execSql($this->_platform->getDropViewSQL($name));
399
    }
400
401
    /* create*() Methods */
402
403
    /**
404
     * Creates a new database.
405
     *
406
     * @param string $database The name of the database to create.
407
     *
408
     * @return void
409
     */
410 46
    public function createDatabase($database)
411
    {
412 46
        $this->_execSql($this->_platform->getCreateDatabaseSQL($database));
413 46
    }
414
415
    /**
416
     * Creates a new table.
417
     *
418
     * @return void
419
     */
420 4104
    public function createTable(Table $table)
421
    {
422 4104
        $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS;
423 4104
        $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
424 3078
    }
425
426
    /**
427
     * Creates a new sequence.
428
     *
429
     * @param Sequence $sequence
430
     *
431
     * @return void
432
     *
433
     * @throws ConnectionException If something fails at database level.
434
     */
435 52
    public function createSequence($sequence)
436
    {
437 52
        $this->_execSql($this->_platform->getCreateSequenceSQL($sequence));
438 45
    }
439
440
    /**
441
     * Creates a constraint on a table.
442
     *
443
     * @param Table|string $table
444
     *
445
     * @return void
446
     */
447 2
    public function createConstraint(Constraint $constraint, $table)
448
    {
449 2
        $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table));
450 2
    }
451
452
    /**
453
     * Creates a new index on a table.
454
     *
455
     * @param Table|string $table The name of the table on which the index is to be created.
456
     *
457
     * @return void
458
     */
459 27
    public function createIndex(Index $index, $table)
460
    {
461 27
        $this->_execSql($this->_platform->getCreateIndexSQL($index, $table));
462 27
    }
463
464
    /**
465
     * Creates a new foreign key.
466
     *
467
     * @param ForeignKeyConstraint $foreignKey The ForeignKey instance.
468
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
469
     *
470
     * @return void
471
     */
472 52
    public function createForeignKey(ForeignKeyConstraint $foreignKey, $table)
473
    {
474 52
        $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table));
475 52
    }
476
477
    /**
478
     * Creates a new view.
479
     *
480
     * @return void
481
     */
482 34
    public function createView(View $view)
483
    {
484 34
        $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql()));
485 34
    }
486
487
    /* dropAndCreate*() Methods */
488
489
    /**
490
     * Drops and creates a constraint.
491
     *
492
     * @see dropConstraint()
493
     * @see createConstraint()
494
     *
495
     * @param Table|string $table
496
     *
497
     * @return void
498
     */
499
    public function dropAndCreateConstraint(Constraint $constraint, $table)
500
    {
501
        $this->tryMethod('dropConstraint', $constraint, $table);
502
        $this->createConstraint($constraint, $table);
503
    }
504
505
    /**
506
     * Drops and creates a new index on a table.
507
     *
508
     * @param Table|string $table The name of the table on which the index is to be created.
509
     *
510
     * @return void
511
     */
512 27
    public function dropAndCreateIndex(Index $index, $table)
513
    {
514 27
        $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table);
515 27
        $this->createIndex($index, $table);
516 27
    }
517
518
    /**
519
     * Drops and creates a new foreign key.
520
     *
521
     * @param ForeignKeyConstraint $foreignKey An associative array that defines properties of the foreign key to be created.
522
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
523
     *
524
     * @return void
525
     */
526
    public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table)
527
    {
528
        $this->tryMethod('dropForeignKey', $foreignKey, $table);
529
        $this->createForeignKey($foreignKey, $table);
530
    }
531
532
    /**
533
     * Drops and create a new sequence.
534
     *
535
     * @return void
536
     *
537
     * @throws ConnectionException If something fails at database level.
538
     */
539 22
    public function dropAndCreateSequence(Sequence $sequence)
540
    {
541 22
        $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform));
542 22
        $this->createSequence($sequence);
543 22
    }
544
545
    /**
546
     * Drops and creates a new table.
547
     *
548
     * @return void
549
     */
550 1935
    public function dropAndCreateTable(Table $table)
551
    {
552 1935
        $this->tryMethod('dropTable', $table->getQuotedName($this->_platform));
553 1935
        $this->createTable($table);
554 1935
    }
555
556
    /**
557
     * Drops and creates a new database.
558
     *
559
     * @param string $database The name of the database to create.
560
     *
561
     * @return void
562
     */
563 51
    public function dropAndCreateDatabase($database)
564
    {
565 51
        $this->tryMethod('dropDatabase', $database);
566 51
        $this->createDatabase($database);
567 51
    }
568
569
    /**
570
     * Drops and creates a new view.
571
     *
572
     * @return void
573
     */
574 34
    public function dropAndCreateView(View $view)
575
    {
576 34
        $this->tryMethod('dropView', $view->getQuotedName($this->_platform));
577 34
        $this->createView($view);
578 34
    }
579
580
    /* alterTable() Methods */
581
582
    /**
583
     * Alters an existing tables schema.
584
     *
585
     * @return void
586
     */
587 508
    public function alterTable(TableDiff $tableDiff)
588
    {
589 508
        $queries = $this->_platform->getAlterTableSQL($tableDiff);
590 508
        if (! is_array($queries) || ! count($queries)) {
591 10
            return;
592
        }
593
594 498
        foreach ($queries as $ddlQuery) {
595 498
            $this->_execSql($ddlQuery);
596
        }
597 498
    }
598
599
    /**
600
     * Renames a given table to another name.
601
     *
602
     * @param string $name    The current name of the table.
603
     * @param string $newName The new name of the table.
604
     *
605
     * @return void
606
     */
607 2
    public function renameTable($name, $newName)
608
    {
609 2
        $tableDiff          = new TableDiff($name);
610 2
        $tableDiff->newName = $newName;
611 2
        $this->alterTable($tableDiff);
612 2
    }
613
614
    /**
615
     * Methods for filtering return values of list*() methods to convert
616
     * the native DBMS data definition to a portable Doctrine definition
617
     */
618
619
    /**
620
     * @param mixed[] $databases
621
     *
622
     * @return string[]
623
     */
624 50
    protected function _getPortableDatabasesList($databases)
625
    {
626 50
        $list = [];
627 50
        foreach ($databases as $value) {
628 50
            $value = $this->_getPortableDatabaseDefinition($value);
629
630 50
            if (! $value) {
631
                continue;
632
            }
633
634 50
            $list[] = $value;
635
        }
636
637 50
        return $list;
638
    }
639
640
    /**
641
     * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition.
642
     *
643
     * @param mixed[][] $namespaces The list of namespace names in the native DBMS data definition.
644
     *
645
     * @return string[]
646
     */
647 18
    protected function getPortableNamespacesList(array $namespaces)
648
    {
649 18
        $namespacesList = [];
650
651 18
        foreach ($namespaces as $namespace) {
652 18
            $namespacesList[] = $this->getPortableNamespaceDefinition($namespace);
653
        }
654
655 18
        return $namespacesList;
656
    }
657
658
    /**
659
     * @param mixed $database
660
     *
661
     * @return mixed
662
     */
663
    protected function _getPortableDatabaseDefinition($database)
664
    {
665
        return $database;
666
    }
667
668
    /**
669
     * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition.
670
     *
671
     * @param mixed[] $namespace The native DBMS namespace definition.
672
     *
673
     * @return mixed
674
     */
675
    protected function getPortableNamespaceDefinition(array $namespace)
676
    {
677
        return $namespace;
678
    }
679
680
    /**
681
     * @param mixed[][] $functions
682
     *
683
     * @return mixed[][]
684
     */
685
    protected function _getPortableFunctionsList($functions)
686
    {
687
        $list = [];
688
        foreach ($functions as $value) {
689
            $value = $this->_getPortableFunctionDefinition($value);
690
691
            if (! $value) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $value of type array<mixed,mixed> is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
692
                continue;
693
            }
694
695
            $list[] = $value;
696
        }
697
698
        return $list;
699
    }
700
701
    /**
702
     * @param mixed[] $function
703
     *
704
     * @return mixed
705
     */
706
    protected function _getPortableFunctionDefinition($function)
707
    {
708
        return $function;
709
    }
710
711
    /**
712
     * @param mixed[][] $triggers
713
     *
714
     * @return mixed[][]
715
     */
716
    protected function _getPortableTriggersList($triggers)
717
    {
718
        $list = [];
719
        foreach ($triggers as $value) {
720
            $value = $this->_getPortableTriggerDefinition($value);
721
722
            if (! $value) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $value of type array<mixed,mixed> is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
723
                continue;
724
            }
725
726
            $list[] = $value;
727
        }
728
729
        return $list;
730
    }
731
732
    /**
733
     * @param mixed[] $trigger
734
     *
735
     * @return mixed
736
     */
737
    protected function _getPortableTriggerDefinition($trigger)
738
    {
739
        return $trigger;
740
    }
741
742
    /**
743
     * @param mixed[][] $sequences
744
     *
745
     * @return Sequence[]
746
     */
747 21
    protected function _getPortableSequencesList($sequences)
748
    {
749 21
        $list = [];
750
751 21
        foreach ($sequences as $value) {
752 21
            $list[] = $this->_getPortableSequenceDefinition($value);
753
        }
754
755 21
        return $list;
756
    }
757
758
    /**
759
     * @param mixed[] $sequence
760
     *
761
     * @return Sequence
762
     *
763
     * @throws DBALException
764
     */
765
    protected function _getPortableSequenceDefinition($sequence)
766
    {
767
        throw DBALException::notSupported('Sequences');
768
    }
769
770
    /**
771
     * Independent of the database the keys of the column list result are lowercased.
772
     *
773
     * The name of the created column instance however is kept in its case.
774
     *
775
     * @param string    $table        The name of the table.
776
     * @param string    $database
777
     * @param mixed[][] $tableColumns
778
     *
779
     * @return Column[]
780
     */
781 1450
    protected function _getPortableTableColumnList($table, $database, $tableColumns)
782
    {
783 1450
        $eventManager = $this->_platform->getEventManager();
784
785 1450
        $list = [];
786 1450
        foreach ($tableColumns as $tableColumn) {
787 1436
            $column           = null;
788 1436
            $defaultPrevented = false;
789
790 1436
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) {
791 27
                $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn);
792 27
                $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs);
793
794 27
                $defaultPrevented = $eventArgs->isDefaultPrevented();
795 27
                $column           = $eventArgs->getColumn();
796
            }
797
798 1436
            if (! $defaultPrevented) {
799 1436
                $column = $this->_getPortableTableColumnDefinition($tableColumn);
800
            }
801
802 1436
            if (! $column) {
803
                continue;
804
            }
805
806 1436
            $name        = strtolower($column->getQuotedName($this->_platform));
807 1436
            $list[$name] = $column;
808
        }
809
810 1450
        return $list;
811
    }
812
813
    /**
814
     * Gets Table Column Definition.
815
     *
816
     * @param mixed[] $tableColumn
817
     *
818
     * @return Column
819
     */
820
    abstract protected function _getPortableTableColumnDefinition($tableColumn);
821
822
    /**
823
     * Aggregates and groups the index results according to the required data result.
824
     *
825
     * @param mixed[][]   $tableIndexRows
826
     * @param string|null $tableName
827
     *
828
     * @return Index[]
829
     */
830 1215
    protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null)
831
    {
832 1215
        $result = [];
833 1215
        foreach ($tableIndexRows as $tableIndex) {
834 662
            $indexName = $keyName = $tableIndex['key_name'];
835 662
            if ($tableIndex['primary']) {
836 547
                $keyName = 'primary';
837
            }
838 662
            $keyName = strtolower($keyName);
839
840 662
            if (! isset($result[$keyName])) {
841
                $options = [
842 662
                    'lengths' => [],
843
                ];
844
845 662
                if (isset($tableIndex['where'])) {
846 21
                    $options['where'] = $tableIndex['where'];
847
                }
848
849 662
                $result[$keyName] = [
850 662
                    'name' => $indexName,
851
                    'columns' => [],
852 662
                    'unique' => $tableIndex['non_unique'] ? false : true,
853 662
                    'primary' => $tableIndex['primary'],
854 662
                    'flags' => $tableIndex['flags'] ?? [],
855 662
                    'options' => $options,
856
                ];
857
            }
858
859 662
            $result[$keyName]['columns'][]            = $tableIndex['column_name'];
860 662
            $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null;
861
        }
862
863 1215
        $eventManager = $this->_platform->getEventManager();
864
865 1215
        $indexes = [];
866 1215
        foreach ($result as $indexKey => $data) {
867 662
            $index            = null;
868 662
            $defaultPrevented = false;
869
870 662
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
871 27
                $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
872 27
                $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
873
874 27
                $defaultPrevented = $eventArgs->isDefaultPrevented();
875 27
                $index            = $eventArgs->getIndex();
876
            }
877
878 662
            if (! $defaultPrevented) {
879 662
                $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary'], $data['flags'], $data['options']);
880
            }
881
882 662
            if (! $index) {
883
                continue;
884
            }
885
886 662
            $indexes[$indexKey] = $index;
887
        }
888
889 1215
        return $indexes;
890
    }
891
892
    /**
893
     * @param mixed[][] $tables
894
     *
895
     * @return string[]
896
     */
897 2176
    protected function _getPortableTablesList($tables)
898
    {
899 2176
        $list = [];
900 2176
        foreach ($tables as $value) {
901 2149
            $value = $this->_getPortableTableDefinition($value);
902
903 2149
            if (! $value) {
904
                continue;
905
            }
906
907 2149
            $list[] = $value;
908
        }
909
910 2176
        return $list;
911
    }
912
913
    /**
914
     * @param mixed $table
915
     *
916
     * @return string
917
     */
918
    protected function _getPortableTableDefinition($table)
919
    {
920
        return $table;
921
    }
922
923
    /**
924
     * @param mixed[][] $users
925
     *
926
     * @return string[][]
927
     */
928
    protected function _getPortableUsersList($users)
929
    {
930
        $list = [];
931
        foreach ($users as $value) {
932
            $value = $this->_getPortableUserDefinition($value);
933
934
            if (! $value) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $value of type array<mixed,mixed> is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
935
                continue;
936
            }
937
938
            $list[] = $value;
939
        }
940
941
        return $list;
942
    }
943
944
    /**
945
     * @param mixed[] $user
946
     *
947
     * @return mixed[]
948
     */
949
    protected function _getPortableUserDefinition($user)
950
    {
951
        return $user;
952
    }
953
954
    /**
955
     * @param mixed[][] $views
956
     *
957
     * @return View[]
958
     */
959 27
    protected function _getPortableViewsList($views)
960
    {
961 27
        $list = [];
962 27
        foreach ($views as $value) {
963 27
            $view = $this->_getPortableViewDefinition($value);
964
965 27
            if (! $view) {
966
                continue;
967
            }
968
969 27
            $viewName        = strtolower($view->getQuotedName($this->_platform));
970 27
            $list[$viewName] = $view;
971
        }
972
973 27
        return $list;
974
    }
975
976
    /**
977
     * @param mixed[] $view
978
     *
979
     * @return View|false
980
     */
981
    protected function _getPortableViewDefinition($view)
982
    {
983
        return false;
984
    }
985
986
    /**
987
     * @param mixed[][] $tableForeignKeys
988
     *
989
     * @return ForeignKeyConstraint[]
990
     */
991 394
    protected function _getPortableTableForeignKeysList($tableForeignKeys)
992
    {
993 394
        $list = [];
994
995 394
        foreach ($tableForeignKeys as $value) {
996 121
            $list[] = $this->_getPortableTableForeignKeyDefinition($value);
997
        }
998
999 394
        return $list;
1000
    }
1001
1002
    /**
1003
     * @param mixed $tableForeignKey
1004
     *
1005
     * @return ForeignKeyConstraint
1006
     */
1007
    protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
1008
    {
1009
        return $tableForeignKey;
1010
    }
1011
1012
    /**
1013
     * @param string[]|string $sql
1014
     *
1015
     * @return void
1016
     */
1017 4530
    protected function _execSql($sql)
1018
    {
1019 4530
        foreach ((array) $sql as $query) {
1020 4530
            $this->_conn->executeUpdate($query);
1021
        }
1022 3204
    }
1023
1024
    /**
1025
     * Creates a schema instance for the current database.
1026
     *
1027
     * @return Schema
1028
     */
1029 122
    public function createSchema()
1030
    {
1031 122
        $namespaces = [];
1032
1033 122
        if ($this->_platform->supportsSchemas()) {
1034 9
            $namespaces = $this->listNamespaceNames();
1035
        }
1036
1037 122
        $sequences = [];
1038
1039 122
        if ($this->_platform->supportsSequences()) {
1040 11
            $sequences = $this->listSequences();
1041
        }
1042
1043 122
        $tables = $this->listTables();
1044
1045 122
        return new Schema($tables, $sequences, $this->createSchemaConfig(), $namespaces);
1046
    }
1047
1048
    /**
1049
     * Creates the configuration for this schema.
1050
     *
1051
     * @return SchemaConfig
1052
     */
1053 486
    public function createSchemaConfig()
1054
    {
1055 486
        $schemaConfig = new SchemaConfig();
1056 486
        $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
1057
1058 486
        $searchPaths = $this->getSchemaSearchPaths();
1059 486
        if (isset($searchPaths[0])) {
1060 368
            $schemaConfig->setName($searchPaths[0]);
1061
        }
1062
1063 486
        $params = $this->_conn->getParams();
1064 486
        if (! isset($params['defaultTableOptions'])) {
1065 486
            $params['defaultTableOptions'] = [];
1066
        }
1067 486
        if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) {
1068 27
            $params['defaultTableOptions']['charset'] = $params['charset'];
1069
        }
1070 486
        $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']);
1071
1072 486
        return $schemaConfig;
1073
    }
1074
1075
    /**
1076
     * The search path for namespaces in the currently connected database.
1077
     *
1078
     * The first entry is usually the default namespace in the Schema. All
1079
     * further namespaces contain tables/sequences which can also be addressed
1080
     * with a short, not full-qualified name.
1081
     *
1082
     * For databases that don't support subschema/namespaces this method
1083
     * returns the name of the currently connected database.
1084
     *
1085
     * @return string[]
1086
     */
1087 381
    public function getSchemaSearchPaths()
1088
    {
1089 381
        return [$this->_conn->getDatabase()];
1090
    }
1091
1092
    /**
1093
     * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns
1094
     * the type given as default.
1095
     *
1096
     * @param string $comment
1097
     * @param string $currentType
1098
     *
1099
     * @return string
1100
     */
1101 1534
    public function extractDoctrineTypeFromComment($comment, $currentType)
1102
    {
1103 1534
        if (preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match)) {
1104 309
            $currentType = $match[1];
1105
        }
1106
1107 1534
        return $currentType;
1108
    }
1109
1110
    /**
1111
     * @param string $comment
1112
     * @param string $type
1113
     *
1114
     * @return string
1115
     */
1116 1360
    public function removeDoctrineTypeFromComment($comment, $type)
1117
    {
1118 1360
        return str_replace('(DC2Type:' . $type . ')', '', $comment);
1119
    }
1120
}
1121