Completed
Pull Request — master (#542)
by Luís
05:35
created

Configuration   F

Complexity

Total Complexity 100

Size/Duplication

Total Lines 908
Duplicated Lines 3.52 %

Coupling/Cohesion

Components 1
Dependencies 14

Test Coverage

Coverage 98.48%

Importance

Changes 0
Metric Value
wmc 100
lcom 1
cbo 14
dl 32
loc 908
ccs 259
cts 263
cp 0.9848
rs 1.5999
c 0
b 0
f 0

50 Methods

Rating   Name   Duplication   Size   Complexity  
A areMigrationsOrganizedByYear() 0 4 1
A areMigrationsOrganizedByYearAndMonth() 0 4 1
A validate() 0 9 3
A setName() 0 4 1
A getName() 0 4 1
A setOutputWriter() 0 4 1
A getOutputWriter() 0 4 1
A getDateTime() 0 11 2
A getConnection() 0 4 1
A setMigrationsTableName() 0 4 1
A getMigrationsTableName() 0 4 1
A setMigrationsColumnName() 0 4 1
A getMigrationsColumnName() 0 4 1
A setMigrationsDirectory() 0 4 1
A getMigrationsDirectory() 0 4 1
A setMigrationsNamespace() 0 4 1
A getMigrationsNamespace() 0 4 1
A __construct() 0 11 1
A formatVersion() 0 4 1
A setMigrationsFinder() 0 12 4
A registerMigrationsFromDirectory() 0 6 1
A registerMigration() 0 15 2
A registerMigrations() 0 9 2
A getMigrations() 0 4 1
A getVersion() 0 12 3
A hasVersion() 0 8 2
A hasVersionMigrated() 0 12 1
A getMigratedVersions() 9 9 1
A getAvailableVersions() 0 14 3
B getCurrentVersion() 0 31 5
A getPrevVersion() 0 4 1
A getNextVersion() 0 4 1
A getRelativeVersion() 0 16 4
A getDeltaVersion() 0 15 4
C resolveVersionAlias() 0 23 8
A getNumberOfExecutedMigrations() 9 9 2
A getNumberOfAvailableMigrations() 0 8 2
A getLatestVersion() 0 11 3
B createMigrationTable() 0 26 3
B getMigrationsToExecute() 0 27 6
A dispatchEvent() 0 4 1
A findMigrations() 0 4 1
A setMigrationsAreOrganizedByYear() 0 6 1
A setMigrationsAreOrganizedByYearAndMonth() 0 7 1
A generateVersionNumber() 0 6 2
A connect() 0 8 2
A ensureOrganizeMigrationsIsCompatibleWithFinder() 0 9 2
B shouldExecuteMigration() 14 18 5
A ensureMigrationClassExists() 0 6 2
A getQueryWriter() 0 12 2

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 Configuration 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 Configuration, 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 LGPL. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Migrations\Configuration;
21
22
use Doctrine\Common\EventArgs;
23
use Doctrine\DBAL\Connection;
24
use Doctrine\DBAL\Connections\MasterSlaveConnection;
25
use Doctrine\DBAL\Migrations\FileQueryWriter;
26
use Doctrine\DBAL\Migrations\Finder\MigrationDeepFinderInterface;
27
use Doctrine\DBAL\Migrations\MigrationException;
28
use Doctrine\DBAL\Migrations\OutputWriter;
29
use Doctrine\DBAL\Migrations\QueryWriter;
30
use Doctrine\DBAL\Migrations\Version;
31
use Doctrine\DBAL\Migrations\Finder\MigrationFinderInterface;
32
use Doctrine\DBAL\Migrations\Finder\RecursiveRegexFinder;
33
use Doctrine\DBAL\Schema\Column;
34
use Doctrine\DBAL\Schema\Table;
35
use Doctrine\DBAL\Types\Type;
36
37
/**
38
 * Default Migration Configuration object used for configuring an instance of
39
 * the Migration class. Set the connection, version table name, register migration
40
 * classes/versions, etc.
41
 *
42
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
43
 * @link        www.doctrine-project.org
44
 * @since       2.0
45
 * @author      Jonathan H. Wage <[email protected]>
46
 */
47
class Configuration
48
{
49
    /**
50
     * Configure versions to be organized by year.
51
     */
52
    const VERSIONS_ORGANIZATION_BY_YEAR = 'year';
53
54
    /**
55
     * Configure versions to be organized by year and month.
56
     *
57
     * @var string
58
     */
59
    const VERSIONS_ORGANIZATION_BY_YEAR_AND_MONTH = 'year_and_month';
60
61
    /**
62
     * The date format for new version numbers
63
     */
64
    const VERSION_FORMAT = 'YmdHis';
65
66
    /**
67
     * Name of this set of migrations
68
     *
69
     * @var string
70
     */
71
    private $name;
72
73
    /**
74
     * Flag for whether or not the migration table has been created
75
     *
76
     * @var boolean
77
     */
78
    private $migrationTableCreated = false;
79
80
    /**
81
     * Connection instance to use for migrations
82
     *
83
     * @var Connection
84
     */
85
    private $connection;
86
87
    /**
88
     * OutputWriter instance for writing output during migrations
89
     *
90
     * @var OutputWriter
91
     */
92
    private $outputWriter;
93
94
    /**
95
     * The migration finder implementation -- used to load migrations from a
96
     * directory.
97
     *
98
     * @var MigrationFinderInterface
99
     */
100
    private $migrationFinder;
101
102
    /**
103
     * @var QueryWriter
104
     */
105
    private $queryWriter;
106
107
    /**
108
     * The migration table name to track versions in
109
     *
110
     * @var string
111
     */
112
    private $migrationsTableName = 'doctrine_migration_versions';
113
114
    /**
115
     * The migration column name to track versions in
116
     *
117
     * @var string
118
     */
119
    private $migrationsColumnName = 'version';
120
121
    /**
122
     * The path to a directory where new migration classes will be written
123
     *
124
     * @var string
125
     */
126
    private $migrationsDirectory;
127
128
    /**
129
     * Namespace the migration classes live in
130
     *
131
     * @var string
132
     */
133
    private $migrationsNamespace;
134
135
    /**
136
     * Array of the registered migrations
137
     *
138
     * @var Version[]
139
     */
140
    private $migrations = [];
141
142
    /**
143
     * Versions are organized by year.
144
     *
145
     * @var boolean
146
     */
147
    private $migrationsAreOrganizedByYear = false;
148
149
    /**
150
     * Versions are organized by year and month.
151
     *
152
     * @var boolean
153
     */
154
    private $migrationsAreOrganizedByYearAndMonth = false;
155
156
    /**
157
     * Construct a migration configuration object.
158
     *
159
     * @param Connection               $connection   A Connection instance
160
     * @param OutputWriter             $outputWriter A OutputWriter instance
161
     * @param MigrationFinderInterface $finder       Migration files finder
162
     * @param QueryWriter|null         $queryWriter
163
     */
164 275
    public function __construct(
165
        Connection $connection,
166
        OutputWriter $outputWriter = null,
167
        MigrationFinderInterface $finder = null,
168
        QueryWriter $queryWriter = null
169
    ) {
170 275
        $this->connection      = $connection;
171 275
        $this->outputWriter    = $outputWriter ?? new OutputWriter();
172 275
        $this->migrationFinder = $finder ?? new RecursiveRegexFinder();
173 275
        $this->queryWriter     = $queryWriter;
174 275
    }
175
176
    /**
177
     * @return bool
178
     */
179 22
    public function areMigrationsOrganizedByYear()
180
    {
181 22
        return $this->migrationsAreOrganizedByYear;
182
    }
183
184
    /**
185
     * @return bool
186
     */
187 22
    public function areMigrationsOrganizedByYearAndMonth()
188
    {
189 22
        return $this->migrationsAreOrganizedByYearAndMonth;
190
    }
191
192
    /**
193
     * Validation that this instance has all the required properties configured
194
     *
195
     * @throws MigrationException
196
     */
197 146
    public function validate()
198
    {
199 146
        if ( ! $this->migrationsNamespace) {
200 10
            throw MigrationException::migrationsNamespaceRequired();
201
        }
202 136
        if ( ! $this->migrationsDirectory) {
203 10
            throw MigrationException::migrationsDirectoryRequired();
204
        }
205 126
    }
206
207
    /**
208
     * Set the name of this set of migrations
209
     *
210
     * @param string $name The name of this set of migrations
211
     */
212 63
    public function setName($name)
213
    {
214 63
        $this->name = $name;
215 63
    }
216
217
    /**
218
     * Returns the name of this set of migrations
219
     *
220
     * @return string $name The name of this set of migrations
221
     */
222 16
    public function getName()
223
    {
224 16
        return $this->name;
225
    }
226
227
    /**
228
     * Sets the output writer.
229
     *
230
     * @param OutputWriter $outputWriter
231
     */
232 3
    public function setOutputWriter(OutputWriter $outputWriter)
233
    {
234 3
        $this->outputWriter = $outputWriter;
235 3
    }
236
237
    /**
238
     * Returns the OutputWriter instance
239
     *
240
     * @return OutputWriter $outputWriter  The OutputWriter instance
241
     */
242 117
    public function getOutputWriter()
243
    {
244 117
        return $this->outputWriter;
245
    }
246
247
    /**
248
     * Returns a timestamp version as a formatted date
249
     *
250
     * @param string $version
251
     *
252
     * @return string The formatted version
253
     * @deprecated
254
     */
255 14
    public function formatVersion($version)
256
    {
257 14
        return $this->getDateTime($version);
258
    }
259
260
    /**
261
     * Returns the datetime of a migration
262
     *
263
     * @param $version
264
     * @return string
265
     */
266 22
    public function getDateTime($version)
267
    {
268 22
        $datetime = str_replace('Version', '', $version);
269 22
        $datetime = \DateTime::createFromFormat('YmdHis', $datetime);
270
271 22
        if ($datetime === false) {
272 8
            return '';
273
        }
274
275 15
        return $datetime->format('Y-m-d H:i:s');
276
    }
277
278
    /**
279
     * Returns the Connection instance
280
     *
281
     * @return Connection $connection  The Connection instance
282
     */
283 120
    public function getConnection()
284
    {
285 120
        return $this->connection;
286
    }
287
288
    /**
289
     * Set the migration table name
290
     *
291
     * @param string $tableName The migration table name
292
     */
293 85
    public function setMigrationsTableName($tableName)
294
    {
295 85
        $this->migrationsTableName = $tableName;
296 85
    }
297
298
    /**
299
     * Returns the migration table name
300
     *
301
     * @return string $migrationsTableName The migration table name
302
     */
303 60
    public function getMigrationsTableName()
304
    {
305 60
        return $this->migrationsTableName;
306
    }
307
308
    /**
309
     * Set the migration column name
310
     *
311
     * @param string $columnName The migration column name
312
     */
313 56
    public function setMigrationsColumnName($columnName)
314
    {
315 56
        $this->migrationsColumnName = $columnName;
316 56
    }
317
318
    /**
319
     * Returns the migration column name
320
     *
321
     * @return string $migrationsColumnName The migration column name
322
     */
323 54
    public function getMigrationsColumnName()
324
    {
325 54
        return $this->migrationsColumnName;
326
    }
327
328
    /**
329
     * Set the new migrations directory where new migration classes are generated
330
     *
331
     * @param string $migrationsDirectory The new migrations directory
332
     */
333 183
    public function setMigrationsDirectory($migrationsDirectory)
334
    {
335 183
        $this->migrationsDirectory = $migrationsDirectory;
336 183
    }
337
338
    /**
339
     * Returns the new migrations directory where new migration classes are generated
340
     *
341
     * @return string $migrationsDirectory The new migrations directory
342
     */
343 65
    public function getMigrationsDirectory()
344
    {
345 65
        return $this->migrationsDirectory;
346
    }
347
348
    /**
349
     * Set the migrations namespace
350
     *
351
     * @param string $migrationsNamespace The migrations namespace
352
     */
353 195
    public function setMigrationsNamespace($migrationsNamespace)
354
    {
355 195
        $this->migrationsNamespace = $migrationsNamespace;
356 195
    }
357
358
    /**
359
     * Returns the migrations namespace
360
     *
361
     * @return string $migrationsNamespace The migrations namespace
362
     */
363 92
    public function getMigrationsNamespace()
364
    {
365 92
        return $this->migrationsNamespace;
366
    }
367
368
    /**
369
     * Set the implementation of the migration finder.
370
     *
371
     * @param MigrationFinderInterface $finder The new migration finder
372
     * @throws MigrationException
373
     */
374 8
    public function setMigrationsFinder(MigrationFinderInterface $finder)
375
    {
376 8
        if (($this->migrationsAreOrganizedByYear || $this->migrationsAreOrganizedByYearAndMonth)
377 8
            && ! ($finder instanceof MigrationDeepFinderInterface)) {
378 4
            throw MigrationException::configurationIncompatibleWithFinder(
379 4
                'organize-migrations',
380 4
                $finder
381
            );
382
        }
383
384 4
        $this->migrationFinder = $finder;
385 4
    }
386
387
    /**
388
     * Register migrations from a given directory. Recursively finds all files
389
     * with the pattern VersionYYYYMMDDHHMMSS.php as the filename and registers
390
     * them as migrations.
391
     *
392
     * @param string $path The root directory to where some migration classes live.
393
     *
394
     * @return Version[] The array of migrations registered.
395
     */
396 103
    public function registerMigrationsFromDirectory($path)
397
    {
398 103
        $this->validate();
399
400 87
        return $this->registerMigrations($this->findMigrations($path));
401
    }
402
403
    /**
404
     * Register a single migration version to be executed by a AbstractMigration
405
     * class.
406
     *
407
     * @param string $version The version of the migration in the format YYYYMMDDHHMMSS.
408
     * @param string $class   The migration class to execute for the version.
409
     *
410
     * @return Version
411
     *
412
     * @throws MigrationException
413
     */
414 69
    public function registerMigration($version, $class)
415
    {
416 69
        $this->ensureMigrationClassExists($class);
417
418 68
        $version = (string) $version;
419 68
        $class   = (string) $class;
420 68
        if (isset($this->migrations[$version])) {
421 1
            throw MigrationException::duplicateMigrationVersion($version, get_class($this->migrations[$version]));
422
        }
423 68
        $version                                  = new Version($this, $version, $class);
424 68
        $this->migrations[$version->getVersion()] = $version;
425 68
        ksort($this->migrations, SORT_STRING);
426
427 68
        return $version;
428
    }
429
430
    /**
431
     * Register an array of migrations. Each key of the array is the version and
432
     * the value is the migration class name.
433
     *
434
     *
435
     * @param array $migrations
436
     *
437
     * @return Version[]
438
     */
439 91
    public function registerMigrations(array $migrations)
440
    {
441 91
        $versions = [];
442 91
        foreach ($migrations as $version => $class) {
443 34
            $versions[] = $this->registerMigration($version, $class);
444
        }
445
446 90
        return $versions;
447
    }
448
449
    /**
450
     * Get the array of registered migration versions.
451
     *
452
     * @return Version[] $migrations
453
     */
454 35
    public function getMigrations()
455
    {
456 35
        return $this->migrations;
457
    }
458
459
    /**
460
     * Returns the Version instance for a given version in the format YYYYMMDDHHMMSS.
461
     *
462
     * @param string $version The version string in the format YYYYMMDDHHMMSS.
463
     *
464
     * @return Version
465
     *
466
     * @throws MigrationException Throws exception if migration version does not exist.
467
     */
468 20
    public function getVersion($version)
469
    {
470 20
        if (empty($this->migrations)) {
471 7
            $this->registerMigrationsFromDirectory($this->getMigrationsDirectory());
472
        }
473
474 20
        if ( ! isset($this->migrations[$version])) {
475 2
            throw MigrationException::unknownMigrationVersion($version);
476
        }
477
478 18
        return $this->migrations[$version];
479
    }
480
481
    /**
482
     * Check if a version exists.
483
     *
484
     * @param string $version
485
     *
486
     * @return boolean
487
     */
488 22
    public function hasVersion($version)
489
    {
490 22
        if (empty($this->migrations)) {
491 4
            $this->registerMigrationsFromDirectory($this->getMigrationsDirectory());
492
        }
493
494 20
        return isset($this->migrations[$version]);
495
    }
496
497
    /**
498
     * Check if a version has been migrated or not yet
499
     *
500
     * @param Version $version
501
     *
502
     * @return boolean
503
     */
504 21
    public function hasVersionMigrated(Version $version)
505
    {
506 21
        $this->connect();
507 21
        $this->createMigrationTable();
508
509 21
        $version = $this->connection->fetchColumn(
510 21
            "SELECT " . $this->migrationsColumnName . " FROM " . $this->migrationsTableName . " WHERE " . $this->migrationsColumnName . " = ?",
511 21
            [$version->getVersion()]
512
        );
513
514 21
        return $version !== false;
515
    }
516
517
    /**
518
     * Returns all migrated versions from the versions table, in an array.
519
     *
520
     * @return Version[]
521
     */
522 41 View Code Duplication
    public function getMigratedVersions()
523
    {
524 41
        $this->connect();
525 41
        $this->createMigrationTable();
526
527 41
        $ret = $this->connection->fetchAll("SELECT " . $this->migrationsColumnName . " FROM " . $this->migrationsTableName);
528
529 41
        return array_map('current', $ret);
530
    }
531
532
    /**
533
     * Returns an array of available migration version numbers.
534
     *
535
     * @return array
536
     */
537 16
    public function getAvailableVersions()
538
    {
539 16
        $availableVersions = [];
540
541 16
        if (empty($this->migrations)) {
542 3
            $this->registerMigrationsFromDirectory($this->getMigrationsDirectory());
543
        }
544
545 14
        foreach ($this->migrations as $migration) {
546 14
            $availableVersions[] = $migration->getVersion();
547
        }
548
549 14
        return $availableVersions;
550
    }
551
552
    /**
553
     * Returns the current migrated version from the versions table.
554
     *
555
     * @return string
556
     */
557 43
    public function getCurrentVersion()
558
    {
559 43
        $this->connect();
560 43
        $this->createMigrationTable();
561
562 41
        if (empty($this->migrations)) {
563 15
            $this->registerMigrationsFromDirectory($this->getMigrationsDirectory());
564
        }
565
566 41
        $where = null;
567 41
        if ( ! empty($this->migrations)) {
568 37
            $migratedVersions = [];
569 37
            foreach ($this->migrations as $migration) {
570 37
                $migratedVersions[] = sprintf("'%s'", $migration->getVersion());
571
            }
572 37
            $where = " WHERE " . $this->migrationsColumnName . " IN (" . implode(', ', $migratedVersions) . ")";
573
        }
574
575 41
        $sql = sprintf(
576 41
            "SELECT %s FROM %s%s ORDER BY %s DESC",
577 41
            $this->migrationsColumnName,
578 41
            $this->migrationsTableName,
579 41
            $where,
580 41
            $this->migrationsColumnName
581
        );
582
583 41
        $sql    = $this->connection->getDatabasePlatform()->modifyLimitQuery($sql, 1);
584 41
        $result = $this->connection->fetchColumn($sql);
585
586 41
        return $result !== false ? (string) $result : '0';
587
    }
588
589
    /**
590
     * Returns the version prior to the current version.
591
     *
592
     * @return string|null A version string, or null if the current version is
593
     *                     the first.
594
     */
595 10
    public function getPrevVersion()
596
    {
597 10
        return $this->getRelativeVersion($this->getCurrentVersion(), -1);
598
    }
599
600
    /**
601
     * Returns the version following the current version.
602
     *
603
     * @return string|null A version string, or null if the current version is
604
     *                     the latest.
605
     */
606 10
    public function getNextVersion()
607
    {
608 10
        return $this->getRelativeVersion($this->getCurrentVersion(), 1);
609
    }
610
611
    /**
612
     * Returns the version with the specified offset to the specified version.
613
     *
614
     * @return string|null A version string, or null if the specified version
615
     *                     is unknown or the specified delta is not within the
616
     *                     list of available versions.
617
     */
618 16
    public function getRelativeVersion($version, $delta)
619
    {
620 16
        if (empty($this->migrations)) {
621 5
            $this->registerMigrationsFromDirectory($this->getMigrationsDirectory());
622
        }
623
624 14
        $versions = array_map('strval', array_keys($this->migrations));
625 14
        array_unshift($versions, '0');
626 14
        $offset = array_search((string) $version, $versions);
627 14
        if ($offset === false || ! isset($versions[$offset + $delta])) {
628
            // Unknown version or delta out of bounds.
629 11
            return null;
630
        }
631
632 12
        return $versions[$offset + $delta];
633
    }
634
635
    /**
636
     * Returns the version with the specified to the current version.
637
     *
638
     * @return string|null A version string, or null if the specified delta is
639
     *                     not within the list of available versions.
640
     */
641 1
    public function getDeltaVersion($delta)
642
    {
643 1
        $symbol = substr($delta, 0, 1);
644 1
        $number = (int) substr($delta, 1);
645
646 1
        if ($number <= 0) {
647
            return null;
648
        }
649
650 1
        if ($symbol == "+" || $symbol == "-") {
651 1
            return $this->getRelativeVersion($this->getCurrentVersion(), (int) $delta);
652
        }
653
654
        return null;
655
    }
656
657
    /**
658
     * Returns the version number from an alias.
659
     *
660
     * Supported aliases are:
661
     * - first: The very first version before any migrations have been run.
662
     * - current: The current version.
663
     * - prev: The version prior to the current version.
664
     * - next: The version following the current version.
665
     * - latest: The latest available version.
666
     *
667
     * If an existing version number is specified, it is returned verbatimly.
668
     *
669
     * @return string|null A version number, or null if the specified alias
670
     *                     does not map to an existing version, e.g. if "next"
671
     *                     is passed but the current version is already the
672
     *                     latest.
673
     */
674 9
    public function resolveVersionAlias($alias)
675
    {
676 9
        if ($this->hasVersion($alias)) {
677 1
            return $alias;
678
        }
679
        switch ($alias) {
680 9
            case 'first':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
681 1
                return '0';
682 9
            case 'current':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
683 9
                return $this->getCurrentVersion();
684 9
            case 'prev':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
685 9
                return $this->getPrevVersion();
686 9
            case 'next':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
687 9
                return $this->getNextVersion();
688 9
            case 'latest':
689 9
                return $this->getLatestVersion();
690
            default:
691 1
                if (substr($alias, 0, 7) == 'current') {
692
                    return $this->getDeltaVersion(substr($alias, 7));
693
                }
694 1
                return null;
695
        }
696
    }
697
698
    /**
699
     * Returns the total number of executed migration versions
700
     *
701
     * @return integer
702
     */
703 1 View Code Duplication
    public function getNumberOfExecutedMigrations()
704
    {
705 1
        $this->connect();
706 1
        $this->createMigrationTable();
707
708 1
        $result = $this->connection->fetchColumn("SELECT COUNT(" . $this->migrationsColumnName . ") FROM " . $this->migrationsTableName);
709
710 1
        return $result !== false ? $result : 0;
711
    }
712
713
    /**
714
     * Returns the total number of available migration versions
715
     *
716
     * @return integer
717
     */
718 5
    public function getNumberOfAvailableMigrations()
719
    {
720 5
        if (empty($this->migrations)) {
721 4
            $this->registerMigrationsFromDirectory($this->getMigrationsDirectory());
722
        }
723
724 3
        return count($this->migrations);
725
    }
726
727
    /**
728
     * Returns the latest available migration version.
729
     *
730
     * @return string The version string in the format YYYYMMDDHHMMSS.
731
     */
732 28
    public function getLatestVersion()
733
    {
734 28
        if (empty($this->migrations)) {
735 7
            $this->registerMigrationsFromDirectory($this->getMigrationsDirectory());
736
        }
737
738 26
        $versions = array_keys($this->migrations);
739 26
        $latest   = end($versions);
740
741 26
        return $latest !== false ? (string) $latest : '0';
742
    }
743
744
    /**
745
     * Create the migration table to track migrations with.
746
     *
747
     * @return boolean Whether or not the table was created.
748
     */
749 64
    public function createMigrationTable()
750
    {
751 64
        $this->validate();
752
753 62
        if ($this->migrationTableCreated) {
754 51
            return false;
755
        }
756
757 62
        $this->connect();
758 62
        if ($this->connection->getSchemaManager()->tablesExist([$this->migrationsTableName])) {
759 4
            $this->migrationTableCreated = true;
760
761 4
            return false;
762
        }
763
764
        $columns = [
765 61
            $this->migrationsColumnName => new Column($this->migrationsColumnName, Type::getType('string'), ['length' => 255]),
766
        ];
767 61
        $table   = new Table($this->migrationsTableName, $columns);
768 61
        $table->setPrimaryKey([$this->migrationsColumnName]);
769 61
        $this->connection->getSchemaManager()->createTable($table);
770
771 61
        $this->migrationTableCreated = true;
772
773 61
        return true;
774
    }
775
776
    /**
777
     * Returns the array of migrations to executed based on the given direction
778
     * and target version number.
779
     *
780
     * @param string $direction The direction we are migrating.
781
     * @param string $to        The version to migrate to.
782
     *
783
     * @return Version[] $migrations   The array of migrations we can execute.
784
     */
785 39
    public function getMigrationsToExecute($direction, $to)
786
    {
787 39
        if (empty($this->migrations)) {
788 11
            $this->registerMigrationsFromDirectory($this->getMigrationsDirectory());
789
        }
790
791 33
        if ($direction === Version::DIRECTION_DOWN) {
792 7
            if (count($this->migrations)) {
793 7
                $allVersions = array_reverse(array_keys($this->migrations));
794 7
                $classes     = array_reverse(array_values($this->migrations));
795 7
                $allVersions = array_combine($allVersions, $classes);
796
            } else {
797 7
                $allVersions = [];
798
            }
799
        } else {
800 31
            $allVersions = $this->migrations;
801
        }
802 33
        $versions = [];
803 33
        $migrated = $this->getMigratedVersions();
804 33
        foreach ($allVersions as $version) {
805 31
            if ($this->shouldExecuteMigration($direction, $version, $to, $migrated)) {
806 31
                $versions[$version->getVersion()] = $version;
807
            }
808
        }
809
810 33
        return $versions;
811
    }
812
813
    /**
814
     * Use the connection's event manager to emit an event.
815
     *
816
     * @param string $eventName The event to emit.
817
     * @param $args The event args instance to emit.
818
     */
819 45
    public function dispatchEvent($eventName, EventArgs $args = null)
820
    {
821 45
        $this->connection->getEventManager()->dispatchEvent($eventName, $args);
822 45
    }
823
824
    /**
825
     * Find all the migrations in a given directory.
826
     *
827
     * @param   string $path the directory to search.
828
     * @return  array
829
     */
830 87
    protected function findMigrations($path)
831
    {
832 87
        return $this->migrationFinder->findMigrations($path, $this->getMigrationsNamespace());
833
    }
834
835
    /**
836
     * @param bool $migrationsAreOrganizedByYear
837
     * @throws MigrationException
838
     */
839 9
    public function setMigrationsAreOrganizedByYear($migrationsAreOrganizedByYear = true)
840
    {
841 9
        $this->ensureOrganizeMigrationsIsCompatibleWithFinder();
842
843 5
        $this->migrationsAreOrganizedByYear = $migrationsAreOrganizedByYear;
844 5
    }
845
846
    /**
847
     * @param bool $migrationsAreOrganizedByYearAndMonth
848
     * @throws MigrationException
849
     */
850 10
    public function setMigrationsAreOrganizedByYearAndMonth($migrationsAreOrganizedByYearAndMonth = true)
851
    {
852 10
        $this->ensureOrganizeMigrationsIsCompatibleWithFinder();
853
854 10
        $this->migrationsAreOrganizedByYear         = $migrationsAreOrganizedByYearAndMonth;
855 10
        $this->migrationsAreOrganizedByYearAndMonth = $migrationsAreOrganizedByYearAndMonth;
856 10
    }
857
858
    /**
859
     * Generate a new migration version. A version is (usually) a datetime string.
860
     *
861
     * @param \DateTimeInterface|null $now Defaults to the current time in UTC
862
     * @return string The newly generated version
863
     */
864 9
    public function generateVersionNumber(\DateTimeInterface $now = null)
865
    {
866 9
        $now = $now ?: new \DateTime('now', new \DateTimeZone('UTC'));
867
868 9
        return $now->format(self::VERSION_FORMAT);
869
    }
870
871
    /**
872
     * Explicitely opens the database connection. This is done to play nice
873
     * with DBAL's MasterSlaveConnection. Which, in some cases, connects to a
874
     * follower when fetching the executed migrations. If a follower is lagging
875
     * significantly behind that means the migrations system may see unexecuted
876
     * migrations that were actually executed earlier.
877
     *
878
     * @return bool The same value returned from the `connect` method
879
     */
880 64
    protected function connect()
881
    {
882 64
        if ($this->connection instanceof MasterSlaveConnection) {
883 1
            return $this->connection->connect('master');
884
        }
885
886 63
        return $this->connection->connect();
887
    }
888
889
    /**
890
     * @throws MigrationException
891
     */
892 19
    private function ensureOrganizeMigrationsIsCompatibleWithFinder()
893
    {
894 19
        if ( ! ($this->migrationFinder instanceof MigrationDeepFinderInterface)) {
895 4
            throw MigrationException::configurationIncompatibleWithFinder(
896 4
                'organize-migrations',
897 4
                $this->migrationFinder
898
            );
899
        }
900 15
    }
901
902
    /**
903
     * Check if we should execute a migration for a given direction and target
904
     * migration version.
905
     *
906
     * @param string  $direction The direction we are migrating.
907
     * @param Version $version   The Version instance to check.
908
     * @param string  $to        The version we are migrating to.
909
     * @param array   $migrated  Migrated versions array.
910
     *
911
     * @return boolean
912
     */
913 31
    private function shouldExecuteMigration($direction, Version $version, $to, $migrated)
914
    {
915 31 View Code Duplication
        if ($direction === Version::DIRECTION_DOWN) {
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...
916 7
            if ( ! in_array($version->getVersion(), $migrated)) {
917 4
                return false;
918
            }
919
920 5
            return $version->getVersion() > $to;
921
        }
922
923 29 View Code Duplication
        if ($direction === Version::DIRECTION_UP) {
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...
924 29
            if (in_array($version->getVersion(), $migrated)) {
925 8
                return false;
926
            }
927
928 28
            return $version->getVersion() <= $to;
929
        }
930
    }
931
932
    /**
933
     * @param string $class
934
     */
935 69
    private function ensureMigrationClassExists($class)
936
    {
937 69
        if ( ! class_exists($class)) {
938 1
            throw MigrationException::migrationClassNotFound($class, $this->getMigrationsNamespace());
939
        }
940 68
    }
941
942 8
    public function getQueryWriter() : QueryWriter
943
    {
944 8
        if ($this->queryWriter === null) {
945 7
            $this->queryWriter = new FileQueryWriter(
946 7
                $this->migrationsColumnName,
947 7
                $this->migrationsTableName,
948 7
                $this->outputWriter
949
            );
950
        }
951
952 8
        return $this->queryWriter;
953
    }
954
}
955