Failed Conditions
Push — master ( 656579...2742cd )
by Marco
11:55
created

AbstractSchemaManager   F

Complexity

Total Complexity 117

Size/Duplication

Total Lines 1073
Duplicated Lines 3.36 %

Test Coverage

Coverage 63.92%

Importance

Changes 0
Metric Value
wmc 117
dl 36
loc 1073
ccs 202
cts 316
cp 0.6392
rs 0.8021
c 0
b 0
f 0

65 Methods

Rating   Name   Duplication   Size   Complexity  
A createDatabase() 0 3 1
A createSchema() 0 17 3
A dropAndCreateSequence() 0 4 1
A dropAndCreateConstraint() 0 4 1
A createSequence() 0 3 1
A _getPortableTriggerDefinition() 0 3 1
A filterAssetNames() 0 12 3
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() 7 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() 11 11 2
A dropConstraint() 0 3 1
A dropView() 0 3 1
D _getPortableTableIndexesList() 7 49 12
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
A createSchemaConfig() 0 16 3
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() 9 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 _getPortableSequenceDefinition() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

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

Common duplication problems, and corresponding solutions are:

Complex Class

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

Complex classes like 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
28
/**
29
 * Base class for schema managers. Schema managers are used to inspect and/or
30
 * modify the database schema/structure.
31
 *
32
 * @author Konsta Vesterinen <[email protected]>
33
 * @author Lukas Smith <[email protected]> (PEAR MDB2 library)
34
 * @author Roman Borschel <[email protected]>
35
 * @author Jonathan H. Wage <[email protected]>
36
 * @author Benjamin Eberlei <[email protected]>
37
 * @since  2.0
38
 */
39
abstract class AbstractSchemaManager
40
{
41
    /**
42
     * Holds instance of the Doctrine connection for this schema manager.
43
     *
44
     * @var \Doctrine\DBAL\Connection
45
     */
46
    protected $_conn;
47
48
    /**
49
     * Holds instance of the database platform used for this schema manager.
50
     *
51
     * @var \Doctrine\DBAL\Platforms\AbstractPlatform
52
     */
53
    protected $_platform;
54
55
    /**
56
     * Constructor. Accepts the Connection instance to manage the schema for.
57
     *
58
     * @param \Doctrine\DBAL\Connection                      $conn
59
     * @param \Doctrine\DBAL\Platforms\AbstractPlatform|null $platform
60
     */
61 50
    public function __construct(\Doctrine\DBAL\Connection $conn, AbstractPlatform $platform = null)
62
    {
63 50
        $this->_conn     = $conn;
64 50
        $this->_platform = $platform ?: $this->_conn->getDatabasePlatform();
65 50
    }
66
67
    /**
68
     * Returns the associated platform.
69
     *
70
     * @return \Doctrine\DBAL\Platforms\AbstractPlatform
71
     */
72 13
    public function getDatabasePlatform()
73
    {
74 13
        return $this->_platform;
75
    }
76
77
    /**
78
     * Tries any method on the schema manager. Normally a method throws an
79
     * exception when your DBMS doesn't support it or if an error occurs.
80
     * This method allows you to try and method on your SchemaManager
81
     * instance and will return false if it does not work or is not supported.
82
     *
83
     * <code>
84
     * $result = $sm->tryMethod('dropView', 'view_name');
85
     * </code>
86
     *
87
     * @return mixed
88
     */
89 49
    public function tryMethod()
90
    {
91 49
        $args = func_get_args();
92 49
        $method = $args[0];
93 49
        unset($args[0]);
94 49
        $args = array_values($args);
95
96
        try {
97 49
            return call_user_func_array([$this, $method], $args);
98 14
        } catch (\Exception $e) {
99 14
            return false;
100
        }
101
    }
102
103
    /**
104
     * Lists the available databases for this connection.
105
     *
106
     * @return array
107
     */
108 1
    public function listDatabases()
109
    {
110 1
        $sql = $this->_platform->getListDatabasesSQL();
111
112
        $databases = $this->_conn->fetchAll($sql);
113
114
        return $this->_getPortableDatabasesList($databases);
115
    }
116
117
    /**
118
     * Returns a list of all namespaces in the current database.
119
     *
120
     * @return array
121
     */
122
    public function listNamespaceNames()
123
    {
124
        $sql = $this->_platform->getListNamespacesSQL();
125
126
        $namespaces = $this->_conn->fetchAll($sql);
127
128
        return $this->getPortableNamespacesList($namespaces);
129
    }
130
131
    /**
132
     * Lists the available sequences for this connection.
133
     *
134
     * @param string|null $database
135
     *
136
     * @return \Doctrine\DBAL\Schema\Sequence[]
137
     */
138 1
    public function listSequences($database = null)
139
    {
140 1
        if (is_null($database)) {
141
            $database = $this->_conn->getDatabase();
142
        }
143 1
        $sql = $this->_platform->getListSequencesSQL($database);
144
145 1
        $sequences = $this->_conn->fetchAll($sql);
146
147 1
        return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
148
    }
149
150
    /**
151
     * Lists the columns for a given table.
152
     *
153
     * In contrast to other libraries and to the old version of Doctrine,
154
     * this column definition does try to contain the 'primary' field for
155
     * the reason that it is not portable across different RDBMS. Use
156
     * {@see listTableIndexes($tableName)} to retrieve the primary key
157
     * of a table. We're a RDBMS specifies more details these are held
158
     * in the platformDetails array.
159
     *
160
     * @param string      $table    The name of the table.
161
     * @param string|null $database
162
     *
163
     * @return \Doctrine\DBAL\Schema\Column[]
164
     */
165 40 View Code Duplication
    public function listTableColumns($table, $database = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
166
    {
167 40
        if ( ! $database) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $database of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
168 40
            $database = $this->_conn->getDatabase();
169
        }
170
171 40
        $sql = $this->_platform->getListTableColumnsSQL($table, $database);
172
173 40
        $tableColumns = $this->_conn->fetchAll($sql);
174
175 40
        return $this->_getPortableTableColumnList($table, $database, $tableColumns);
176
    }
177
178
    /**
179
     * Lists the indexes for a given table returning an array of Index instances.
180
     *
181
     * Keys of the portable indexes list are all lower-cased.
182
     *
183
     * @param string $table The name of the table.
184
     *
185
     * @return \Doctrine\DBAL\Schema\Index[]
186
     */
187 33
    public function listTableIndexes($table)
188
    {
189 33
        $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
190
191 33
        $tableIndexes = $this->_conn->fetchAll($sql);
192
193 33
        return $this->_getPortableTableIndexesList($tableIndexes, $table);
194
    }
195
196
    /**
197
     * Returns true if all the given tables exist.
198
     *
199
     * @param array $tableNames
200
     *
201
     * @return boolean
202
     */
203 61
    public function tablesExist($tableNames)
204
    {
205 61
        $tableNames = array_map('strtolower', (array) $tableNames);
206
207 61
        return count($tableNames) == count(\array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
208
    }
209
210
    /**
211
     * Returns a list of all tables in the current database.
212
     *
213
     * @return array
214
     */
215 64
    public function listTableNames()
216
    {
217 64
        $sql = $this->_platform->getListTablesSQL();
218
219 64
        $tables = $this->_conn->fetchAll($sql);
220 64
        $tableNames = $this->_getPortableTablesList($tables);
221
222 64
        return $this->filterAssetNames($tableNames);
223
    }
224
225
    /**
226
     * Filters asset names if they are configured to return only a subset of all
227
     * the found elements.
228
     *
229
     * @param array $assetNames
230
     *
231
     * @return array
232
     */
233 65
    protected function filterAssetNames($assetNames)
234
    {
235 65
        $filterExpr = $this->getFilterSchemaAssetsExpression();
236 65
        if ( ! $filterExpr) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $filterExpr of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
237 64
            return $assetNames;
238
        }
239
240 1
        return array_values(
241 1
            array_filter($assetNames, function ($assetName) use ($filterExpr) {
242 1
                $assetName = ($assetName instanceof AbstractAsset) ? $assetName->getName() : $assetName;
243
244 1
                return preg_match($filterExpr, $assetName);
245 1
            })
246
        );
247
    }
248
249
    /**
250
     * @return string|null
251
     */
252 65
    protected function getFilterSchemaAssetsExpression()
253
    {
254 65
        return $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression();
255
    }
256
257
    /**
258
     * Lists the tables for this connection.
259
     *
260
     * @return \Doctrine\DBAL\Schema\Table[]
261
     */
262 5
    public function listTables()
263
    {
264 5
        $tableNames = $this->listTableNames();
265
266 5
        $tables = [];
267 5
        foreach ($tableNames as $tableName) {
268 4
            $tables[] = $this->listTableDetails($tableName);
269
        }
270
271 5
        return $tables;
272
    }
273
274
    /**
275
     * @param string $tableName
276
     *
277
     * @return \Doctrine\DBAL\Schema\Table
278
     */
279 29
    public function listTableDetails($tableName)
280
    {
281 29
        $columns = $this->listTableColumns($tableName);
282 29
        $foreignKeys = [];
283 29
        if ($this->_platform->supportsForeignKeyConstraints()) {
284
            $foreignKeys = $this->listTableForeignKeys($tableName);
285
        }
286 29
        $indexes = $this->listTableIndexes($tableName);
287
288 29
        return new Table($tableName, $columns, $indexes, $foreignKeys, false, []);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type integer expected by parameter $idGeneratorType of Doctrine\DBAL\Schema\Table::__construct(). ( Ignorable by Annotation )

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

288
        return new Table($tableName, $columns, $indexes, $foreignKeys, /** @scrutinizer ignore-type */ false, []);
Loading history...
289
    }
290
291
    /**
292
     * Lists the views this connection has.
293
     *
294
     * @return \Doctrine\DBAL\Schema\View[]
295
     */
296 1
    public function listViews()
297
    {
298 1
        $database = $this->_conn->getDatabase();
299 1
        $sql = $this->_platform->getListViewsSQL($database);
300 1
        $views = $this->_conn->fetchAll($sql);
301
302 1
        return $this->_getPortableViewsList($views);
303
    }
304
305
    /**
306
     * Lists the foreign keys for the given table.
307
     *
308
     * @param string      $table    The name of the table.
309
     * @param string|null $database
310
     *
311
     * @return \Doctrine\DBAL\Schema\ForeignKeyConstraint[]
312
     */
313 1 View Code Duplication
    public function listTableForeignKeys($table, $database = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
314
    {
315 1
        if (is_null($database)) {
316 1
            $database = $this->_conn->getDatabase();
317
        }
318 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

318
        /** @scrutinizer ignore-call */ 
319
        $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...
319 1
        $tableForeignKeys = $this->_conn->fetchAll($sql);
320
321 1
        return $this->_getPortableTableForeignKeysList($tableForeignKeys);
322
    }
323
324
    /* drop*() Methods */
325
326
    /**
327
     * Drops a database.
328
     *
329
     * NOTE: You can not drop the database this SchemaManager is currently connected to.
330
     *
331
     * @param string $database The name of the database to drop.
332
     *
333
     * @return void
334
     */
335
    public function dropDatabase($database)
336
    {
337
        $this->_execSql($this->_platform->getDropDatabaseSQL($database));
338
    }
339
340
    /**
341
     * Drops the given table.
342
     *
343
     * @param string $tableName The name of the table to drop.
344
     *
345
     * @return void
346
     */
347 61
    public function dropTable($tableName)
348
    {
349 61
        $this->_execSql($this->_platform->getDropTableSQL($tableName));
350 46
    }
351
352
    /**
353
     * Drops the index from the given table.
354
     *
355
     * @param \Doctrine\DBAL\Schema\Index|string $index The name of the index.
356
     * @param \Doctrine\DBAL\Schema\Table|string $table The name of the table.
357
     *
358
     * @return void
359
     */
360 1
    public function dropIndex($index, $table)
361
    {
362 1
        if ($index instanceof Index) {
363
            $index = $index->getQuotedName($this->_platform);
364
        }
365
366 1
        $this->_execSql($this->_platform->getDropIndexSQL($index, $table));
367 1
    }
368
369
    /**
370
     * Drops the constraint from the given table.
371
     *
372
     * @param \Doctrine\DBAL\Schema\Constraint   $constraint
373
     * @param \Doctrine\DBAL\Schema\Table|string $table      The name of the table.
374
     *
375
     * @return void
376
     */
377
    public function dropConstraint(Constraint $constraint, $table)
378
    {
379
        $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table));
380
    }
381
382
    /**
383
     * Drops a foreign key from a table.
384
     *
385
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint|string $foreignKey The name of the foreign key.
386
     * @param \Doctrine\DBAL\Schema\Table|string                $table      The name of the table with the foreign key.
387
     *
388
     * @return void
389
     */
390
    public function dropForeignKey($foreignKey, $table)
391
    {
392
        $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table));
393
    }
394
395
    /**
396
     * Drops a sequence with a given name.
397
     *
398
     * @param string $name The name of the sequence to drop.
399
     *
400
     * @return void
401
     */
402
    public function dropSequence($name)
403
    {
404
        $this->_execSql($this->_platform->getDropSequenceSQL($name));
405
    }
406
407
    /**
408
     * Drops a view.
409
     *
410
     * @param string $name The name of the view.
411
     *
412
     * @return void
413
     */
414 1
    public function dropView($name)
415
    {
416 1
        $this->_execSql($this->_platform->getDropViewSQL($name));
417
    }
418
419
    /* create*() Methods */
420
421
    /**
422
     * Creates a new database.
423
     *
424
     * @param string $database The name of the database to create.
425
     *
426
     * @return void
427
     */
428
    public function createDatabase($database)
429
    {
430
        $this->_execSql($this->_platform->getCreateDatabaseSQL($database));
431
    }
432
433
    /**
434
     * Creates a new table.
435
     *
436
     * @param \Doctrine\DBAL\Schema\Table $table
437
     *
438
     * @return void
439
     */
440 117
    public function createTable(Table $table)
441
    {
442 117
        $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS;
443 117
        $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
444 85
    }
445
446
    /**
447
     * Creates a new sequence.
448
     *
449
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
450
     *
451
     * @return void
452
     *
453
     * @throws \Doctrine\DBAL\ConnectionException If something fails at database level.
454
     */
455
    public function createSequence($sequence)
456
    {
457
        $this->_execSql($this->_platform->getCreateSequenceSQL($sequence));
458
    }
459
460
    /**
461
     * Creates a constraint on a table.
462
     *
463
     * @param \Doctrine\DBAL\Schema\Constraint   $constraint
464
     * @param \Doctrine\DBAL\Schema\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
473
    /**
474
     * Creates a new index on a table.
475
     *
476
     * @param \Doctrine\DBAL\Schema\Index        $index
477
     * @param \Doctrine\DBAL\Schema\Table|string $table The name of the table on which the index is to be created.
478
     *
479
     * @return void
480
     */
481 1
    public function createIndex(Index $index, $table)
482
    {
483 1
        $this->_execSql($this->_platform->getCreateIndexSQL($index, $table));
484 1
    }
485
486
    /**
487
     * Creates a new foreign key.
488
     *
489
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey The ForeignKey instance.
490
     * @param \Doctrine\DBAL\Schema\Table|string         $table      The name of the table on which the foreign key is to be created.
491
     *
492
     * @return void
493
     */
494
    public function createForeignKey(ForeignKeyConstraint $foreignKey, $table)
495
    {
496
        $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table));
497
    }
498
499
    /**
500
     * Creates a new view.
501
     *
502
     * @param \Doctrine\DBAL\Schema\View $view
503
     *
504
     * @return void
505
     */
506 1
    public function createView(View $view)
507
    {
508 1
        $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql()));
509 1
    }
510
511
    /* dropAndCreate*() Methods */
512
513
    /**
514
     * Drops and creates a constraint.
515
     *
516
     * @see dropConstraint()
517
     * @see createConstraint()
518
     *
519
     * @param \Doctrine\DBAL\Schema\Constraint   $constraint
520
     * @param \Doctrine\DBAL\Schema\Table|string $table
521
     *
522
     * @return void
523
     */
524
    public function dropAndCreateConstraint(Constraint $constraint, $table)
525
    {
526
        $this->tryMethod('dropConstraint', $constraint, $table);
527
        $this->createConstraint($constraint, $table);
528
    }
529
530
    /**
531
     * Drops and creates a new index on a table.
532
     *
533
     * @param \Doctrine\DBAL\Schema\Index        $index
534
     * @param \Doctrine\DBAL\Schema\Table|string $table The name of the table on which the index is to be created.
535
     *
536
     * @return void
537
     */
538 1
    public function dropAndCreateIndex(Index $index, $table)
539
    {
540 1
        $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table);
541 1
        $this->createIndex($index, $table);
542 1
    }
543
544
    /**
545
     * Drops and creates a new foreign key.
546
     *
547
     * @param \Doctrine\DBAL\Schema\ForeignKeyConstraint $foreignKey An associative array that defines properties of the foreign key to be created.
548
     * @param \Doctrine\DBAL\Schema\Table|string         $table      The name of the table on which the foreign key is to be created.
549
     *
550
     * @return void
551
     */
552
    public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table)
553
    {
554
        $this->tryMethod('dropForeignKey', $foreignKey, $table);
555
        $this->createForeignKey($foreignKey, $table);
556
    }
557
558
    /**
559
     * Drops and create a new sequence.
560
     *
561
     * @param \Doctrine\DBAL\Schema\Sequence $sequence
562
     *
563
     * @return void
564
     *
565
     * @throws \Doctrine\DBAL\ConnectionException If something fails at database level.
566
     */
567
    public function dropAndCreateSequence(Sequence $sequence)
568
    {
569
        $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform));
570
        $this->createSequence($sequence);
571
    }
572
573
    /**
574
     * Drops and creates a new table.
575
     *
576
     * @param \Doctrine\DBAL\Schema\Table $table
577
     *
578
     * @return void
579
     */
580 48
    public function dropAndCreateTable(Table $table)
581
    {
582 48
        $this->tryMethod('dropTable', $table->getQuotedName($this->_platform));
583 48
        $this->createTable($table);
584 48
    }
585
586
    /**
587
     * Drops and creates a new database.
588
     *
589
     * @param string $database The name of the database to create.
590
     *
591
     * @return void
592
     */
593 1
    public function dropAndCreateDatabase($database)
594
    {
595 1
        $this->tryMethod('dropDatabase', $database);
596 1
        $this->createDatabase($database);
597 1
    }
598
599
    /**
600
     * Drops and creates a new view.
601
     *
602
     * @param \Doctrine\DBAL\Schema\View $view
603
     *
604
     * @return void
605
     */
606 1
    public function dropAndCreateView(View $view)
607
    {
608 1
        $this->tryMethod('dropView', $view->getQuotedName($this->_platform));
609 1
        $this->createView($view);
610 1
    }
611
612
    /* alterTable() Methods */
613
614
    /**
615
     * Alters an existing tables schema.
616
     *
617
     * @param \Doctrine\DBAL\Schema\TableDiff $tableDiff
618
     *
619
     * @return void
620
     */
621 14
    public function alterTable(TableDiff $tableDiff)
622
    {
623 14
        $queries = $this->_platform->getAlterTableSQL($tableDiff);
624 14
        if (is_array($queries) && count($queries)) {
625 14
            foreach ($queries as $ddlQuery) {
626 14
                $this->_execSql($ddlQuery);
627
            }
628
        }
629 14
    }
630
631
    /**
632
     * Renames a given table to another name.
633
     *
634
     * @param string $name    The current name of the table.
635
     * @param string $newName The new name of the table.
636
     *
637
     * @return void
638
     */
639
    public function renameTable($name, $newName)
640
    {
641
        $tableDiff = new TableDiff($name);
642
        $tableDiff->newName = $newName;
643
        $this->alterTable($tableDiff);
644
    }
645
646
    /**
647
     * Methods for filtering return values of list*() methods to convert
648
     * the native DBMS data definition to a portable Doctrine definition
649
     */
650
651
    /**
652
     * @param array $databases
653
     *
654
     * @return array
655
     */
656
    protected function _getPortableDatabasesList($databases)
657
    {
658
        $list = [];
659
        foreach ($databases as $value) {
660
            if ($value = $this->_getPortableDatabaseDefinition($value)) {
661
                $list[] = $value;
662
            }
663
        }
664
665
        return $list;
666
    }
667
668
    /**
669
     * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition.
670
     *
671
     * @param array $namespaces The list of namespace names in the native DBMS data definition.
672
     *
673
     * @return array
674
     */
675
    protected function getPortableNamespacesList(array $namespaces)
676
    {
677
        $namespacesList = [];
678
679
        foreach ($namespaces as $namespace) {
680
            $namespacesList[] = $this->getPortableNamespaceDefinition($namespace);
681
        }
682
683
        return $namespacesList;
684
    }
685
686
    /**
687
     * @param array $database
688
     *
689
     * @return mixed
690
     */
691
    protected function _getPortableDatabaseDefinition($database)
692
    {
693
        return $database;
694
    }
695
696
    /**
697
     * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition.
698
     *
699
     * @param array $namespace The native DBMS namespace definition.
700
     *
701
     * @return mixed
702
     */
703
    protected function getPortableNamespaceDefinition(array $namespace)
704
    {
705
        return $namespace;
706
    }
707
708
    /**
709
     * @param array $functions
710
     *
711
     * @return array
712
     */
713
    protected function _getPortableFunctionsList($functions)
714
    {
715
        $list = [];
716
        foreach ($functions as $value) {
717
            if ($value = $this->_getPortableFunctionDefinition($value)) {
718
                $list[] = $value;
719
            }
720
        }
721
722
        return $list;
723
    }
724
725
    /**
726
     * @param array $function
727
     *
728
     * @return mixed
729
     */
730
    protected function _getPortableFunctionDefinition($function)
731
    {
732
        return $function;
733
    }
734
735
    /**
736
     * @param array $triggers
737
     *
738
     * @return array
739
     */
740
    protected function _getPortableTriggersList($triggers)
741
    {
742
        $list = [];
743
        foreach ($triggers as $value) {
744
            if ($value = $this->_getPortableTriggerDefinition($value)) {
745
                $list[] = $value;
746
            }
747
        }
748
749
        return $list;
750
    }
751
752
    /**
753
     * @param array $trigger
754
     *
755
     * @return mixed
756
     */
757
    protected function _getPortableTriggerDefinition($trigger)
758
    {
759
        return $trigger;
760
    }
761
762
    /**
763
     * @param array $sequences
764
     *
765
     * @return array
766
     */
767
    protected function _getPortableSequencesList($sequences)
768
    {
769
        $list = [];
770
        foreach ($sequences as $value) {
771
            if ($value = $this->_getPortableSequenceDefinition($value)) {
772
                $list[] = $value;
773
            }
774
        }
775
776
        return $list;
777
    }
778
779
    /**
780
     * @param array $sequence
781
     *
782
     * @return \Doctrine\DBAL\Schema\Sequence
783
     *
784
     * @throws \Doctrine\DBAL\DBALException
785
     */
786
    protected function _getPortableSequenceDefinition($sequence)
787
    {
788
        throw DBALException::notSupported('Sequences');
789
    }
790
791
    /**
792
     * Independent of the database the keys of the column list result are lowercased.
793
     *
794
     * The name of the created column instance however is kept in its case.
795
     *
796
     * @param string $table        The name of the table.
797
     * @param string $database
798
     * @param array  $tableColumns
799
     *
800
     * @return array
801
     */
802 40
    protected function _getPortableTableColumnList($table, $database, $tableColumns)
803
    {
804 40
        $eventManager = $this->_platform->getEventManager();
805
806 40
        $list = [];
807 40
        foreach ($tableColumns as $tableColumn) {
808 40
            $column = null;
809 40
            $defaultPrevented = false;
810
811 40 View Code Duplication
            if (null !== $eventManager && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
812 1
                $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn);
813 1
                $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs);
814
815 1
                $defaultPrevented = $eventArgs->isDefaultPrevented();
816 1
                $column = $eventArgs->getColumn();
817
            }
818
819 40
            if ( ! $defaultPrevented) {
820 40
                $column = $this->_getPortableTableColumnDefinition($tableColumn);
821
            }
822
823 40
            if ($column) {
824 40
                $name = strtolower($column->getQuotedName($this->_platform));
825 40
                $list[$name] = $column;
826
            }
827
        }
828
829 40
        return $list;
830
    }
831
832
    /**
833
     * Gets Table Column Definition.
834
     *
835
     * @param array $tableColumn
836
     *
837
     * @return \Doctrine\DBAL\Schema\Column
838
     */
839
    abstract protected function _getPortableTableColumnDefinition($tableColumn);
840
841
    /**
842
     * Aggregates and groups the index results according to the required data result.
843
     *
844
     * @param array       $tableIndexRows
845
     * @param string|null $tableName
846
     *
847
     * @return array
848
     */
849 33
    protected function _getPortableTableIndexesList($tableIndexRows, $tableName=null)
850
    {
851 33
        $result = [];
852 33
        foreach ($tableIndexRows as $tableIndex) {
853 21
            $indexName = $keyName = $tableIndex['key_name'];
854 21
            if ($tableIndex['primary']) {
855 21
                $keyName = 'primary';
856
            }
857 21
            $keyName = strtolower($keyName);
858
859 21
            if (!isset($result[$keyName])) {
860 21
                $result[$keyName] = [
861 21
                    'name' => $indexName,
862 21
                    'columns' => [$tableIndex['column_name']],
863 21
                    'unique' => $tableIndex['non_unique'] ? false : true,
864 21
                    'primary' => $tableIndex['primary'],
865 21
                    'flags' => isset($tableIndex['flags']) ? $tableIndex['flags'] : [],
866 21
                    'options' => isset($tableIndex['where']) ? ['where' => $tableIndex['where']] : [],
867
                ];
868
            } else {
869 21
                $result[$keyName]['columns'][] = $tableIndex['column_name'];
870
            }
871
        }
872
873 33
        $eventManager = $this->_platform->getEventManager();
874
875 33
        $indexes = [];
876 33
        foreach ($result as $indexKey => $data) {
877 21
            $index = null;
878 21
            $defaultPrevented = false;
879
880 21 View Code Duplication
            if (null !== $eventManager && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
881 1
                $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
882 1
                $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
883
884 1
                $defaultPrevented = $eventArgs->isDefaultPrevented();
885 1
                $index = $eventArgs->getIndex();
886
            }
887
888 21
            if ( ! $defaultPrevented) {
889 21
                $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary'], $data['flags'], $data['options']);
890
            }
891
892 21
            if ($index) {
893 21
                $indexes[$indexKey] = $index;
894
            }
895
        }
896
897 33
        return $indexes;
898
    }
899
900
    /**
901
     * @param array $tables
902
     *
903
     * @return array
904
     */
905 64
    protected function _getPortableTablesList($tables)
906
    {
907 64
        $list = [];
908 64
        foreach ($tables as $value) {
909 63
            if ($value = $this->_getPortableTableDefinition($value)) {
910 63
                $list[] = $value;
911
            }
912
        }
913
914 64
        return $list;
915
    }
916
917
    /**
918
     * @param array $table
919
     *
920
     * @return array
921
     */
922
    protected function _getPortableTableDefinition($table)
923
    {
924
        return $table;
925
    }
926
927
    /**
928
     * @param array $users
929
     *
930
     * @return array
931
     */
932
    protected function _getPortableUsersList($users)
933
    {
934
        $list = [];
935
        foreach ($users as $value) {
936
            if ($value = $this->_getPortableUserDefinition($value)) {
937
                $list[] = $value;
938
            }
939
        }
940
941
        return $list;
942
    }
943
944
    /**
945
     * @param array $user
946
     *
947
     * @return mixed
948
     */
949
    protected function _getPortableUserDefinition($user)
950
    {
951
        return $user;
952
    }
953
954
    /**
955
     * @param array $views
956
     *
957
     * @return array
958
     */
959 1
    protected function _getPortableViewsList($views)
960
    {
961 1
        $list = [];
962 1
        foreach ($views as $value) {
963 1
            if ($view = $this->_getPortableViewDefinition($value)) {
964 1
                $viewName = strtolower($view->getQuotedName($this->_platform));
965 1
                $list[$viewName] = $view;
966
            }
967
        }
968
969 1
        return $list;
970
    }
971
972
    /**
973
     * @param array $view
974
     *
975
     * @return mixed
976
     */
977
    protected function _getPortableViewDefinition($view)
978
    {
979
        return false;
980
    }
981
982
    /**
983
     * @param array $tableForeignKeys
984
     *
985
     * @return array
986
     */
987
    protected function _getPortableTableForeignKeysList($tableForeignKeys)
988
    {
989
        $list = [];
990
        foreach ($tableForeignKeys as $value) {
991
            if ($value = $this->_getPortableTableForeignKeyDefinition($value)) {
992
                $list[] = $value;
993
            }
994
        }
995
996
        return $list;
997
    }
998
999
    /**
1000
     * @param array $tableForeignKey
1001
     *
1002
     * @return mixed
1003
     */
1004
    protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
1005
    {
1006
        return $tableForeignKey;
1007
    }
1008
1009
    /**
1010
     * @param array|string $sql
1011
     *
1012
     * @return void
1013
     */
1014 117
    protected function _execSql($sql)
1015
    {
1016 117
        foreach ((array) $sql as $query) {
1017 117
            $this->_conn->executeUpdate($query);
1018
        }
1019 85
    }
1020
1021
    /**
1022
     * Creates a schema instance for the current database.
1023
     *
1024
     * @return \Doctrine\DBAL\Schema\Schema
1025
     */
1026 4
    public function createSchema()
1027
    {
1028 4
        $namespaces = [];
1029
1030 4
        if ($this->_platform->supportsSchemas()) {
1031
            $namespaces = $this->listNamespaceNames();
1032
        }
1033
1034 4
        $sequences = [];
1035
1036 4
        if ($this->_platform->supportsSequences()) {
1037
            $sequences = $this->listSequences();
1038
        }
1039
1040 4
        $tables = $this->listTables();
1041
1042 4
        return new Schema($tables, $sequences, $this->createSchemaConfig(), $namespaces);
1043
    }
1044
1045
    /**
1046
     * Creates the configuration for this schema.
1047
     *
1048
     * @return \Doctrine\DBAL\Schema\SchemaConfig
1049
     */
1050 13
    public function createSchemaConfig()
1051
    {
1052 13
        $schemaConfig = new SchemaConfig();
1053 13
        $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
1054
1055 13
        $searchPaths = $this->getSchemaSearchPaths();
1056 13
        if (isset($searchPaths[0])) {
1057
            $schemaConfig->setName($searchPaths[0]);
1058
        }
1059
1060 13
        $params = $this->_conn->getParams();
1061 13
        if (isset($params['defaultTableOptions'])) {
1062
            $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']);
1063
        }
1064
1065 13
        return $schemaConfig;
1066
    }
1067
1068
    /**
1069
     * The search path for namespaces in the currently connected database.
1070
     *
1071
     * The first entry is usually the default namespace in the Schema. All
1072
     * further namespaces contain tables/sequences which can also be addressed
1073
     * with a short, not full-qualified name.
1074
     *
1075
     * For databases that don't support subschema/namespaces this method
1076
     * returns the name of the currently connected database.
1077
     *
1078
     * @return array
1079
     */
1080 13
    public function getSchemaSearchPaths()
1081
    {
1082 13
        return [$this->_conn->getDatabase()];
1083
    }
1084
1085
    /**
1086
     * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns
1087
     * the type given as default.
1088
     *
1089
     * @param string $comment
1090
     * @param string $currentType
1091
     *
1092
     * @return string
1093
     */
1094 23
    public function extractDoctrineTypeFromComment($comment, $currentType)
1095
    {
1096 23
        if (preg_match("(\(DC2Type:(((?!\)).)+)\))", $comment, $match)) {
1097 9
            $currentType = $match[1];
1098
        }
1099
1100 23
        return $currentType;
1101
    }
1102
1103
    /**
1104
     * @param string $comment
1105
     * @param string $type
1106
     *
1107
     * @return string
1108
     */
1109 5
    public function removeDoctrineTypeFromComment($comment, $type)
1110
    {
1111 5
        return str_replace('(DC2Type:'.$type.')', '', $comment);
1112
    }
1113
}
1114