Completed
Push — master ( 368556...6bf94b )
by Jonathan
11s
created

MigrationRepository::getMigratedVersions()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 2
nop 0
dl 0
loc 19
ccs 11
cts 11
cp 1
crap 3
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Migrations;
6
7
use Doctrine\DBAL\Connection;
8
use Doctrine\Migrations\Configuration\Configuration;
9
use Doctrine\Migrations\Exception\DuplicateMigrationVersion;
10
use Doctrine\Migrations\Exception\MigrationClassNotFound;
11
use Doctrine\Migrations\Exception\UnknownMigrationVersion;
12
use Doctrine\Migrations\Finder\MigrationFinder;
13
use const SORT_STRING;
14
use function array_diff;
15
use function array_keys;
16
use function array_map;
17
use function array_search;
18
use function array_unshift;
19
use function class_exists;
20
use function count;
21
use function end;
22
use function get_class;
23
use function implode;
24
use function ksort;
25
use function sprintf;
26
use function substr;
27
28
/**
29
 * @internal
30
 */
31
class MigrationRepository
32
{
33
    /** @var Configuration */
34
    private $configuration;
35
36
    /** @var Connection */
37
    private $connection;
38
39
    /** @var MigrationFinder */
40
    private $migrationFinder;
41
42
    /** @var VersionFactory */
43
    private $versionFactory;
44
45
    /** @var Version[] */
46
    private $versions = [];
47
48 130
    public function __construct(
49
        Configuration $configuration,
50
        Connection $connection,
51
        MigrationFinder $migrationFinder,
52
        VersionFactory $versionFactory
53
    ) {
54 130
        $this->configuration   = $configuration;
55 130
        $this->connection      = $connection;
56 130
        $this->migrationFinder = $migrationFinder;
57 130
        $this->versionFactory  = $versionFactory;
58 130
    }
59
60
    /**
61
     * @return string[]
62
     */
63 83
    public function findMigrations(string $path) : array
64
    {
65 83
        return $this->migrationFinder->findMigrations($path, $this->configuration->getMigrationsNamespace());
66
    }
67
68
    /** @return Version[] */
69 83
    public function registerMigrationsFromDirectory(string $path) : array
70
    {
71 83
        return $this->registerMigrations($this->findMigrations($path));
72
    }
73
74
    /** @throws MigrationException */
75 71
    public function registerMigration(string $version, string $migrationClassName) : Version
76
    {
77 71
        $this->ensureMigrationClassExists($migrationClassName);
78
79 70
        if (isset($this->versions[$version])) {
80 1
            throw DuplicateMigrationVersion::new(
81 1
                $version,
82 1
                get_class($this->versions[$version])
83
            );
84
        }
85
86 70
        $version = $this->versionFactory->createVersion($version, $migrationClassName);
87
88 70
        $this->versions[$version->getVersion()] = $version;
89
90 70
        ksort($this->versions, SORT_STRING);
91
92 70
        return $version;
93
    }
94
95
    /**
96
     * @param string[] $migrations
97
     *
98
     * @return Version[]
99
     */
100 87
    public function registerMigrations(array $migrations) : array
101
    {
102 87
        $versions = [];
103
104 87
        foreach ($migrations as $version => $class) {
105 35
            $versions[] = $this->registerMigration((string) $version, $class);
106
        }
107
108 86
        return $versions;
109
    }
110
111 42
    public function getCurrentVersion() : string
112
    {
113 42
        $this->configuration->createMigrationTable();
114
115 42
        if (! $this->configuration->isMigrationTableCreated() && $this->configuration->isDryRun()) {
116 1
            return '0';
117
        }
118
119 42
        $this->configuration->connect();
120
121 42
        $this->loadMigrationsFromDirectory();
122
123 42
        $where = null;
124
125 42
        if (! empty($this->versions)) {
126 38
            $migratedVersions = [];
127
128 38
            foreach ($this->versions as $migration) {
129 38
                $migratedVersions[] = sprintf("'%s'", $migration->getVersion());
130
            }
131
132 38
            $where = sprintf(
133 38
                ' WHERE %s IN (%s)',
134 38
                $this->configuration->getQuotedMigrationsColumnName(),
135 38
                implode(', ', $migratedVersions)
136
            );
137
        }
138
139 42
        $sql = sprintf(
140 42
            'SELECT %s FROM %s%s ORDER BY %s DESC',
141 42
            $this->configuration->getQuotedMigrationsColumnName(),
142 42
            $this->configuration->getMigrationsTableName(),
143 42
            $where,
144 42
            $this->configuration->getQuotedMigrationsColumnName()
145
        );
146
147 42
        $sql    = $this->connection->getDatabasePlatform()->modifyLimitQuery($sql, 1);
148 42
        $result = $this->connection->fetchColumn($sql);
149
150 42
        return $result !== false ? (string) $result : '0';
151
    }
152
153 22
    public function getVersion(string $version) : Version
154
    {
155 22
        $this->loadMigrationsFromDirectory();
156
157 22
        if (! isset($this->versions[$version])) {
158 2
            throw UnknownMigrationVersion::new($version);
159
        }
160
161 20
        return $this->versions[$version];
162
    }
163
164 19
    public function hasVersion(string $version) : bool
165
    {
166 19
        $this->loadMigrationsFromDirectory();
167
168 19
        return isset($this->versions[$version]);
169
    }
170
171 21
    public function hasVersionMigrated(Version $version) : bool
172
    {
173 21
        $this->configuration->connect();
174 21
        $this->configuration->createMigrationTable();
175
176 21
        $sql = sprintf(
177 21
            'SELECT %s FROM %s WHERE %s = ?',
178 21
            $this->configuration->getQuotedMigrationsColumnName(),
179 21
            $this->configuration->getMigrationsTableName(),
180 21
            $this->configuration->getQuotedMigrationsColumnName()
181
        );
182
183 21
        $version = $this->connection->fetchColumn($sql, [$version->getVersion()]);
184
185 21
        return $version !== false;
186
    }
187
188
    /**
189
     * @return Version[]
190
     */
191 38
    public function getMigrations() : array
192
    {
193 38
        $this->loadMigrationsFromDirectory();
194
195 38
        return $this->versions;
196
    }
197
198
    /** @return string[] */
199 15
    public function getAvailableVersions() : array
200
    {
201 15
        $availableVersions = [];
202
203 15
        $this->loadMigrationsFromDirectory();
204
205 15
        foreach ($this->versions as $migration) {
206 14
            $availableVersions[] = $migration->getVersion();
207
        }
208
209 15
        return $availableVersions;
210
    }
211
212
    /** @return string[] */
213 8
    public function getNewVersions() : array
214
    {
215 8
        $availableMigrations = $this->getAvailableVersions();
216 8
        $executedMigrations  = $this->getMigratedVersions();
217
218 8
        return array_diff($availableMigrations, $executedMigrations);
219
    }
220
221
    /** @return string[] */
222 42
    public function getMigratedVersions() : array
223
    {
224 42
        $this->configuration->createMigrationTable();
225
226 42
        if (! $this->configuration->isMigrationTableCreated() && $this->configuration->isDryRun()) {
227 1
            return [];
228
        }
229
230 42
        $this->configuration->connect();
231
232 42
        $sql = sprintf(
233 42
            'SELECT %s FROM %s',
234 42
            $this->configuration->getQuotedMigrationsColumnName(),
235 42
            $this->configuration->getMigrationsTableName()
236
        );
237
238 42
        $result = $this->connection->fetchAll($sql);
239
240 42
        return array_map('current', $result);
241
    }
242
243
    /**
244
     * @return string[]
245
     */
246 8
    public function getExecutedUnavailableMigrations() : array
247
    {
248 8
        $executedMigrations  = $this->getMigratedVersions();
249 8
        $availableMigrations = $this->getAvailableVersions();
250
251 8
        return array_diff($executedMigrations, $availableMigrations);
252
    }
253
254 3
    public function getNumberOfAvailableMigrations() : int
255
    {
256 3
        $this->loadMigrationsFromDirectory();
257
258 3
        return count($this->versions);
259
    }
260
261 25
    public function getLatestVersion() : string
262
    {
263 25
        $this->loadMigrationsFromDirectory();
264
265 25
        $versions = array_keys($this->versions);
266 25
        $latest   = end($versions);
267
268 25
        return $latest !== false ? (string) $latest : '0';
269
    }
270
271 1
    public function getNumberOfExecutedMigrations() : int
272
    {
273 1
        $this->configuration->connect();
274 1
        $this->configuration->createMigrationTable();
275
276 1
        $sql = sprintf(
277 1
            'SELECT COUNT(%s) FROM %s',
278 1
            $this->configuration->getQuotedMigrationsColumnName(),
279 1
            $this->configuration->getMigrationsTableName()
280
        );
281
282 1
        $result = $this->connection->fetchColumn($sql);
283
284 1
        return $result !== false ? (int) $result : 0;
285
    }
286
287 14
    public function getRelativeVersion(string $version, int $delta) : ?string
288
    {
289 14
        $this->loadMigrationsFromDirectory();
290
291 14
        $versions = array_map('strval', array_keys($this->versions));
292
293 14
        array_unshift($versions, '0');
294
295 14
        $offset = array_search($version, $versions, true);
296
297 14
        if ($offset === false || ! isset($versions[$offset + $delta])) {
298
            // Unknown version or delta out of bounds.
299 10
            return null;
300
        }
301
302 13
        return $versions[$offset + $delta];
303
    }
304
305 1
    public function getDeltaVersion(string $delta) : ?string
306
    {
307 1
        $symbol = substr($delta, 0, 1);
308 1
        $number = (int) substr($delta, 1);
309
310 1
        if ($number <= 0) {
311
            return null;
312
        }
313
314 1
        if ($symbol === '+' || $symbol === '-') {
315 1
            return $this->getRelativeVersion($this->getCurrentVersion(), (int) $delta);
316
        }
317
318
        return null;
319
    }
320
321 9
    public function getPrevVersion() : ?string
322
    {
323 9
        return $this->getRelativeVersion($this->getCurrentVersion(), -1);
324
    }
325
326 10
    public function getNextVersion() : ?string
327
    {
328 10
        return $this->getRelativeVersion($this->getCurrentVersion(), 1);
329
    }
330
331 70
    private function loadMigrationsFromDirectory() : void
332
    {
333 70
        $migrationsDirectory = $this->configuration->getMigrationsDirectory();
334
335 70
        if (count($this->versions) !== 0 || $migrationsDirectory === null) {
336 49
            return;
337
        }
338
339 32
        $this->registerMigrationsFromDirectory($migrationsDirectory);
340 32
    }
341
342
    /** @throws MigrationException */
343 71
    private function ensureMigrationClassExists(string $class) : void
344
    {
345 71
        if (! class_exists($class)) {
346 1
            throw MigrationClassNotFound::new(
347 1
                $class,
348 1
                $this->configuration->getMigrationsNamespace()
349
            );
350
        }
351 70
    }
352
}
353