Completed
Push — master ( 9613ab...ee300a )
by Mike
03:47
created

Configuration::getMigrationsToExecute()   B

Complexity

Conditions 6
Paths 18

Size

Total Lines 27
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 6

Importance

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