Completed
Pull Request — master (#3610)
by Sergei
03:03
created

AbstractSchemaManager::_getPortableUsersList()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 6
cts 6
cp 1
rs 9.7666
c 0
b 0
f 0
cc 3
nc 3
nop 1
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\DBAL\Schema;
6
7
use Doctrine\DBAL\Connection;
8
use Doctrine\DBAL\ConnectionException;
9
use Doctrine\DBAL\DBALException;
10
use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs;
11
use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs;
12
use Doctrine\DBAL\Events;
13
use Doctrine\DBAL\Exception\DatabaseRequired;
14
use Doctrine\DBAL\Platforms\AbstractPlatform;
15
use Doctrine\DBAL\Platforms\Exception\NotSupported;
16
use Throwable;
17
use function array_filter;
18
use function array_intersect;
19
use function array_map;
20
use function array_shift;
21
use function array_values;
22
use function assert;
23
use function call_user_func_array;
24
use function count;
25
use function func_get_args;
26
use function is_array;
27
use function is_callable;
28
use function preg_match;
29
use function strtolower;
30
31
/**
32
 * Base class for schema managers. Schema managers are used to inspect and/or
33
 * modify the database schema/structure.
34
 */
35
abstract class AbstractSchemaManager
36
{
37
    /**
38
     * Holds instance of the Doctrine connection for this schema manager.
39
     *
40
     * @var Connection
41
     */
42
    protected $_conn;
43
44
    /**
45
     * Holds instance of the database platform used for this schema manager.
46
     *
47
     * @var AbstractPlatform
48
     */
49
    protected $_platform;
50 6048
51
    /**
52 6048
     * Constructor. Accepts the Connection instance to manage the schema for.
53 6048
     */
54 6048
    public function __construct(Connection $conn, ?AbstractPlatform $platform = null)
55
    {
56
        $this->_conn     = $conn;
57
        $this->_platform = $platform ?: $this->_conn->getDatabasePlatform();
58
    }
59
60
    /**
61 3750
     * Returns the associated platform.
62
     */
63 3750
    public function getDatabasePlatform() : AbstractPlatform
64
    {
65
        return $this->_platform;
66
    }
67
68
    /**
69
     * Tries any method on the schema manager. Normally a method throws an
70
     * exception when your DBMS doesn't support it or if an error occurs.
71
     * This method allows you to try and method on your SchemaManager
72
     * instance and will return false if it does not work or is not supported.
73
     *
74
     * <code>
75
     * $result = $sm->tryMethod('dropView', 'view_name');
76
     * </code>
77
     *
78 5861
     * @return mixed
79
     */
80 5861
    public function tryMethod()
81 5861
    {
82 5861
        $args   = func_get_args();
83 5861
        $method = $args[0];
84
        unset($args[0]);
85 5861
        $args = array_values($args);
86 5861
87
        $callback = [$this, $method];
88
        assert(is_callable($callback));
89 5861
90 5721
        try {
91 5721
            return call_user_func_array($callback, $args);
92
        } catch (Throwable $e) {
93
            return false;
94
        }
95
    }
96
97
    /**
98
     * Lists the available databases for this connection.
99
     *
100 3331
     * @return array<int, string>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
101
     */
102 3331
    public function listDatabases() : array
103
    {
104 3189
        $sql = $this->_platform->getListDatabasesSQL();
105
106 3189
        $databases = $this->_conn->fetchAll($sql);
107
108
        return $this->_getPortableDatabasesList($databases);
109
    }
110
111
    /**
112
     * Returns a list of all namespaces in the current database.
113
     *
114 1242
     * @return array<int, string>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
115
     */
116 1242
    public function listNamespaceNames() : array
117
    {
118 1242
        $sql = $this->_platform->getListNamespacesSQL();
119
120 1242
        $namespaces = $this->_conn->fetchAll($sql);
121
122
        return $this->getPortableNamespacesList($namespaces);
123
    }
124
125
    /**
126
     * Lists the available sequences for this connection.
127
     *
128
     * @return array<int, Sequence>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
129
     */
130 1278
    public function listSequences(?string $database = null) : array
131
    {
132 1278
        $database = $this->ensureDatabase(
133 1278
            $database ?? $this->_conn->getDatabase(),
134
            __METHOD__
135 1278
        );
136
137 1278
        $sql = $this->_platform->getListSequencesSQL($database);
138
139 1278
        $sequences = $this->_conn->fetchAll($sql);
140
141
        return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
142
    }
143
144
    /**
145
     * Lists the columns for a given table.
146
     *
147
     * In contrast to other libraries and to the old version of Doctrine,
148
     * this column definition does try to contain the 'primary' field for
149
     * the reason that it is not portable across different RDBMS. Use
150
     * {@see listTableIndexes($tableName)} to retrieve the primary key
151
     * of a table. Where a RDBMS specifies more details, these are held
152
     * in the platformDetails array.
153
     *
154
     * @return array<string, Column>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
155
     */
156
    public function listTableColumns(string $table, ?string $database = null) : array
157 4571
    {
158
        $database = $this->ensureDatabase(
159 4571
            $database ?? $this->_conn->getDatabase(),
160 4569
            __METHOD__
161
        );
162
163 4571
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
164
165 4571
        $tableColumns = $this->_conn->fetchAll($sql);
166
167 4571
        return $this->_getPortableTableColumnList($table, $database, $tableColumns);
168
    }
169
170
    /**
171
     * Lists the indexes for a given table returning an array of Index instances.
172
     *
173
     * Keys of the portable indexes list are all lower-cased.
174
     *
175
     * @return array<string, Index>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
176
     */
177
    public function listTableIndexes(string $table) : array
178
    {
179 4253
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
180
181 4253
        $tableIndexes = $this->_conn->fetchAll($sql);
182
183 4253
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
184
    }
185 4253
186
    /**
187
     * Returns true if all the given tables exist.
188
     *
189
     * @param array<int, string> $tableNames
190
     */
191
    public function tablesExist(array $tableNames) : bool
192
    {
193
        $tableNames = array_map('strtolower', $tableNames);
194
195
        return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
196
    }
197 5063
198
    public function tableExists(string $tableName) : bool
199 5063
    {
200
        return $this->tablesExist([$tableName]);
201 5063
    }
202
203
    /**
204
     * Returns a list of all tables in the current database.
205
     *
206
     * @return array<int, string>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
207
     */
208
    public function listTableNames() : array
209 4901
    {
210
        $sql = $this->_platform->getListTablesSQL();
211 4901
212
        $tables     = $this->_conn->fetchAll($sql);
213 4901
        $tableNames = $this->_getPortableTablesList($tables);
214 4901
215
        return $this->filterAssetNames($tableNames);
216 4901
    }
217
218
    /**
219
     * Filters asset names if they are configured to return only a subset of all
220
     * the found elements.
221
     *
222
     * @param array<int, mixed> $assetNames
223
     *
224
     * @return array<int, mixed>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
225
     */
226
    protected function filterAssetNames(array $assetNames) : array
227 5087
    {
228
        $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter();
229 5087
        if (! $filter) {
230 5087
            return $assetNames;
231 5087
        }
232
233
        return array_values(array_filter($assetNames, $filter));
234 1718
    }
235
236
    /**
237
     * Lists the tables for this connection.
238
     *
239
     * @return array<int, Table>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
240
     */
241
    public function listTables() : array
242
    {
243
        $tableNames = $this->listTableNames();
244
245
        $tables = [];
246
        foreach ($tableNames as $tableName) {
247
            $tables[] = $this->listTableDetails($tableName);
248
        }
249
250
        return $tables;
251
    }
252 4300
253
    public function listTableDetails(string $tableName) : Table
254 4300
    {
255
        $columns     = $this->listTableColumns($tableName);
256 4300
        $foreignKeys = [];
257 4300
258 4249
        if ($this->_platform->supportsForeignKeyConstraints()) {
259
            $foreignKeys = $this->listTableForeignKeys($tableName);
260
        }
261 4300
262
        $indexes = $this->listTableIndexes($tableName);
263
264
        return new Table($tableName, $columns, $indexes, [], $foreignKeys, []);
265
    }
266
267
    /**
268
     * Lists the views this connection has.
269 4547
     *
270
     * @return array<string, View>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
271 4547
     */
272 4547
    public function listViews() : array
273 4547
    {
274 4397
        $database = $this->ensureDatabase(
275
            $this->_conn->getDatabase(),
276 4547
            __METHOD__
277
        );
278 4547
279
        $sql   = $this->_platform->getListViewsSQL($database);
280
        $views = $this->_conn->fetchAll($sql);
281
282
        return $this->_getPortableViewsList($views);
283
    }
284
285
    /**
286 3079
     * Lists the foreign keys for the given table.
287
     *
288 3079
     * @return array<int|string, ForeignKeyConstraint>
0 ignored issues
show
Documentation introduced by
The doc-type array<int|string, could not be parsed: Expected ">" at position 7, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
289 3079
     */
290 3079
    public function listTableForeignKeys(string $table, ?string $database = null) : array
291
    {
292 3079
        if ($database === null) {
293
            $database = $this->_conn->getDatabase();
294
        }
295
        $sql              = $this->_platform->getListTableForeignKeysSQL($table, $database);
296
        $tableForeignKeys = $this->_conn->fetchAll($sql);
297
298
        return $this->_getPortableTableForeignKeysList($tableForeignKeys);
299
    }
300
301
    /* drop*() Methods */
302
303 4436
    /**
304
     * Drops a database.
305 4436
     *
306 4436
     * NOTE: You can not drop the database this SchemaManager is currently connected to.
307
     */
308 4436
    public function dropDatabase(string $database) : void
309 4436
    {
310
        $this->_execSql($this->_platform->getDropDatabaseSQL($database));
311 4436
    }
312
313
    /**
314
     * Drops the given table.
315
     */
316
    public function dropTable(string $tableName) : void
317
    {
318
        $this->_execSql($this->_platform->getDropTableSQL($tableName));
319
    }
320
321
    /**
322
     * Drops the index from the given table.
323
     *
324
     * @param Index|string $index The name of the index.
325 5271
     * @param Table|string $table The name of the table.
326
     */
327 5271
    public function dropIndex($index, $table) : void
328 4536
    {
329
        if ($index instanceof Index) {
330
            $index = $index->getQuotedName($this->_platform);
331
        }
332
333
        $this->_execSql($this->_platform->getDropIndexSQL($index, $table));
334
    }
335
336
    /**
337 5640
     * Drops the constraint from the given table.
338
     *
339 5640
     * @param Table|string $table The name of the table.
340 5519
     */
341
    public function dropConstraint(Constraint $constraint, $table) : void
342
    {
343
        $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table));
344
    }
345
346
    /**
347
     * Drops a foreign key from a table.
348
     *
349
     * @param ForeignKeyConstraint|string $foreignKey The name of the foreign key.
350 3204
     * @param Table|string                $table      The name of the table with the foreign key.
351
     */
352 3204
    public function dropForeignKey($foreignKey, $table) : void
353
    {
354
        $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table));
355
    }
356 3204
357 3204
    /**
358
     * Drops a sequence with a given name.
359
     */
360
    public function dropSequence(string $name) : void
361
    {
362
        $this->_execSql($this->_platform->getDropSequenceSQL($name));
363
    }
364
365
    /**
366
     * Drops a view.
367
     */
368
    public function dropView(string $name) : void
369
    {
370
        $this->_execSql($this->_platform->getDropViewSQL($name));
371
    }
372
373
    /* create*() Methods */
374
375
    /**
376
     * Creates a new database.
377
     */
378
    public function createDatabase(string $database) : void
379
    {
380
        $this->_execSql($this->_platform->getCreateDatabaseSQL($database));
381
    }
382
383
    /**
384
     * Creates a new table.
385
     */
386
    public function createTable(Table $table) : void
387
    {
388
        $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS;
389
        $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
390
    }
391 1273
392
    /**
393 1273
     * Creates a new sequence.
394
     *
395
     * @throws ConnectionException If something fails at database level.
396
     */
397
    public function createSequence(Sequence $sequence) : void
398
    {
399
        $this->_execSql($this->_platform->getCreateSequenceSQL($sequence));
400
    }
401
402
    /**
403 3271
     * Creates a constraint on a table.
404
     *
405 3271
     * @param Table|string $table
406
     */
407
    public function createConstraint(Constraint $constraint, $table) : void
408
    {
409
        $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table));
410
    }
411
412
    /**
413
     * Creates a new index on a table.
414
     *
415
     * @param Table|string $table The name of the table on which the index is to be created.
416
     */
417 5267
    public function createIndex(Index $index, $table) : void
418
    {
419 5267
        $this->_execSql($this->_platform->getCreateIndexSQL($index, $table));
420 5267
    }
421
422
    /**
423
     * Creates a new foreign key.
424
     *
425
     * @param ForeignKeyConstraint $foreignKey The ForeignKey instance.
426
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
427 5674
     */
428
    public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) : void
429 5674
    {
430 5674
        $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table));
431 5635
    }
432
433
    /**
434
     * Creates a new view.
435
     */
436
    public function createView(View $view) : void
437
    {
438
        $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql()));
439
    }
440
441
    /* dropAndCreate*() Methods */
442 1276
443
    /**
444 1276
     * Drops and creates a constraint.
445 1276
     *
446
     * @see dropConstraint()
447
     * @see createConstraint()
448
     *
449
     * @param Table|string $table
450
     */
451
    public function dropAndCreateConstraint(Constraint $constraint, $table) : void
452
    {
453
        $this->tryMethod('dropConstraint', $constraint, $table);
454 2
        $this->createConstraint($constraint, $table);
455
    }
456 2
457 2
    /**
458
     * Drops and creates a new index on a table.
459
     *
460
     * @param Table|string $table The name of the table on which the index is to be created.
461
     */
462
    public function dropAndCreateIndex(Index $index, $table) : void
463
    {
464
        $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table);
465
        $this->createIndex($index, $table);
466 3204
    }
467
468 3204
    /**
469 3204
     * Drops and creates a new foreign key.
470
     *
471
     * @param ForeignKeyConstraint $foreignKey An associative array that defines properties of the foreign key to be created.
472
     * @param Table|string         $table      The name of the table on which the foreign key is to be created.
473
     */
474
    public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) : void
475
    {
476
        $this->tryMethod('dropForeignKey', $foreignKey, $table);
477
        $this->createForeignKey($foreignKey, $table);
478
    }
479 3245
480
    /**
481 3245
     * Drops and create a new sequence.
482 3245
     *
483
     * @throws ConnectionException If something fails at database level.
484
     */
485
    public function dropAndCreateSequence(Sequence $sequence) : void
486
    {
487
        $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform));
488
        $this->createSequence($sequence);
489 3271
    }
490
491 3271
    /**
492 3271
     * Drops and creates a new table.
493
     */
494
    public function dropAndCreateTable(Table $table) : void
495
    {
496
        $this->tryMethod('dropTable', $table->getQuotedName($this->_platform));
497
        $this->createTable($table);
498
    }
499
500
    /**
501
     * Drops and creates a new database.
502
     */
503
    public function dropAndCreateDatabase(string $database) : void
504
    {
505
        $this->tryMethod('dropDatabase', $database);
506
        $this->createDatabase($database);
507
    }
508
509
    /**
510
     * Drops and creates a new view.
511
     */
512
    public function dropAndCreateView(View $view) : void
513
    {
514
        $this->tryMethod('dropView', $view->getQuotedName($this->_platform));
515
        $this->createView($view);
516
    }
517
518
    /* alterTable() Methods */
519 3204
520
    /**
521 3204
     * Alters an existing tables schema.
522 3204
     */
523 3204
    public function alterTable(TableDiff $tableDiff) : void
524
    {
525
        $queries = $this->_platform->getAlterTableSQL($tableDiff);
526
527
        if (! is_array($queries) || ! count($queries)) {
528
            return;
529
        }
530
531
        foreach ($queries as $ddlQuery) {
532
            $this->_execSql($ddlQuery);
533
        }
534
    }
535
536
    /**
537
     * Renames a given table to another name.
538
     */
539
    public function renameTable(string $name, string $newName) : void
540
    {
541
        $tableDiff          = new TableDiff($name);
542
        $tableDiff->newName = $newName;
543
        $this->alterTable($tableDiff);
544
    }
545
546 1273
    /**
547
     * Methods for filtering return values of list*() methods to convert
548 1273
     * the native DBMS data definition to a portable Doctrine definition
549 1273
     */
550 1273
551
    /**
552
     * @param array<int, mixed> $databases
553
     *
554
     * @return array<int, string>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
555
     */
556
    protected function _getPortableDatabasesList(array $databases) : array
557 5561
    {
558
        $list = [];
559 5561
        foreach ($databases as $value) {
560 5561
            $value = $this->_getPortableDatabaseDefinition($value);
561 5561
562
            if (! $value) {
563
                continue;
564
            }
565
566
            $list[] = $value;
567
        }
568
569
        return $list;
570 5411
    }
571
572 5411
    /**
573 5411
     * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition.
574 5411
     *
575
     * @param array<int, array<int, mixed>> $namespaces The list of namespace names in the native DBMS data definition.
576
     *
577
     * @return array<int, string>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
578
     */
579
    protected function getPortableNamespacesList(array $namespaces) : array
580
    {
581 3271
        $namespacesList = [];
582
583 3271
        foreach ($namespaces as $namespace) {
584 3271
            $namespacesList[] = $this->getPortableNamespaceDefinition($namespace);
585 3271
        }
586
587
        return $namespacesList;
588
    }
589
590
    /**
591
     * @param array<string, string> $database
592
     */
593
    protected function _getPortableDatabaseDefinition(array $database) : string
594 3947
    {
595
        return array_shift($database);
596 3947
    }
597 3947
598 1515
    /**
599
     * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition.
600
     *
601 3947
     * @param array<string|int, mixed> $namespace The native DBMS namespace definition.
602 3947
     */
603
    protected function getPortableNamespaceDefinition(array $namespace) : string
604 3947
    {
605
        return array_shift($namespace);
606
    }
607
608
    /**
609
     * @param array<int, array<string, mixed>> $sequences
610
     *
611
     * @return array<int, Sequence>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
612
     */
613
    protected function _getPortableSequencesList(array $sequences) : array
614 2
    {
615
        $list = [];
616 2
617 2
        foreach ($sequences as $value) {
618 2
            $list[] = $this->_getPortableSequenceDefinition($value);
619 2
        }
620
621
        return $list;
622
    }
623
624
    /**
625
     * @param array<string, mixed> $sequence
626
     *
627
     * @throws DBALException
628
     */
629
    protected function _getPortableSequenceDefinition(array $sequence) : Sequence
630
    {
631 3189
        throw NotSupported::new('Sequences');
632
    }
633 3189
634 3189
    /**
635 3189
     * Independent of the database the keys of the column list result are lowercased.
636
     *
637 3189
     * The name of the created column instance however is kept in its case.
638
     *
639
     * @param array<int, array<string, mixed>> $tableColumns
640
     *
641 3189
     * @return array<string, Column>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
642
     */
643
    protected function _getPortableTableColumnList(string $table, string $database, array $tableColumns) : array
644 3189
    {
645
        $eventManager = $this->_platform->getEventManager();
646
647
        $list = [];
648
        foreach ($tableColumns as $tableColumn) {
649
            $column           = null;
650
            $defaultPrevented = false;
651
652
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) {
653
                $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn);
654 1242
                $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs);
655
656 1242
                $defaultPrevented = $eventArgs->isDefaultPrevented();
657
                $column           = $eventArgs->getColumn();
658 1242
            }
659 1242
660
            if (! $defaultPrevented) {
661
                $column = $this->_getPortableTableColumnDefinition($tableColumn);
662 1242
            }
663
664
            if (! $column) {
665
                continue;
666
            }
667
668
            $name        = strtolower($column->getQuotedName($this->_platform));
669
            $list[$name] = $column;
670
        }
671
672
        return $list;
673
    }
674
675
    /**
676
     * Gets Table Column Definition.
677
     *
678
     * @param array<string, mixed> $tableColumn
679
     */
680
    abstract protected function _getPortableTableColumnDefinition(array $tableColumn) : Column;
681
682
    /**
683
     * Aggregates and groups the index results according to the required data result.
684
     *
685
     * @param array<int, array<string, mixed>> $tableIndexRows
686
     *
687
     * @return array<string, Index>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
688
     */
689
    protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array
690
    {
691
        $result = [];
692
        foreach ($tableIndexRows as $tableIndex) {
693
            $indexName = $keyName = $tableIndex['key_name'];
694
            if ($tableIndex['primary']) {
695
                $keyName = 'primary';
696
            }
697
            $keyName = strtolower($keyName);
698
699
            if (! isset($result[$keyName])) {
700
                $options = [
701
                    'lengths' => [],
702
                ];
703
704
                if (isset($tableIndex['where'])) {
705
                    $options['where'] = $tableIndex['where'];
706
                }
707
708
                $result[$keyName] = [
709
                    'name' => $indexName,
710
                    'columns' => [],
711
                    'unique' => ! $tableIndex['non_unique'],
712
                    'primary' => $tableIndex['primary'],
713
                    'flags' => $tableIndex['flags'] ?? [],
714
                    'options' => $options,
715
                ];
716
            }
717
718
            $result[$keyName]['columns'][]            = $tableIndex['column_name'];
719
            $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null;
720
        }
721
722
        $eventManager = $this->_platform->getEventManager();
723
724
        $indexes = [];
725
        foreach ($result as $indexKey => $data) {
726
            $index            = null;
727
            $defaultPrevented = false;
728
729
            if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
730
                $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
731
                $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
732
733
                $defaultPrevented = $eventArgs->isDefaultPrevented();
734
                $index            = $eventArgs->getIndex();
735
            }
736
737
            if (! $defaultPrevented) {
738
                $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary'], $data['flags'], $data['options']);
739
            }
740
741
            if (! $index) {
742
                continue;
743
            }
744
745
            $indexes[$indexKey] = $index;
746
        }
747
748
        return $indexes;
749
    }
750
751
    /**
752
     * @param array<int, array<string, mixed>> $tables
753
     *
754
     * @return array<int, string>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
755
     */
756
    protected function _getPortableTablesList(array $tables) : array
757
    {
758 294
        $list = [];
759
        foreach ($tables as $value) {
760 294
            $value = $this->_getPortableTableDefinition($value);
761
762 294
            if (! $value) {
763 294
                continue;
764
            }
765
766 294
            $list[] = $value;
767
        }
768
769
        return $list;
770
    }
771
772
    /**
773
     * @param array<string, string> $table
774
     */
775
    protected function _getPortableTableDefinition(array $table) : string
776
    {
777
        return array_shift($table);
778
    }
779
780
    /**
781
     * @param array<int, array<string, mixed>> $users
782
     *
783
     * @return array<int, array<string, mixed>>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
784
     */
785
    protected function _getPortableUsersList(array $users) : array
786
    {
787
        $list = [];
788
        foreach ($users as $value) {
789
            $value = $this->_getPortableUserDefinition($value);
790
791
            if (! $value) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $value of type array 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...
792 4571
                continue;
793
            }
794 4571
795
            $list[] = $value;
796 4571
        }
797 4571
798 4571
        return $list;
799 4571
    }
800
801 4571
    /**
802 3304
     * @param array<string, mixed> $user
803 3304
     *
804
     * @return array<string, mixed>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
805 3304
     */
806 3304
    protected function _getPortableUserDefinition(array $user) : array
807
    {
808
        return $user;
809 4571
    }
810 4571
811
    /**
812
     * @param array<int, array<string, mixed>> $views
813 4571
     *
814
     * @return array<string, View>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
815
     */
816
    protected function _getPortableViewsList(array $views) : array
817 4571
    {
818 4571
        $list = [];
819
        foreach ($views as $value) {
820
            $view        = $this->_getPortableViewDefinition($value);
821 4571
            $name        = strtolower($view->getQuotedName($this->_platform));
822
            $list[$name] = $view;
823
        }
824
825
        return $list;
826
    }
827
828
    /**
829
     * @param array<string, mixed> $view
830
     */
831
    protected function _getPortableViewDefinition(array $view) : View
832
    {
833
        throw NotSupported::new('Views');
834
    }
835
836
    /**
837
     * @param array<int|string, array<string, mixed>> $tableForeignKeys
838
     *
839
     * @return array<int, ForeignKeyConstraint>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
840
     */
841 4557
    protected function _getPortableTableForeignKeysList(array $tableForeignKeys) : array
842
    {
843 4557
        $list = [];
844 4557
845 4382
        foreach ($tableForeignKeys as $value) {
846 4382
            $list[] = $this->_getPortableTableForeignKeyDefinition($value);
847 4378
        }
848
849 4382
        return $list;
850
    }
851 4382
852
    /**
853 4382
     * @param array<string, mixed> $tableForeignKey
854
     */
855
    protected function _getPortableTableForeignKeyDefinition(array $tableForeignKey) : ForeignKeyConstraint
856 4382
    {
857 1057
        throw NotSupported::new('ForeignKey');
858
    }
859
860 4382
    /**
861 4382
     * @param array<int, string>|string $sql
862
     */
863 4382
    protected function _execSql($sql) : void
864 4382
    {
865 4382
        foreach ((array) $sql as $query) {
866 4382
            $this->_conn->executeUpdate($query);
867
        }
868
    }
869
870 4382
    /**
871 4382
     * Creates a schema instance for the current database.
872
     */
873
    public function createSchema() : Schema
874 4557
    {
875
        $namespaces = [];
876 4557
877 4557
        if ($this->_platform->supportsSchemas()) {
878 4382
            $namespaces = $this->listNamespaceNames();
879 4382
        }
880
881 4382
        $sequences = [];
882 3279
883 3279
        if ($this->_platform->supportsSequences()) {
884
            $sequences = $this->listSequences();
885 3279
        }
886 3279
887
        $tables = $this->listTables();
888
889 4382
        return new Schema($tables, $sequences, $this->createSchemaConfig(), $namespaces);
890 4382
    }
891
892
    /**
893 4382
     * Creates the configuration for this schema.
894
     */
895
    public function createSchemaConfig() : SchemaConfig
896
    {
897 4382
        $schemaConfig = new SchemaConfig();
898
        $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
899
900 4557
        $searchPaths = $this->getSchemaSearchPaths();
901
        if (isset($searchPaths[0])) {
902
            $schemaConfig->setName($searchPaths[0]);
903
        }
904
905
        $params = $this->_conn->getParams();
906
        if (! isset($params['defaultTableOptions'])) {
907
            $params['defaultTableOptions'] = [];
908 4901
        }
909
        if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) {
910 4901
            $params['defaultTableOptions']['charset'] = $params['charset'];
911 4901
        }
912 4898
        $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']);
913
914 4898
        return $schemaConfig;
915
    }
916
917
    /**
918 4898
     * The search path for namespaces in the currently connected database.
919
     *
920
     * The first entry is usually the default namespace in the Schema. All
921 4901
     * further namespaces contain tables/sequences which can also be addressed
922
     * with a short, not full-qualified name.
923
     *
924
     * For databases that don't support subschema/namespaces this method
925
     * returns the name of the currently connected database.
926
     *
927
     * @return array<int, string>
0 ignored issues
show
Documentation introduced by
The doc-type array<int, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
928
     */
929
    public function getSchemaSearchPaths() : array
930
    {
931
        $database = $this->_conn->getDatabase();
932
933
        if ($database !== null) {
934
            return [$database];
935
        }
936
937
        return [];
938
    }
939
940
    /**
941
     * Given a table comment this method tries to extract a type hint for Doctrine Type. If the type hint is found,
942
     * it's removed from the comment.
943
     *
944
     * @return string|null The extracted Doctrine type or NULL of the type hint was not found.
945
     */
946
    final protected function extractDoctrineTypeFromComment(?string &$comment) : ?string
947
    {
948
        if ($comment === null || ! preg_match('/(.*)\(DC2Type:(((?!\)).)+)\)(.*)/', $comment, $match)) {
949
            return null;
950
        }
951
952
        $comment = $match[1] . $match[4];
953
954
        return $match[2];
955
    }
956
957
    /**
958
     * @throws DatabaseRequired
959
     */
960
    private function ensureDatabase(?string $database, string $methodName) : string
961
    {
962
        if ($database === null) {
963
            throw DatabaseRequired::new($methodName);
964
        }
965
966
        return $database;
967
    }
968
}
969