Completed
Push — master ( 8bb342...0101f5 )
by Jonathan
25s
created

Configuration::createDateTime()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Migrations\Configuration;
6
7
use DateTimeImmutable;
8
use DateTimeInterface;
9
use DateTimeZone;
10
use Doctrine\Common\EventArgs;
11
use Doctrine\DBAL\Connection;
12
use Doctrine\DBAL\Connections\MasterSlaveConnection;
13
use Doctrine\Migrations\Configuration\Exception\MigrationsNamespaceRequired;
14
use Doctrine\Migrations\Configuration\Exception\ParameterIncompatibleWithFinder;
15
use Doctrine\Migrations\DependencyFactory;
16
use Doctrine\Migrations\Exception\MigrationException;
17
use Doctrine\Migrations\Exception\MigrationsDirectoryRequired;
18
use Doctrine\Migrations\Finder\MigrationDeepFinder;
19
use Doctrine\Migrations\Finder\MigrationFinder;
20
use Doctrine\Migrations\OutputWriter;
21
use Doctrine\Migrations\QueryWriter;
22
use Doctrine\Migrations\Version\Version;
23
use function str_replace;
24
use function strlen;
25
26
/**
27
 * The Configuration class is responsible for defining migration configuration information.
28
 */
29
class Configuration
30
{
31
    public const VERSIONS_ORGANIZATION_BY_YEAR = 'year';
32
33
    public const VERSIONS_ORGANIZATION_BY_YEAR_AND_MONTH = 'year_and_month';
34
35
    public const VERSION_FORMAT = 'YmdHis';
36
37
    /** @var string|null */
38
    private $name;
39
40
    /** @var string */
41
    private $migrationsTableName = 'doctrine_migration_versions';
42
43
    /** @var string */
44
    private $migrationsColumnName = 'version';
45
46
    /** @var int */
47
    private $migrationsColumnLength;
48
49
    /** @var string */
50
    private $migrationsExecutedAtColumnName = 'executed_at';
51
52
    /** @var string|null */
53
    private $migrationsDirectory;
54
55
    /** @var string|null */
56
    private $migrationsNamespace;
57
58
    /** @var bool */
59
    private $migrationsAreOrganizedByYear = false;
60
61
    /** @var bool */
62
    private $migrationsAreOrganizedByYearAndMonth = false;
63
64
    /** @var string|null */
65
    private $customTemplate;
66
67
    /** @var bool */
68
    private $isDryRun = false;
69
70
    /** @var bool */
71
    private $allOrNothing = false;
72
73
    /** @var Connection */
74
    private $connection;
75
76
    /** @var OutputWriter|null */
77
    private $outputWriter;
78
79
    /** @var MigrationFinder|null */
80
    private $migrationFinder;
81
82
    /** @var QueryWriter|null */
83
    private $queryWriter;
84
85
    /** @var DependencyFactory|null */
86
    private $dependencyFactory;
87
88 277
    public function __construct(
89
        Connection $connection,
90
        ?OutputWriter $outputWriter = null,
91
        ?MigrationFinder $migrationFinder = null,
92
        ?QueryWriter $queryWriter = null,
93
        ?DependencyFactory $dependencyFactory = null
94
    ) {
95 277
        $this->connection             = $connection;
96 277
        $this->outputWriter           = $outputWriter;
97 277
        $this->migrationFinder        = $migrationFinder;
98 277
        $this->queryWriter            = $queryWriter;
99 277
        $this->dependencyFactory      = $dependencyFactory;
100 277
        $this->migrationsColumnLength = strlen($this->createDateTime()->format(self::VERSION_FORMAT));
101 277
    }
102
103 71
    public function setName(string $name) : void
104
    {
105 71
        $this->name = $name;
106 71
    }
107
108 15
    public function getName() : ?string
109
    {
110 15
        return $this->name;
111
    }
112
113 200
    public function getConnection() : Connection
114
    {
115 200
        return $this->connection;
116
    }
117
118 95
    public function setMigrationsTableName(string $tableName) : void
119
    {
120 95
        $this->migrationsTableName = $tableName;
121 95
    }
122
123 92
    public function getMigrationsTableName() : string
124
    {
125 92
        return $this->migrationsTableName;
126
    }
127
128 70
    public function setMigrationsColumnName(string $columnName) : void
129
    {
130 70
        $this->migrationsColumnName = $columnName;
131 70
    }
132
133 88
    public function getMigrationsColumnName() : string
134
    {
135 88
        return $this->migrationsColumnName;
136
    }
137
138 73
    public function getQuotedMigrationsColumnName() : string
139
    {
140 73
        return $this->getDependencyFactory()
141 73
            ->getTrackingTableDefinition()
142 73
            ->getMigrationsColumn()
143 73
            ->getQuotedName($this->connection->getDatabasePlatform());
144
    }
145
146 47
    public function setMigrationsColumnLength(int $columnLength) : void
147
    {
148 47
        $this->migrationsColumnLength = $columnLength;
149 47
    }
150
151 88
    public function getMigrationsColumnLength() : int
152
    {
153 88
        return $this->migrationsColumnLength;
154
    }
155
156 49
    public function setMigrationsExecutedAtColumnName(string $migrationsExecutedAtColumnName) : void
157
    {
158 49
        $this->migrationsExecutedAtColumnName = $migrationsExecutedAtColumnName;
159 49
    }
160
161 88
    public function getMigrationsExecutedAtColumnName() : string
162
    {
163 88
        return $this->migrationsExecutedAtColumnName;
164
    }
165
166 58
    public function getQuotedMigrationsExecutedAtColumnName() : string
167
    {
168 58
        return $this->getDependencyFactory()
169 58
            ->getTrackingTableDefinition()
170 58
            ->getExecutedAtColumn()
171 58
            ->getQuotedName($this->connection->getDatabasePlatform());
172
    }
173
174 208
    public function setMigrationsDirectory(string $migrationsDirectory) : void
175
    {
176 208
        $this->migrationsDirectory = $migrationsDirectory;
177 208
    }
178
179 82
    public function getMigrationsDirectory() : ?string
180
    {
181 82
        return $this->migrationsDirectory;
182
    }
183
184 211
    public function setMigrationsNamespace(string $migrationsNamespace) : void
185
    {
186 211
        $this->migrationsNamespace = $migrationsNamespace;
187 211
    }
188
189 100
    public function getMigrationsNamespace() : ?string
190
    {
191 100
        return $this->migrationsNamespace;
192
    }
193
194 4
    public function setCustomTemplate(?string $customTemplate) : void
195
    {
196 4
        $this->customTemplate = $customTemplate;
197 4
    }
198
199 9
    public function getCustomTemplate() : ?string
200
    {
201 9
        return $this->customTemplate;
202
    }
203
204 22
    public function areMigrationsOrganizedByYear() : bool
205
    {
206 22
        return $this->migrationsAreOrganizedByYear;
207
    }
208
209
    /**
210
     * @throws MigrationException
211
     */
212 9
    public function setMigrationsAreOrganizedByYear(
213
        bool $migrationsAreOrganizedByYear = true
214
    ) : void {
215 9
        $this->ensureOrganizeMigrationsIsCompatibleWithFinder();
216
217 5
        $this->migrationsAreOrganizedByYear = $migrationsAreOrganizedByYear;
218 5
    }
219
220
    /**
221
     * @throws MigrationException
222
     */
223 10
    public function setMigrationsAreOrganizedByYearAndMonth(
224
        bool $migrationsAreOrganizedByYearAndMonth = true
225
    ) : void {
226 10
        $this->ensureOrganizeMigrationsIsCompatibleWithFinder();
227
228 10
        $this->migrationsAreOrganizedByYear         = $migrationsAreOrganizedByYearAndMonth;
229 10
        $this->migrationsAreOrganizedByYearAndMonth = $migrationsAreOrganizedByYearAndMonth;
230 10
    }
231
232 22
    public function areMigrationsOrganizedByYearAndMonth() : bool
233
    {
234 22
        return $this->migrationsAreOrganizedByYearAndMonth;
235
    }
236
237
    /** @throws MigrationException */
238 8
    public function setMigrationsFinder(MigrationFinder $migrationFinder) : void
239
    {
240 8
        if (($this->migrationsAreOrganizedByYear || $this->migrationsAreOrganizedByYearAndMonth)
241 8
            && ! ($migrationFinder instanceof MigrationDeepFinder)) {
242 4
            throw ParameterIncompatibleWithFinder::new(
243 4
                'organize-migrations',
244 4
                $migrationFinder
245
            );
246
        }
247
248 4
        $this->migrationFinder = $migrationFinder;
249 4
    }
250
251 163
    public function getMigrationsFinder() : MigrationFinder
252
    {
253 163
        if ($this->migrationFinder === null) {
254 159
            $this->migrationFinder = $this->getDependencyFactory()->getRecursiveRegexFinder();
255
        }
256
257 163
        return $this->migrationFinder;
258
    }
259
260
    /** @throws MigrationException */
261 133
    public function validate() : void
262
    {
263 133
        if ($this->migrationsNamespace === null) {
264 1
            throw MigrationsNamespaceRequired::new();
265
        }
266
267 132
        if ($this->migrationsDirectory === null) {
268 1
            throw MigrationsDirectoryRequired::new();
269
        }
270 131
    }
271
272 20
    public function hasVersionMigrated(Version $version) : bool
273
    {
274 20
        return $this->getDependencyFactory()->getMigrationRepository()->hasVersionMigrated($version);
275
    }
276
277
    /**
278
     * @return mixed[]
279
     */
280 5
    public function getVersionData(Version $version) : ?array
281
    {
282 5
        return $this->getDependencyFactory()->getMigrationRepository()->getVersionData($version);
283
    }
284
285 8
    public function resolveVersionAlias(string $alias) : ?string
286
    {
287 8
        return $this->getDependencyFactory()->getVersionAliasResolver()->resolveVersionAlias($alias);
288
    }
289
290 2
    public function setIsDryRun(bool $isDryRun) : void
291
    {
292 2
        $this->isDryRun = $isDryRun;
293 2
    }
294
295 76
    public function isDryRun() : bool
296
    {
297 76
        return $this->isDryRun;
298
    }
299
300 45
    public function setAllOrNothing(bool $allOrNothing) : void
301
    {
302 45
        $this->allOrNothing = $allOrNothing;
303 45
    }
304
305 6
    public function isAllOrNothing() : bool
306
    {
307 6
        return $this->allOrNothing;
308
    }
309
310 45
    public function isMigrationTableCreated() : bool
311
    {
312 45
        return $this->getDependencyFactory()->getTrackingTableStatus()->isCreated();
313
    }
314
315 74
    public function createMigrationTable() : bool
316
    {
317 74
        return $this->getDependencyFactory()->getTrackingTableManipulator()->createMigrationTable();
318
    }
319
320 14
    public function getDateTime(string $version) : string
321
    {
322 14
        $datetime = str_replace('Version', '', $version);
323 14
        $datetime = DateTimeImmutable::createFromFormat(self::VERSION_FORMAT, $datetime);
324
325 14
        if ($datetime === false) {
326 4
            return '';
327
        }
328
329 11
        return $datetime->format('Y-m-d H:i:s');
330
    }
331
332 9
    public function generateVersionNumber(?DateTimeInterface $now = null) : string
333
    {
334 9
        $now = $now ?: $this->createDateTime();
335
336 9
        return $now->format(self::VERSION_FORMAT);
337
    }
338
339
    /**
340
     * Explicitely opens the database connection. This is done to play nice
341
     * with DBAL's MasterSlaveConnection. Which, in some cases, connects to a
342
     * follower when fetching the executed migrations. If a follower is lagging
343
     * significantly behind that means the migrations system may see unexecuted
344
     * migrations that were actually executed earlier.
345
     */
346 62
    public function connect() : bool
347
    {
348 62
        if ($this->connection instanceof MasterSlaveConnection) {
349 1
            return $this->connection->connect('master');
350
        }
351
352 61
        return $this->connection->connect();
353
    }
354
355 27
    public function dispatchMigrationEvent(string $eventName, string $direction, bool $dryRun) : void
356
    {
357 27
        $this->getDependencyFactory()->getEventDispatcher()->dispatchMigrationEvent(
358 27
            $eventName,
359 27
            $direction,
360 27
            $dryRun
361
        );
362 27
    }
363
364 53
    public function dispatchVersionEvent(
365
        Version $version,
366
        string $eventName,
367
        string $direction,
368
        bool $dryRun
369
    ) : void {
370 53
        $this->getDependencyFactory()->getEventDispatcher()->dispatchVersionEvent(
371 53
            $version,
372 53
            $eventName,
373 53
            $direction,
374 53
            $dryRun
375
        );
376 53
    }
377
378 1
    public function dispatchEvent(string $eventName, ?EventArgs $args = null) : void
379
    {
380 1
        $this->getDependencyFactory()->getEventDispatcher()->dispatchEvent(
381 1
            $eventName,
382 1
            $args
383
        );
384 1
    }
385
386 1
    public function getNumberOfExecutedMigrations() : int
387
    {
388 1
        return $this->getDependencyFactory()->getMigrationRepository()->getNumberOfExecutedMigrations();
389
    }
390
391 3
    public function getNumberOfAvailableMigrations() : int
392
    {
393 3
        return $this->getDependencyFactory()->getMigrationRepository()->getNumberOfAvailableMigrations();
394
    }
395
396 4
    public function getLatestVersion() : string
397
    {
398 4
        return $this->getDependencyFactory()->getMigrationRepository()->getLatestVersion();
399
    }
400
401
    /** @return string[] */
402 1
    public function getMigratedVersions() : array
403
    {
404 1
        return $this->getDependencyFactory()->getMigrationRepository()->getMigratedVersions();
405
    }
406
407
    /** @return string[] */
408 3
    public function getAvailableVersions() : array
409
    {
410 3
        return $this->getDependencyFactory()->getMigrationRepository()->getAvailableVersions();
411
    }
412
413 11
    public function getCurrentVersion() : string
414
    {
415 11
        return $this->getDependencyFactory()->getMigrationRepository()->getCurrentVersion();
416
    }
417
418
    /** @return Version[] */
419 64
    public function registerMigrationsFromDirectory(string $path) : array
420
    {
421 64
        $this->validate();
422
423 64
        return $this->getDependencyFactory()->getMigrationRepository()->registerMigrationsFromDirectory($path);
424
    }
425
426
    /** @throws MigrationException */
427 42
    public function registerMigration(string $version, string $class) : Version
428
    {
429 42
        return $this->getDependencyFactory()->getMigrationRepository()->registerMigration($version, $class);
430
    }
431
432
    /**
433
     * @param string[] $migrations
434
     *
435
     * @return Version[]
436
     */
437 5
    public function registerMigrations(array $migrations) : array
438
    {
439 5
        return $this->getDependencyFactory()->getMigrationRepository()->registerMigrations($migrations);
440
    }
441
442
    /**
443
     * @return Version[]
444
     */
445 10
    public function getMigrations() : array
446
    {
447 10
        return $this->getDependencyFactory()->getMigrationRepository()->getMigrations();
448
    }
449
450 20
    public function getVersion(string $version) : Version
451
    {
452 20
        return $this->getDependencyFactory()->getMigrationRepository()->getVersion($version);
453
    }
454
455 3
    public function hasVersion(string $version) : bool
456
    {
457 3
        return $this->getDependencyFactory()->getMigrationRepository()->hasVersion($version);
458
    }
459
460
    /** @return Version[] */
461 33
    public function getMigrationsToExecute(string $direction, string $to) : array
462
    {
463 33
        return $this->getDependencyFactory()->getMigrationPlanCalculator()->getMigrationsToExecute($direction, $to);
464
    }
465
466 2
    public function getPrevVersion() : ?string
467
    {
468 2
        return $this->getDependencyFactory()->getMigrationRepository()->getPrevVersion();
469
    }
470
471 3
    public function getNextVersion() : ?string
472
    {
473 3
        return $this->getDependencyFactory()->getMigrationRepository()->getNextVersion();
474
    }
475
476 3
    public function getRelativeVersion(string $version, int $delta) : ?string
477
    {
478 3
        return $this->getDependencyFactory()->getMigrationRepository()->getRelativeVersion($version, $delta);
479
    }
480
481 1
    public function getDeltaVersion(string $delta) : ?string
482
    {
483 1
        return $this->getDependencyFactory()->getMigrationRepository()->getDeltaVersion($delta);
484
    }
485
486 15
    public function setOutputWriter(OutputWriter $outputWriter) : void
487
    {
488 15
        $this->outputWriter = $outputWriter;
489 15
    }
490
491 132
    public function getOutputWriter() : OutputWriter
492
    {
493 132
        if ($this->outputWriter === null) {
494 103
            $this->outputWriter = $this->getDependencyFactory()->getOutputWriter();
495
        }
496
497 132
        return $this->outputWriter;
498
    }
499
500 7
    public function getQueryWriter() : QueryWriter
501
    {
502 7
        if ($this->queryWriter === null) {
503 6
            $this->queryWriter = $this->getDependencyFactory()->getQueryWriter();
504
        }
505
506 7
        return $this->queryWriter;
507
    }
508
509 202
    public function getDependencyFactory() : DependencyFactory
510
    {
511 202
        if ($this->dependencyFactory === null) {
512 200
            $this->dependencyFactory = new DependencyFactory($this);
513
        }
514
515 202
        return $this->dependencyFactory;
516
    }
517
518
    /**
519
     * @throws MigrationException
520
     */
521 19
    private function ensureOrganizeMigrationsIsCompatibleWithFinder() : void
522
    {
523 19
        if (! ($this->getMigrationsFinder() instanceof MigrationDeepFinder)) {
524 4
            throw ParameterIncompatibleWithFinder::new(
525 4
                'organize-migrations',
526 4
                $this->getMigrationsFinder()
527
            );
528
        }
529 15
    }
530
531 277
    private function createDateTime() : DateTimeImmutable
532
    {
533 277
        return new DateTimeImmutable('now', new DateTimeZone('UTC'));
534
    }
535
}
536