Failed Conditions
Pull Request — master (#969)
by
unknown
09:23
created

findMigrationsToExecute()   B

Complexity

Conditions 10
Paths 8

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 10

Importance

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

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