Passed
Push — master ( 229462...d74785 )
by Andreas
02:20 queued 14s
created

MigrationPlanCalculator   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 106
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 42
c 1
b 0
f 0
dl 0
loc 106
ccs 46
cts 46
cp 1
rs 10
wmc 23

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getExecutedUnavailableMigrations() 0 7 1
A __construct() 0 4 1
A getNewMigrations() 0 7 1
A getPlanForExactVersion() 0 7 1
A findDirection() 0 7 4
B findMigrationsToExecute() 0 20 10
A arrangeMigrationsForDirection() 0 3 2
A getPlanUntilVersion() 0 20 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Migrations;
6
7
use Doctrine\Migrations\Exception\NoMigrationsFoundWithCriteria;
8
use Doctrine\Migrations\Exception\NoMigrationsToExecute;
9
use Doctrine\Migrations\Metadata\AvailableMigration;
10
use Doctrine\Migrations\Metadata\AvailableMigrationsList;
11
use Doctrine\Migrations\Metadata\ExecutedMigration;
12
use Doctrine\Migrations\Metadata\ExecutedMigrationsSet;
13
use Doctrine\Migrations\Metadata\MigrationPlan;
14
use Doctrine\Migrations\Metadata\MigrationPlanList;
15
use Doctrine\Migrations\Metadata\Storage\MetadataStorage;
16
use Doctrine\Migrations\Version\Direction;
17
use Doctrine\Migrations\Version\Version;
18
use function array_filter;
19
use function array_map;
20
use function array_reverse;
21
22
/**
23
 * The MigrationPlanCalculator is responsible for calculating the plan for migrating from the current
24
 * version to another version.
25
 *
26
 * @internal
27
 */
28
final class MigrationPlanCalculator
29
{
30
    /** @var MigrationRepository */
31
    private $migrationRepository;
32
33
    /** @var MetadataStorage */
34
    private $metadataStorage;
35
36 57
    public function __construct(MigrationRepository $migrationRepository, MetadataStorage $metadataStorage)
37
    {
38 57
        $this->migrationRepository = $migrationRepository;
39 57
        $this->metadataStorage     = $metadataStorage;
40 57
    }
41
42 5
    public function getPlanForExactVersion(Version $version, string $direction) : MigrationPlanList
43
    {
44 5
        $migration = $this->migrationRepository->getMigration($version);
45
46 5
        $planItem = new MigrationPlan($migration->getVersion(), $migration->getMigration(), $direction);
47
48 5
        return new MigrationPlanList([$planItem], $direction);
49
    }
50
51 20
    public function getPlanUntilVersion(?Version $to = null) : MigrationPlanList
52
    {
53 20
        $availableMigrations = $this->migrationRepository->getMigrations();
54 20
        $executedMigrations  = $this->metadataStorage->getExecutedMigrations();
55
56
        try {
57 20
            $to = $to ?: $availableMigrations->getLast()->getVersion();
58 1
        } catch (NoMigrationsFoundWithCriteria $e) {
59 1
            throw NoMigrationsToExecute::new($e);
60
        }
61
62 19
        $direction = $this->findDirection($to, $executedMigrations);
63
64 19
        $migrationsToCheck = $this->arrangeMigrationsForDirection($direction, $availableMigrations);
65
66 19
        $toExecute = $this->findMigrationsToExecute($to, $migrationsToCheck, $direction, $executedMigrations);
67
68
        return new MigrationPlanList(array_map(static function (AvailableMigration $migration) use ($direction) {
69 15
            return new MigrationPlan($migration->getVersion(), $migration->getMigration(), $direction);
70 19
        }, $toExecute), $direction);
71
    }
72
73 19
    private function findDirection(Version $to, Metadata\ExecutedMigrationsSet $executedMigrations) : string
74
    {
75 19
        if ((string) $to === '0' || ($executedMigrations->hasMigration($to) && ! $executedMigrations->getLast()->getVersion()->equals($to))) {
76 2
            return Direction::DOWN;
77
        }
78
79 17
        return Direction::UP;
80
    }
81
82
    /**
83
     * @return  AvailableMigration[]
84
     */
85 19
    private function arrangeMigrationsForDirection(string $direction, Metadata\AvailableMigrationsList $availableMigrations) : array
86
    {
87 19
        return $direction === Direction::UP ? $availableMigrations->getItems() : array_reverse($availableMigrations->getItems());
88
    }
89
90
    /**
91
     * @param AvailableMigration[] $migrationsToCheck
92
     *
93
     * @return AvailableMigration[]
94
     */
95 19
    private function findMigrationsToExecute(Version $to, array $migrationsToCheck, string $direction, Metadata\ExecutedMigrationsSet $executedMigrations) : array
96
    {
97 19
        $toExecute = [];
98 19
        foreach ($migrationsToCheck as $availableMigration) {
99 19
            if ($direction === Direction::DOWN && $availableMigration->getVersion()->equals($to)) {
100 1
                break;
101
            }
102
103 19
            if ($direction === Direction::UP && ! $executedMigrations->hasMigration($availableMigration->getVersion())) {
104 13
                $toExecute[] = $availableMigration;
105 8
            } elseif ($direction === Direction::DOWN && $executedMigrations->hasMigration($availableMigration->getVersion())) {
106 2
                $toExecute[] = $availableMigration;
107
            }
108
109 19
            if ($direction === Direction::UP && $availableMigration->getVersion()->equals($to)) {
110 17
                break;
111
            }
112
        }
113
114 19
        return $toExecute;
115
    }
116
117 19
    public function getExecutedUnavailableMigrations() : ExecutedMigrationsSet
118
    {
119 19
        $executedMigrationsSet  = $this->metadataStorage->getExecutedMigrations();
120 19
        $availableMigrationsSet = $this->migrationRepository->getMigrations();
121
122
        return new ExecutedMigrationsSet(array_filter($executedMigrationsSet->getItems(), static function (ExecutedMigration $migrationInfo) use ($availableMigrationsSet) {
123 12
            return ! $availableMigrationsSet->hasMigration($migrationInfo->getVersion());
124 19
        }));
125
    }
126
127 14
    public function getNewMigrations() : AvailableMigrationsList
128
    {
129 14
        $executedMigrationsSet  = $this->metadataStorage->getExecutedMigrations();
130 14
        $availableMigrationsSet = $this->migrationRepository->getMigrations();
131
132
        return new AvailableMigrationsList(array_filter($availableMigrationsSet->getItems(), static function (AvailableMigration $migrationInfo) use ($executedMigrationsSet) {
133 10
            return ! $executedMigrationsSet->hasMigration($migrationInfo->getVersion());
134 14
        }));
135
    }
136
}
137