Completed
Push — master ( 5ff3e1...46578f )
by Jonathan
12s
created

MigrationRepository::addVersions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

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