Failed Conditions
Pull Request — master (#675)
by Jonathan
06:31
created

MigrationRepository::loadMigrationsFromDirectory()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

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