Completed
Pull Request — 2.9 (#3692)
by
unknown
61:17 queued 10s
created

AbstractSchemaManager::listAllTableNames()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 3
c 2
b 0
f 0
dl 0
loc 7
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
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 543
    public function getDatabasePlatform()
60
    {
61 543
        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 2808
    public function tryMethod()
77
    {
78 2808
        $args   = func_get_args();
79 2808
        $method = $args[0];
80 2808
        unset($args[0]);
81 2808
        $args = array_values($args);
82
83
        try {
84 2808
            return call_user_func_array([$this, $method], $args);
85 2095
        } catch (Throwable $e) {
86 2095
            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 1394
    public function listTableColumns($table, $database = null)
153
    {
154 1394
        if (! $database) {
155 1392
            $database = $this->_conn->getDatabase();
156
        }
157
158 1394
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
159
160 1394
        $tableColumns = $this->_conn->fetchAll($sql);
161
162 1394
        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 1113
    public function listTableIndexes($table)
175
    {
176 1113
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
177
178 1113
        $tableIndexes = $this->_conn->fetchAll($sql);
179
180 1113
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
181
    }
182
183
    /**
184
     * Returns true if all the given tables exist.
185
     *
186
     * To avoid BC-break not all parameters are included.
187
     *
188
     * @param string|string[] $tableNames
189
     * @param bool            $filtered   Optional parameter, if false ignores filters.
190 2078
     *
191
     * @return bool
192 2078
     */
193
    public function tablesExist($tableNames)
194 2078
    {
195
        $tableNames = array_map('strtolower', (array) $tableNames);
196
197
        $args = func_get_args();
198
199
        $tables = count($args) > 1 && ! $args[1] ? $this->listAllTableNames() : $this->listTableNames();
200
201
        return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $tables)));
202 2106
    }
203
204 2106
    /**
205
     * Returns a filtered list of all tables in the current database.
206 2106
     *
207 2106
     * @return string[]
208
     */
209 2106
    public function listTableNames()
210
    {
211
        $sql = $this->_platform->getListTablesSQL();
212
213
        $tables     = $this->_conn->fetchAll($sql);
214
        $tableNames = $this->_getPortableTablesList($tables);
215
216
        return $this->filterAssetNames($tableNames);
217
    }
218
219
    /**
220 2169
     * Returns a list of all tables in the current database.
221
     *
222 2169
     * @return string[]
223 2169
     */
224 2169
    final public function listAllTableNames(): iterable
225
    {
226
        $sql = $this->_platform->getListTablesSQL();
227 7
228
        $tables = $this->_conn->fetchAll($sql);
229
230
        return $this->_getPortableTablesList($tables);
231
    }
232
233
    /**
234
     * Filters asset names if they are configured to return only a subset of all
235
     * the found elements.
236
     *
237
     * @param mixed[] $assetNames
238
     *
239
     * @return mixed[]
240
     */
241
    protected function filterAssetNames($assetNames)
242
    {
243
        $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
244
        if (! $filter) {
245 144
            return $assetNames;
246
        }
247 144
248
        return array_values(array_filter($assetNames, $filter));
249 144
    }
250 144
251 117
    /**
252
     * @deprecated Use Configuration::getSchemaAssetsFilter() instead
253
     *
254 144
     * @return string|null
255
     */
256
    protected function getFilterSchemaAssetsExpression()
257
    {
258
        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

258
        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...
259
    }
260
261
    /**
262 1010
     * Lists the tables for this connection.
263
     *
264 1010
     * @return Table[]
265 1010
     */
266 1010
    public function listTables()
267 927
    {
268
        $tableNames = $this->listTableNames();
269 1010
270
        $tables = [];
271 1010
        foreach ($tableNames as $tableName) {
272
            $tables[] = $this->listTableDetails($tableName);
273
        }
274
275
        return $tables;
276
    }
277
278
    /**
279 27
     * @param string $tableName
280
     *
281 27
     * @return Table
282 27
     */
283 27
    public function listTableDetails($tableName)
284
    {
285 27
        $columns     = $this->listTableColumns($tableName);
286
        $foreignKeys = [];
287
        if ($this->_platform->supportsForeignKeyConstraints()) {
288
            $foreignKeys = $this->listTableForeignKeys($tableName);
289
        }
290
        $indexes = $this->listTableIndexes($tableName);
291
292
        return new Table($tableName, $columns, $indexes, $foreignKeys, false, []);
293
    }
294
295
    /**
296 1015
     * Lists the views this connection has.
297
     *
298 1015
     * @return View[]
299 1015
     */
300
    public function listViews()
301 1015
    {
302 1015
        $database = $this->_conn->getDatabase();
303
        $sql      = $this->_platform->getListViewsSQL($database);
304 1015
        $views    = $this->_conn->fetchAll($sql);
305
306
        return $this->_getPortableViewsList($views);
307
    }
308
309
    /**
310
     * Lists the foreign keys for the given table.
311
     *
312
     * @param string      $table    The name of the table.
313
     * @param string|null $database
314
     *
315
     * @return ForeignKeyConstraint[]
316
     */
317
    public function listTableForeignKeys($table, $database = null)
318 50
    {
319
        if ($database === null) {
320 50
            $database = $this->_conn->getDatabase();
321 35
        }
322
        $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

322
        /** @scrutinizer ignore-call */ 
323
        $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...
323
        $tableForeignKeys = $this->_conn->fetchAll($sql);
324
325
        return $this->_getPortableTableForeignKeysList($tableForeignKeys);
326
    }
327
328
    /* drop*() Methods */
329
330 3192
    /**
331
     * Drops a database.
332 3192
     *
333 1549
     * NOTE: You can not drop the database this SchemaManager is currently connected to.
334
     *
335
     * @param string $database The name of the database to drop.
336
     *
337
     * @return void
338
     */
339
    public function dropDatabase($database)
340
    {
341
        $this->_execSql($this->_platform->getDropDatabaseSQL($database));
342
    }
343 27
344
    /**
345 27
     * Drops the given table.
346
     *
347
     * @param string $tableName The name of the table to drop.
348
     *
349 27
     * @return void
350 27
     */
351
    public function dropTable($tableName)
352
    {
353
        $this->_execSql($this->_platform->getDropTableSQL($tableName));
354
    }
355
356
    /**
357
     * Drops the index from the given table.
358
     *
359
     * @param Index|string $index The name of the index.
360
     * @param Table|string $table The name of the table.
361
     *
362
     * @return void
363
     */
364
    public function dropIndex($index, $table)
365
    {
366
        if ($index instanceof Index) {
367
            $index = $index->getQuotedName($this->_platform);
368
        }
369
370
        $this->_execSql($this->_platform->getDropIndexSQL($index, $table));
371
    }
372
373
    /**
374
     * Drops the constraint from the given table.
375
     *
376
     * @param Table|string $table The name of the table.
377
     *
378
     * @return void
379
     */
380
    public function dropConstraint(Constraint $constraint, $table)
381
    {
382
        $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table));
383
    }
384 22
385
    /**
386 22
     * Drops a foreign key from a table.
387
     *
388
     * @param ForeignKeyConstraint|string $foreignKey The name of the foreign key.
389
     * @param Table|string                $table      The name of the table with the foreign key.
390
     *
391
     * @return void
392
     */
393
    public function dropForeignKey($foreignKey, $table)
394
    {
395
        $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table));
396 34
    }
397
398 34
    /**
399
     * Drops a sequence with a given name.
400
     *
401
     * @param string $name The name of the sequence to drop.
402
     *
403
     * @return void
404
     */
405
    public function dropSequence($name)
406
    {
407
        $this->_execSql($this->_platform->getDropSequenceSQL($name));
408
    }
409
410 46
    /**
411
     * Drops a view.
412 46
     *
413 46
     * @param string $name The name of the view.
414
     *
415
     * @return void
416
     */
417
    public function dropView($name)
418
    {
419
        $this->_execSql($this->_platform->getDropViewSQL($name));
420 4099
    }
421
422 4099
    /* create*() Methods */
423 4099
424 3073
    /**
425
     * Creates a new database.
426
     *
427
     * @param string $database The name of the database to create.
428
     *
429
     * @return void
430
     */
431
    public function createDatabase($database)
432
    {
433
        $this->_execSql($this->_platform->getCreateDatabaseSQL($database));
434
    }
435 52
436
    /**
437 52
     * Creates a new table.
438 45
     *
439
     * @return void
440
     */
441
    public function createTable(Table $table)
442
    {
443
        $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS;
444
        $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
445
    }
446
447 2
    /**
448
     * Creates a new sequence.
449 2
     *
450 2
     * @param Sequence $sequence
451
     *
452
     * @return void
453
     *
454
     * @throws ConnectionException If something fails at database level.
455
     */
456
    public function createSequence($sequence)
457
    {
458
        $this->_execSql($this->_platform->getCreateSequenceSQL($sequence));
459 27
    }
460
461 27
    /**
462 27
     * Creates a constraint on a table.
463
     *
464
     * @param Table|string $table
465
     *
466
     * @return void
467
     */
468
    public function createConstraint(Constraint $constraint, $table)
469
    {
470
        $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table));
471
    }
472 52
473
    /**
474 52
     * Creates a new index on a table.
475 52
     *
476
     * @param Table|string $table The name of the table on which the index is to be created.
477
     *
478
     * @return void
479
     */
480
    public function createIndex(Index $index, $table)
481
    {
482 34
        $this->_execSql($this->_platform->getCreateIndexSQL($index, $table));
483
    }
484 34
485 34
    /**
486
     * Creates a new foreign key.
487
     *
488
     * @param ForeignKeyConstraint $foreignKey The ForeignKey instance.
489
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
490
     *
491
     * @return void
492
     */
493
    public function createForeignKey(ForeignKeyConstraint $foreignKey, $table)
494
    {
495
        $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table));
496
    }
497
498
    /**
499
     * Creates a new view.
500
     *
501
     * @return void
502
     */
503
    public function createView(View $view)
504
    {
505
        $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql()));
506
    }
507
508
    /* dropAndCreate*() Methods */
509
510
    /**
511
     * Drops and creates a constraint.
512 27
     *
513
     * @see dropConstraint()
514 27
     * @see createConstraint()
515 27
     *
516 27
     * @param Table|string $table
517
     *
518
     * @return void
519
     */
520
    public function dropAndCreateConstraint(Constraint $constraint, $table)
521
    {
522
        $this->tryMethod('dropConstraint', $constraint, $table);
523
        $this->createConstraint($constraint, $table);
524
    }
525
526
    /**
527
     * Drops and creates a new index on a table.
528
     *
529
     * @param Table|string $table The name of the table on which the index is to be created.
530
     *
531
     * @return void
532
     */
533
    public function dropAndCreateIndex(Index $index, $table)
534
    {
535
        $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table);
536
        $this->createIndex($index, $table);
537
    }
538
539 22
    /**
540
     * Drops and creates a new foreign key.
541 22
     *
542 22
     * @param ForeignKeyConstraint $foreignKey An associative array that defines properties of the foreign key to be created.
543 22
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
544
     *
545
     * @return void
546
     */
547
    public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table)
548
    {
549
        $this->tryMethod('dropForeignKey', $foreignKey, $table);
550 1930
        $this->createForeignKey($foreignKey, $table);
551
    }
552 1930
553 1930
    /**
554 1930
     * Drops and create a new sequence.
555
     *
556
     * @return void
557
     *
558
     * @throws ConnectionException If something fails at database level.
559
     */
560
    public function dropAndCreateSequence(Sequence $sequence)
561
    {
562
        $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform));
563 51
        $this->createSequence($sequence);
564
    }
565 51
566 51
    /**
567 51
     * Drops and creates a new table.
568
     *
569
     * @return void
570
     */
571
    public function dropAndCreateTable(Table $table)
572
    {
573
        $this->tryMethod('dropTable', $table->getQuotedName($this->_platform));
574 34
        $this->createTable($table);
575
    }
576 34
577 34
    /**
578 34
     * Drops and creates a new database.
579
     *
580
     * @param string $database The name of the database to create.
581
     *
582
     * @return void
583
     */
584
    public function dropAndCreateDatabase($database)
585
    {
586
        $this->tryMethod('dropDatabase', $database);
587 494
        $this->createDatabase($database);
588
    }
589 494
590 494
    /**
591 10
     * Drops and creates a new view.
592
     *
593
     * @return void
594 484
     */
595 484
    public function dropAndCreateView(View $view)
596
    {
597 484
        $this->tryMethod('dropView', $view->getQuotedName($this->_platform));
598
        $this->createView($view);
599
    }
600
601
    /* alterTable() Methods */
602
603
    /**
604
     * Alters an existing tables schema.
605
     *
606
     * @return void
607 2
     */
608
    public function alterTable(TableDiff $tableDiff)
609 2
    {
610 2
        $queries = $this->_platform->getAlterTableSQL($tableDiff);
611 2
        if (! is_array($queries) || ! count($queries)) {
612 2
            return;
613
        }
614
615
        foreach ($queries as $ddlQuery) {
616
            $this->_execSql($ddlQuery);
617
        }
618
    }
619
620
    /**
621
     * Renames a given table to another name.
622
     *
623
     * @param string $name    The current name of the table.
624 50
     * @param string $newName The new name of the table.
625
     *
626 50
     * @return void
627 50
     */
628 50
    public function renameTable($name, $newName)
629
    {
630 50
        $tableDiff          = new TableDiff($name);
631
        $tableDiff->newName = $newName;
632
        $this->alterTable($tableDiff);
633
    }
634 50
635
    /**
636
     * Methods for filtering return values of list*() methods to convert
637 50
     * the native DBMS data definition to a portable Doctrine definition
638
     */
639
640
    /**
641
     * @param mixed[] $databases
642
     *
643
     * @return string[]
644
     */
645
    protected function _getPortableDatabasesList($databases)
646
    {
647 18
        $list = [];
648
        foreach ($databases as $value) {
649 18
            $value = $this->_getPortableDatabaseDefinition($value);
650
651 18
            if (! $value) {
652 18
                continue;
653
            }
654
655 18
            $list[] = $value;
656
        }
657
658
        return $list;
659
    }
660
661
    /**
662
     * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition.
663
     *
664
     * @param mixed[][] $namespaces The list of namespace names in the native DBMS data definition.
665
     *
666
     * @return string[]
667
     */
668
    protected function getPortableNamespacesList(array $namespaces)
669
    {
670
        $namespacesList = [];
671
672
        foreach ($namespaces as $namespace) {
673
            $namespacesList[] = $this->getPortableNamespaceDefinition($namespace);
674
        }
675
676
        return $namespacesList;
677
    }
678
679
    /**
680
     * @param mixed $database
681
     *
682
     * @return mixed
683
     */
684
    protected function _getPortableDatabaseDefinition($database)
685
    {
686
        return $database;
687
    }
688
689
    /**
690
     * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition.
691
     *
692
     * @param mixed[] $namespace The native DBMS namespace definition.
693
     *
694
     * @return mixed
695
     */
696
    protected function getPortableNamespaceDefinition(array $namespace)
697
    {
698
        return $namespace;
699
    }
700
701
    /**
702
     * @param mixed[][] $functions
703
     *
704
     * @return mixed[][]
705
     */
706
    protected function _getPortableFunctionsList($functions)
707
    {
708
        $list = [];
709
        foreach ($functions as $value) {
710
            $value = $this->_getPortableFunctionDefinition($value);
711
712
            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...
713
                continue;
714
            }
715
716
            $list[] = $value;
717
        }
718
719
        return $list;
720
    }
721
722
    /**
723
     * @param mixed[] $function
724
     *
725
     * @return mixed
726
     */
727
    protected function _getPortableFunctionDefinition($function)
728
    {
729
        return $function;
730
    }
731
732
    /**
733
     * @param mixed[][] $triggers
734
     *
735
     * @return mixed[][]
736
     */
737
    protected function _getPortableTriggersList($triggers)
738
    {
739
        $list = [];
740
        foreach ($triggers as $value) {
741
            $value = $this->_getPortableTriggerDefinition($value);
742
743
            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...
744
                continue;
745
            }
746
747 21
            $list[] = $value;
748
        }
749 21
750 21
        return $list;
751 21
    }
752
753 21
    /**
754
     * @param mixed[] $trigger
755
     *
756
     * @return mixed
757 21
     */
758
    protected function _getPortableTriggerDefinition($trigger)
759
    {
760 21
        return $trigger;
761
    }
762
763
    /**
764
     * @param mixed[][] $sequences
765
     *
766
     * @return Sequence[]
767
     */
768
    protected function _getPortableSequencesList($sequences)
769
    {
770
        $list = [];
771
        foreach ($sequences as $value) {
772
            $value = $this->_getPortableSequenceDefinition($value);
773
774
            if (! $value) {
775
                continue;
776
            }
777
778
            $list[] = $value;
779
        }
780
781
        return $list;
782
    }
783
784
    /**
785
     * @param mixed[] $sequence
786 1394
     *
787
     * @return Sequence
788 1394
     *
789
     * @throws DBALException
790 1394
     */
791 1394
    protected function _getPortableSequenceDefinition($sequence)
792 1380
    {
793 1380
        throw DBALException::notSupported('Sequences');
794
    }
795 1380
796 27
    /**
797 27
     * Independent of the database the keys of the column list result are lowercased.
798
     *
799 27
     * The name of the created column instance however is kept in its case.
800 27
     *
801
     * @param string    $table        The name of the table.
802
     * @param string    $database
803 1380
     * @param mixed[][] $tableColumns
804 1380
     *
805
     * @return Column[]
806
     */
807 1380
    protected function _getPortableTableColumnList($table, $database, $tableColumns)
808
    {
809
        $eventManager = $this->_platform->getEventManager();
810
811 1380
        $list = [];
812 1380
        foreach ($tableColumns as $tableColumn) {
813
            $column           = null;
814
            $defaultPrevented = false;
815 1394
816
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) {
817
                $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn);
818
                $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs);
819
820
                $defaultPrevented = $eventArgs->isDefaultPrevented();
821
                $column           = $eventArgs->getColumn();
822
            }
823
824
            if (! $defaultPrevented) {
825
                $column = $this->_getPortableTableColumnDefinition($tableColumn);
826
            }
827
828
            if (! $column) {
829
                continue;
830
            }
831
832
            $name        = strtolower($column->getQuotedName($this->_platform));
833
            $list[$name] = $column;
834
        }
835 1173
836
        return $list;
837 1173
    }
838 1173
839 648
    /**
840 648
     * Gets Table Column Definition.
841 533
     *
842
     * @param mixed[] $tableColumn
843 648
     *
844
     * @return Column
845 648
     */
846
    abstract protected function _getPortableTableColumnDefinition($tableColumn);
847 648
848
    /**
849
     * Aggregates and groups the index results according to the required data result.
850 648
     *
851 21
     * @param mixed[][]   $tableIndexRows
852
     * @param string|null $tableName
853
     *
854 648
     * @return Index[]
855 648
     */
856
    protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null)
857 648
    {
858 648
        $result = [];
859 648
        foreach ($tableIndexRows as $tableIndex) {
860 648
            $indexName = $keyName = $tableIndex['key_name'];
861
            if ($tableIndex['primary']) {
862
                $keyName = 'primary';
863
            }
864 648
            $keyName = strtolower($keyName);
865 648
866
            if (! isset($result[$keyName])) {
867
                $options = [
868 1173
                    'lengths' => [],
869
                ];
870 1173
871 1173
                if (isset($tableIndex['where'])) {
872 648
                    $options['where'] = $tableIndex['where'];
873 648
                }
874
875 648
                $result[$keyName] = [
876 27
                    'name' => $indexName,
877 27
                    'columns' => [],
878
                    'unique' => $tableIndex['non_unique'] ? false : true,
879 27
                    'primary' => $tableIndex['primary'],
880 27
                    'flags' => $tableIndex['flags'] ?? [],
881
                    'options' => $options,
882
                ];
883 648
            }
884 648
885
            $result[$keyName]['columns'][]            = $tableIndex['column_name'];
886
            $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null;
887 648
        }
888
889
        $eventManager = $this->_platform->getEventManager();
890
891 648
        $indexes = [];
892
        foreach ($result as $indexKey => $data) {
893
            $index            = null;
894 1173
            $defaultPrevented = false;
895
896
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
897
                $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
898
                $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
899
900
                $defaultPrevented = $eventArgs->isDefaultPrevented();
901
                $index            = $eventArgs->getIndex();
902 2106
            }
903
904 2106
            if (! $defaultPrevented) {
905 2106
                $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary'], $data['flags'], $data['options']);
906 2079
            }
907
908 2079
            if (! $index) {
909
                continue;
910
            }
911
912 2079
            $indexes[$indexKey] = $index;
913
        }
914
915 2106
        return $indexes;
916
    }
917
918
    /**
919
     * @param mixed[][] $tables
920
     *
921
     * @return string[]
922
     */
923
    protected function _getPortableTablesList($tables)
924
    {
925
        $list = [];
926
        foreach ($tables as $value) {
927
            $value = $this->_getPortableTableDefinition($value);
928
929
            if (! $value) {
930
                continue;
931
            }
932
933
            $list[] = $value;
934
        }
935
936
        return $list;
937
    }
938
939
    /**
940
     * @param mixed $table
941
     *
942
     * @return string
943
     */
944
    protected function _getPortableTableDefinition($table)
945
    {
946
        return $table;
947
    }
948
949
    /**
950
     * @param mixed[][] $users
951
     *
952
     * @return string[][]
953
     */
954
    protected function _getPortableUsersList($users)
955
    {
956
        $list = [];
957
        foreach ($users as $value) {
958
            $value = $this->_getPortableUserDefinition($value);
959
960
            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...
961
                continue;
962
            }
963
964 27
            $list[] = $value;
965
        }
966 27
967 27
        return $list;
968 27
    }
969
970 27
    /**
971
     * @param mixed[] $user
972
     *
973
     * @return mixed[]
974 27
     */
975 27
    protected function _getPortableUserDefinition($user)
976
    {
977
        return $user;
978 27
    }
979
980
    /**
981
     * @param mixed[][] $views
982
     *
983
     * @return View[]
984
     */
985
    protected function _getPortableViewsList($views)
986
    {
987
        $list = [];
988
        foreach ($views as $value) {
989
            $view = $this->_getPortableViewDefinition($value);
990
991
            if (! $view) {
992
                continue;
993
            }
994
995
            $viewName        = strtolower($view->getQuotedName($this->_platform));
996 394
            $list[$viewName] = $view;
997
        }
998 394
999 394
        return $list;
1000 121
    }
1001
1002 121
    /**
1003
     * @param mixed[] $view
1004
     *
1005
     * @return View|false
1006 121
     */
1007
    protected function _getPortableViewDefinition($view)
1008
    {
1009 394
        return false;
1010
    }
1011
1012
    /**
1013
     * @param mixed[][] $tableForeignKeys
1014
     *
1015
     * @return ForeignKeyConstraint[]
1016
     */
1017
    protected function _getPortableTableForeignKeysList($tableForeignKeys)
1018
    {
1019
        $list = [];
1020
        foreach ($tableForeignKeys as $value) {
1021
            $value = $this->_getPortableTableForeignKeyDefinition($value);
1022
1023
            if (! $value) {
1024
                continue;
1025
            }
1026
1027 4511
            $list[] = $value;
1028
        }
1029 4511
1030 4511
        return $list;
1031
    }
1032 3199
1033
    /**
1034
     * @param mixed $tableForeignKey
1035
     *
1036
     * @return ForeignKeyConstraint
1037
     */
1038
    protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
1039 108
    {
1040
        return $tableForeignKey;
1041 108
    }
1042
1043 108
    /**
1044 9
     * @param string[]|string $sql
1045
     *
1046
     * @return void
1047 108
     */
1048
    protected function _execSql($sql)
1049 108
    {
1050 11
        foreach ((array) $sql as $query) {
1051
            $this->_conn->executeUpdate($query);
1052
        }
1053 108
    }
1054
1055 108
    /**
1056
     * Creates a schema instance for the current database.
1057
     *
1058
     * @return Schema
1059
     */
1060
    public function createSchema()
1061
    {
1062
        $namespaces = [];
1063 472
1064
        if ($this->_platform->supportsSchemas()) {
1065 472
            $namespaces = $this->listNamespaceNames();
1066 472
        }
1067
1068 472
        $sequences = [];
1069 472
1070 354
        if ($this->_platform->supportsSequences()) {
1071
            $sequences = $this->listSequences();
1072
        }
1073 472
1074 472
        $tables = $this->listTables();
1075 472
1076
        return new Schema($tables, $sequences, $this->createSchemaConfig(), $namespaces);
1077 472
    }
1078 27
1079
    /**
1080 472
     * Creates the configuration for this schema.
1081
     *
1082 472
     * @return SchemaConfig
1083
     */
1084
    public function createSchemaConfig()
1085
    {
1086
        $schemaConfig = new SchemaConfig();
1087
        $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
1088
1089
        $searchPaths = $this->getSchemaSearchPaths();
1090
        if (isset($searchPaths[0])) {
1091
            $schemaConfig->setName($searchPaths[0]);
1092
        }
1093
1094
        $params = $this->_conn->getParams();
1095
        if (! isset($params['defaultTableOptions'])) {
1096
            $params['defaultTableOptions'] = [];
1097 367
        }
1098
        if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) {
1099 367
            $params['defaultTableOptions']['charset'] = $params['charset'];
1100
        }
1101
        $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']);
1102
1103
        return $schemaConfig;
1104
    }
1105
1106
    /**
1107
     * The search path for namespaces in the currently connected database.
1108
     *
1109
     * The first entry is usually the default namespace in the Schema. All
1110
     * further namespaces contain tables/sequences which can also be addressed
1111 1478
     * with a short, not full-qualified name.
1112
     *
1113 1478
     * For databases that don't support subschema/namespaces this method
1114 309
     * returns the name of the currently connected database.
1115
     *
1116
     * @return string[]
1117 1478
     */
1118
    public function getSchemaSearchPaths()
1119
    {
1120
        return [$this->_conn->getDatabase()];
1121
    }
1122
1123
    /**
1124
     * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns
1125
     * the type given as default.
1126 1304
     *
1127
     * @param string $comment
1128 1304
     * @param string $currentType
1129
     *
1130
     * @return string
1131
     */
1132
    public function extractDoctrineTypeFromComment($comment, $currentType)
1133
    {
1134
        if (preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match)) {
1135
            $currentType = $match[1];
1136
        }
1137
1138
        return $currentType;
1139
    }
1140
1141
    /**
1142
     * @param string $comment
1143
     * @param string $type
1144
     *
1145
     * @return string
1146
     */
1147
    public function removeDoctrineTypeFromComment($comment, $type)
1148
    {
1149
        return str_replace('(DC2Type:' . $type . ')', '', $comment);
1150
    }
1151
}
1152