findMigrationsToExecute()   B
last analyzed

Complexity

Conditions 10
Paths 8

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 10

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 12
cts 12
cp 1
rs 7.6666
c 0
b 0
f 0
cc 10
nc 8
nop 4
crap 10

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Migrations\Version;
6
7
use Doctrine\Migrations\Exception\MigrationClassNotFound;
8
use Doctrine\Migrations\Metadata;
9
use Doctrine\Migrations\Metadata\AvailableMigration;
10
use Doctrine\Migrations\Metadata\AvailableMigrationsList;
11
use Doctrine\Migrations\Metadata\ExecutedMigrationsList;
12
use Doctrine\Migrations\Metadata\MigrationPlan;
13
use Doctrine\Migrations\Metadata\MigrationPlanList;
14
use Doctrine\Migrations\Metadata\Storage\MetadataStorage;
15
use Doctrine\Migrations\MigrationsRepository;
16
use function array_diff;
17
use function array_filter;
18
use function array_map;
19
use function array_reverse;
20
use function count;
21
use function in_array;
22
use function reset;
23
use function uasort;
24
25
/**
26
 * The MigrationPlanCalculator is responsible for calculating the plan for migrating from the current
27
 * version to another version.
28
 *
29
 * @internal
30
 */
31
final class SortedMigrationPlanCalculator implements MigrationPlanCalculator
32
{
33
    /** @var MigrationsRepository */
34
    private $migrationRepository;
35
36
    /** @var MetadataStorage */
37
    private $metadataStorage;
38
39
    /** @var Comparator */
40
    private $sorter;
41
42 76
    public function __construct(
43
        MigrationsRepository $migrationRepository,
44
        MetadataStorage $metadataStorage,
45
        Comparator $sorter
46
    ) {
47 76
        $this->migrationRepository = $migrationRepository;
48 76
        $this->metadataStorage     = $metadataStorage;
49 76
        $this->sorter              = $sorter;
50 76
    }
51
52
    /**
53
     * @param Version[] $versions
54
     */
55 5
    public function getPlanForVersions(array $versions, string $direction) : MigrationPlanList
56
    {
57 5
        $migrationsToCheck   = $this->arrangeMigrationsForDirection($direction, $this->getMigrations());
58
        $availableMigrations = array_filter($migrationsToCheck, static function (AvailableMigration $availableMigration) use ($versions) : bool {
59
            // in_array third parameter is intentionally false to force object to string casting
60 5
            return in_array($availableMigration->getVersion(), $versions, false);
61 5
        });
62
63
        $planItems = array_map(static function (AvailableMigration $availableMigration) use ($direction) : MigrationPlan {
64 3
            return new MigrationPlan($availableMigration->getVersion(), $availableMigration->getMigration(), $direction);
65 5
        }, $availableMigrations);
66
67 5
        if (count($planItems) !== count($versions)) {
68
            $plannedVersions = array_map(static function (MigrationPlan $migrationPlan) : Version {
69
                return $migrationPlan->getVersion();
70 1
            }, $planItems);
71 1
            $diff            = array_diff($versions, $plannedVersions);
72
73 1
            throw MigrationClassNotFound::new((string) reset($diff));
74
        }
75
76 4
        return new MigrationPlanList($planItems, $direction);
77
    }
78
79 23
    public function getPlanUntilVersion(Version $to) : MigrationPlanList
80
    {
81 23
        if ((string) $to !== '0' && ! $this->migrationRepository->hasMigration((string) $to)) {
82 1
            throw MigrationClassNotFound::new((string) $to);
83
        }
84
85 22
        $availableMigrations = $this->getMigrations();
86 22
        $executedMigrations  = $this->metadataStorage->getExecutedMigrations();
87
88 22
        $direction = $this->findDirection($to, $executedMigrations);
89
90 22
        $migrationsToCheck = $this->arrangeMigrationsForDirection($direction, $availableMigrations);
91
92 22
        $toExecute = $this->findMigrationsToExecute($to, $migrationsToCheck, $direction, $executedMigrations);
93
94
        return new MigrationPlanList(array_map(static function (AvailableMigration $migration) use ($direction) : MigrationPlan {
95 16
            return new MigrationPlan($migration->getVersion(), $migration->getMigration(), $direction);
96 22
        }, $toExecute), $direction);
97
    }
98
99 75
    public function getMigrations() : AvailableMigrationsList
100
    {
101 75
        $availableMigrations = $this->migrationRepository->getMigrations()->getItems();
102
        uasort($availableMigrations, function (AvailableMigration $a, AvailableMigration $b) : int {
103 44
            return $this->sorter->compare($a->getVersion(), $b->getVersion());
104 75
        });
105
106 75
        return new AvailableMigrationsList($availableMigrations);
107
    }
108
109 22
    private function findDirection(Version $to, ExecutedMigrationsList $executedMigrations) : string
110
    {
111 22
        if ((string) $to === '0' || ($executedMigrations->hasMigration($to) && ! $executedMigrations->getLast()->getVersion()->equals($to))) {
112 5
            return Direction::DOWN;
113
        }
114
115 17
        return Direction::UP;
116
    }
117
118
    /**
119
     * @return  AvailableMigration[]
120
     */
121 27
    private function arrangeMigrationsForDirection(string $direction, Metadata\AvailableMigrationsList $availableMigrations) : array
122
    {
123 27
        return $direction === Direction::UP ? $availableMigrations->getItems() : array_reverse($availableMigrations->getItems());
124
    }
125
126
    /**
127
     * @param AvailableMigration[] $migrationsToCheck
128
     *
129
     * @return AvailableMigration[]
130
     */
131 22
    private function findMigrationsToExecute(Version $to, array $migrationsToCheck, string $direction, ExecutedMigrationsList $executedMigrations) : array
132
    {
133 22
        $toExecute = [];
134 22
        foreach ($migrationsToCheck as $availableMigration) {
135 22
            if ($direction === Direction::DOWN && $availableMigration->getVersion()->equals($to)) {
136 2
                break;
137
            }
138
139 22
            if ($direction === Direction::UP && ! $executedMigrations->hasMigration($availableMigration->getVersion())) {
140 13
                $toExecute[] = $availableMigration;
141 10
            } elseif ($direction === Direction::DOWN && $executedMigrations->hasMigration($availableMigration->getVersion())) {
142 3
                $toExecute[] = $availableMigration;
143
            }
144
145 22
            if ($direction === Direction::UP && $availableMigration->getVersion()->equals($to)) {
146 17
                break;
147
            }
148
        }
149
150 22
        return $toExecute;
151
    }
152
}
153