Failed Conditions
Push — master ( 51f284...368556 )
by Jonathan
02:26
created

MigrationRepository   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 298
Duplicated Lines 0 %

Test Coverage

Coverage 98.52%

Importance

Changes 0
Metric Value
dl 0
loc 298
ccs 133
cts 135
cp 0.9852
rs 8.295
c 0
b 0
f 0
wmc 42

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A hasVersionMigrated() 0 15 1
A getMigratedVersions() 0 19 3
B getCurrentVersion() 0 40 6
A getMigrations() 0 5 1
A registerMigrationsFromDirectory() 0 3 1
A getLatestVersion() 0 8 2
A findMigrations() 0 3 1
A getAvailableVersions() 0 11 2
A getVersion() 0 9 2
A registerMigration() 0 18 2
A registerMigrations() 0 9 2
A hasVersion() 0 5 1
A getNumberOfAvailableMigrations() 0 5 1
A loadMigrationsFromDirectory() 0 9 3
A ensureMigrationClassExists() 0 6 2
A getNextVersion() 0 3 1
A getPrevVersion() 0 3 1
A getNumberOfExecutedMigrations() 0 14 2
A getDeltaVersion() 0 14 4
A getRelativeVersion() 0 16 3

How to fix   Complexity   

Complex Class

Complex classes like MigrationRepository often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MigrationRepository, and based on these observations, apply Extract Interface, too.

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