Completed
Push — master ( 228133...b8267c )
by Mike
03:12
created

Configuration   F

Complexity

Total Complexity 83

Size/Duplication

Total Lines 779
Duplicated Lines 1.8 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 98.71%

Importance

Changes 9
Bugs 1 Features 2
Metric Value
wmc 83
c 9
b 1
f 2
lcom 1
cbo 11
dl 14
loc 779
ccs 229
cts 232
cp 0.9871
rs 3.9999

45 Methods

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