Passed
Push — 2.7 ( bd5e19...0d26c7 )
by Sergei
14:54
created

AbstractSchemaManager   F

Complexity

Total Complexity 118

Size/Duplication

Total Lines 1077
Duplicated Lines 0 %

Test Coverage

Coverage 61.63%

Importance

Changes 0
Metric Value
wmc 118
dl 0
loc 1077
ccs 196
cts 318
cp 0.6163
rs 0.7768
c 0
b 0
f 0

65 Methods

Rating   Name   Duplication   Size   Complexity  
A createDatabase() 0 3 1
A createSchema() 0 17 3
A _getPortableSequenceDefinition() 0 3 1
A dropAndCreateSequence() 0 4 1
A dropAndCreateConstraint() 0 4 1
A createSequence() 0 3 1
A _getPortableTriggerDefinition() 0 3 1
A _getPortableUserDefinition() 0 3 1
A dropIndex() 0 7 2
A __construct() 0 4 2
A _getPortableDatabasesList() 0 10 3
A dropDatabase() 0 3 1
A _getPortableSequencesList() 0 10 3
A removeDoctrineTypeFromComment() 0 3 1
A _getPortableFunctionDefinition() 0 3 1
A listTableDetails() 0 10 2
A _getPortableTableDefinition() 0 3 1
A _getPortableTableForeignKeyDefinition() 0 3 1
A getDatabasePlatform() 0 3 1
A dropAndCreateTable() 0 4 1
A dropTable() 0 3 1
A listNamespaceNames() 0 7 1
B _getPortableTableColumnList() 0 28 6
A alterTable() 0 6 4
A listSequences() 0 10 2
A listDatabases() 0 7 1
A _getPortableTriggersList() 0 10 3
A createForeignKey() 0 3 1
A tryMethod() 0 11 2
A listTableColumns() 0 11 2
A dropConstraint() 0 3 1
A dropView() 0 3 1
C _getPortableTableIndexesList() 0 49 11
A getFilterSchemaAssetsExpression() 0 3 1
A dropAndCreateDatabase() 0 4 1
A _getPortableTableForeignKeysList() 0 10 3
A getPortableNamespacesList() 0 9 2
A createTable() 0 4 1
A createIndex() 0 3 1
A _getPortableTablesList() 0 10 3
A _getPortableViewDefinition() 0 3 1
A tablesExist() 0 5 1
A dropAndCreateForeignKey() 0 4 1
A dropAndCreateIndex() 0 4 1
A _execSql() 0 4 2
B createSchemaConfig() 0 20 5
A _getPortableDatabaseDefinition() 0 3 1
A dropSequence() 0 3 1
A renameTable() 0 5 1
A getSchemaSearchPaths() 0 3 1
A _getPortableViewsList() 0 11 3
A getPortableNamespaceDefinition() 0 3 1
A extractDoctrineTypeFromComment() 0 7 2
A listTableForeignKeys() 0 9 2
A _getPortableUsersList() 0 10 3
A dropForeignKey() 0 3 1
A listViews() 0 7 1
A listTableIndexes() 0 7 1
A listTables() 0 10 2
A listTableNames() 0 8 1
A createConstraint() 0 3 1
A dropAndCreateView() 0 4 1
A createView() 0 3 1
A _getPortableFunctionsList() 0 10 3
A filterAssetNames() 0 12 3

How to fix   Complexity   

Complex Class

Complex classes like AbstractSchemaManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

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

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

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Schema;
21
22
use Doctrine\DBAL\Events;
23
use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs;
24
use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs;
25
use Doctrine\DBAL\DBALException;
26
use Doctrine\DBAL\Platforms\AbstractPlatform;
27
use function array_filter;
28
use function array_map;
29
use function array_values;
30
use function call_user_func_array;
31
use function count;
32
use function func_get_args;
33
use function is_array;
34
use function is_null;
35
use function preg_match;
36
use function str_replace;
37
use function strtolower;
38
39
/**
40
 * Base class for schema managers. Schema managers are used to inspect and/or
41
 * modify the database schema/structure.
42
 *
43
 * @author Konsta Vesterinen <[email protected]>
44
 * @author Lukas Smith <[email protected]> (PEAR MDB2 library)
45
 * @author Roman Borschel <[email protected]>
46
 * @author Jonathan H. Wage <[email protected]>
47
 * @author Benjamin Eberlei <[email protected]>
48
 * @since  2.0
49
 */
50
abstract class AbstractSchemaManager
51
{
52
    /**
53
     * Holds instance of the Doctrine connection for this schema manager.
54
     *
55
     * @var \Doctrine\DBAL\Connection
56
     */
57
    protected $_conn;
58
59
    /**
60
     * Holds instance of the database platform used for this schema manager.
61
     *
62
     * @var \Doctrine\DBAL\Platforms\AbstractPlatform
63
     */
64
    protected $_platform;
65
66
    /**
67
     * Constructor. Accepts the Connection instance to manage the schema for.
68
     *
69
     * @param \Doctrine\DBAL\Connection                      $conn
70
     * @param \Doctrine\DBAL\Platforms\AbstractPlatform|null $platform
71
     */
72 71
    public function __construct(\Doctrine\DBAL\Connection $conn, AbstractPlatform $platform = null)
73
    {
74 71
        $this->_conn     = $conn;
75 71
        $this->_platform = $platform ?: $this->_conn->getDatabasePlatform();
76 71
    }
77
78
    /**
79
     * Returns the associated platform.
80
     *
81
     * @return \Doctrine\DBAL\Platforms\AbstractPlatform
82
     */
83 13
    public function getDatabasePlatform()
84
    {
85 13
        return $this->_platform;
86
    }
87
88
    /**
89
     * Tries any method on the schema manager. Normally a method throws an
90
     * exception when your DBMS doesn't support it or if an error occurs.
91
     * This method allows you to try and method on your SchemaManager
92
     * instance and will return false if it does not work or is not supported.
93
     *
94
     * <code>
95
     * $result = $sm->tryMethod('dropView', 'view_name');
96
     * </code>
97
     *
98
     * @return mixed
99
     */
100 74
    public function tryMethod()
101
    {
102 74
        $args = func_get_args();
103 74
        $method = $args[0];
104 74
        unset($args[0]);
105 74
        $args = array_values($args);
106
107
        try {
108 74
            return call_user_func_array([$this, $method], $args);
109 54
        } catch (\Exception $e) {
110 54
            return false;
111
        }
112
    }
113
114
    /**
115
     * Lists the available databases for this connection.
116
     *
117
     * @return array
118
     */
119 1
    public function listDatabases()
120
    {
121 1
        $sql = $this->_platform->getListDatabasesSQL();
122
123
        $databases = $this->_conn->fetchAll($sql);
124
125
        return $this->_getPortableDatabasesList($databases);
126
    }
127
128
    /**
129
     * Returns a list of all namespaces in the current database.
130
     *
131
     * @return array
132
     */
133
    public function listNamespaceNames()
134
    {
135
        $sql = $this->_platform->getListNamespacesSQL();
136
137
        $namespaces = $this->_conn->fetchAll($sql);
138
139
        return $this->getPortableNamespacesList($namespaces);
140
    }
141
142
    /**
143
     * Lists the available sequences for this connection.
144
     *
145
     * @param string|null $database
146
     *
147
     * @return \Doctrine\DBAL\Schema\Sequence[]
148
     */
149
    public function listSequences($database = null)
150
    {
151
        if (is_null($database)) {
152
            $database = $this->_conn->getDatabase();
153
        }
154
        $sql = $this->_platform->getListSequencesSQL($database);
155
156
        $sequences = $this->_conn->fetchAll($sql);
157
158
        return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
159
    }
160
161
    /**
162
     * Lists the columns for a given table.
163
     *
164
     * In contrast to other libraries and to the old version of Doctrine,
165
     * this column definition does try to contain the 'primary' field for
166
     * the reason that it is not portable across different RDBMS. Use
167
     * {@see listTableIndexes($tableName)} to retrieve the primary key
168
     * of a table. We're a RDBMS specifies more details these are held
169
     * in the platformDetails array.
170
     *
171
     * @param string      $table    The name of the table.
172
     * @param string|null $database
173
     *
174
     * @return \Doctrine\DBAL\Schema\Column[]
175
     */
176 40
    public function listTableColumns($table, $database = null)
177
    {
178 40
        if ( ! $database) {
179 40
            $database = $this->_conn->getDatabase();
180
        }
181
182 40
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
183
184 40
        $tableColumns = $this->_conn->fetchAll($sql);
185
186 40
        return $this->_getPortableTableColumnList($table, $database, $tableColumns);
187
    }
188
189
    /**
190
     * Lists the indexes for a given table returning an array of Index instances.
191
     *
192
     * Keys of the portable indexes list are all lower-cased.
193
     *
194
     * @param string $table The name of the table.
195
     *
196
     * @return \Doctrine\DBAL\Schema\Index[]
197
     */
198 33
    public function listTableIndexes($table)
199
    {
200 33
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
201
202 33
        $tableIndexes = $this->_conn->fetchAll($sql);
203
204 33
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
205
    }
206
207
    /**
208
     * Returns true if all the given tables exist.
209
     *
210
     * @param array $tableNames
211
     *
212
     * @return bool
213
     */
214 61
    public function tablesExist($tableNames)
215
    {
216 61
        $tableNames = array_map('strtolower', (array) $tableNames);
217
218 61
        return count($tableNames) == count(\array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
219
    }
220
221
    /**
222
     * Returns a list of all tables in the current database.
223
     *
224
     * @return array
225
     */
226 64
    public function listTableNames()
227
    {
228 64
        $sql = $this->_platform->getListTablesSQL();
229
230 64
        $tables = $this->_conn->fetchAll($sql);
231 64
        $tableNames = $this->_getPortableTablesList($tables);
232
233 64
        return $this->filterAssetNames($tableNames);
234
    }
235
236
    /**
237
     * Filters asset names if they are configured to return only a subset of all
238
     * the found elements.
239
     *
240
     * @param array $assetNames
241
     *
242
     * @return array
243
     */
244 64
    protected function filterAssetNames($assetNames)
245
    {
246 64
        $filterExpr = $this->getFilterSchemaAssetsExpression();
247 64
        if ( ! $filterExpr) {
248 64
            return $assetNames;
249
        }
250
251
        return array_values(
252
            array_filter($assetNames, function ($assetName) use ($filterExpr) {
253
                $assetName = ($assetName instanceof AbstractAsset) ? $assetName->getName() : $assetName;
254
255
                return preg_match($filterExpr, $assetName);
256
            })
257
        );
258
    }
259
260
    /**
261
     * @return string|null
262
     */
263 64
    protected function getFilterSchemaAssetsExpression()
264
    {
265 64
        return $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression();
266
    }
267
268
    /**
269
     * Lists the tables for this connection.
270
     *
271
     * @return \Doctrine\DBAL\Schema\Table[]
272
     */
273 5
    public function listTables()
274
    {
275 5
        $tableNames = $this->listTableNames();
276
277 5
        $tables = [];
278 5
        foreach ($tableNames as $tableName) {
279 4
            $tables[] = $this->listTableDetails($tableName);
280
        }
281
282 5
        return $tables;
283
    }
284
285
    /**
286
     * @param string $tableName
287
     *
288
     * @return \Doctrine\DBAL\Schema\Table
289
     */
290 29
    public function listTableDetails($tableName)
291
    {
292 29
        $columns = $this->listTableColumns($tableName);
293 29
        $foreignKeys = [];
294 29
        if ($this->_platform->supportsForeignKeyConstraints()) {
295
            $foreignKeys = $this->listTableForeignKeys($tableName);
296
        }
297 29
        $indexes = $this->listTableIndexes($tableName);
298
299 29
        return new Table($tableName, $columns, $indexes, $foreignKeys, false, []);
300
    }
301
302
    /**
303
     * Lists the views this connection has.
304
     *
305
     * @return \Doctrine\DBAL\Schema\View[]
306
     */
307 1
    public function listViews()
308
    {
309 1
        $database = $this->_conn->getDatabase();
310 1
        $sql = $this->_platform->getListViewsSQL($database);
311 1
        $views = $this->_conn->fetchAll($sql);
312
313 1
        return $this->_getPortableViewsList($views);
314
    }
315
316
    /**
317
     * Lists the foreign keys for the given table.
318
     *
319
     * @param string      $table    The name of the table.
320
     * @param string|null $database
321
     *
322
     * @return \Doctrine\DBAL\Schema\ForeignKeyConstraint[]
323
     */
324 1
    public function listTableForeignKeys($table, $database = null)
325
    {
326 1
        if (is_null($database)) {
327 1
            $database = $this->_conn->getDatabase();
328
        }
329 1
        $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

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