1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the AntiMattr MongoDB Migrations Library, a library by Matthew Fitzgerald. |
5
|
|
|
* |
6
|
|
|
* (c) 2014 Matthew Fitzgerald |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace AntiMattr\MongoDB\Migrations\Configuration; |
13
|
|
|
|
14
|
|
|
use AntiMattr\MongoDB\Migrations\Exception\ConfigurationValidationException; |
15
|
|
|
use AntiMattr\MongoDB\Migrations\Exception\DuplicateVersionException; |
16
|
|
|
use AntiMattr\MongoDB\Migrations\Exception\UnknownVersionException; |
17
|
|
|
use AntiMattr\MongoDB\Migrations\OutputWriter; |
18
|
|
|
use AntiMattr\MongoDB\Migrations\Version; |
19
|
|
|
use MongoDB\Client; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @author Matthew Fitzgerald <[email protected]> |
23
|
|
|
*/ |
24
|
|
|
class Configuration |
25
|
|
|
{ |
26
|
|
|
/** |
27
|
|
|
* @var \MongoDB\Collection |
28
|
|
|
*/ |
29
|
|
|
private $collection; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @var \MongoDB\Client |
33
|
|
|
*/ |
34
|
|
|
private $connection; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @var \MongoDB\Database |
38
|
|
|
*/ |
39
|
|
|
private $database; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* The migration database name to track versions in. |
43
|
|
|
* |
44
|
|
|
* @var string |
45
|
|
|
*/ |
46
|
|
|
private $migrationsDatabaseName; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* Flag for whether or not the migration collection has been created. |
50
|
|
|
* |
51
|
|
|
* @var bool |
52
|
|
|
*/ |
53
|
|
|
private $migrationCollectionCreated = false; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* The migration collection name to track versions in. |
57
|
|
|
* |
58
|
|
|
* @var string |
59
|
|
|
*/ |
60
|
|
|
private $migrationsCollectionName = 'antimattr_migration_versions'; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* The path to a directory where new migration classes will be written. |
64
|
|
|
* |
65
|
|
|
* @var string |
66
|
|
|
*/ |
67
|
|
|
private $migrationsDirectory; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* Namespace the migration classes live in. |
71
|
|
|
* |
72
|
|
|
* @var string |
73
|
|
|
*/ |
74
|
|
|
private $migrationsNamespace; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* The path to a directory where mongo console scripts are. |
78
|
|
|
* |
79
|
|
|
* @var string |
80
|
|
|
*/ |
81
|
|
|
private $migrationsScriptDirectory; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Used by Console Commands and Output Writer. |
85
|
|
|
* |
86
|
|
|
* @var string |
87
|
|
|
*/ |
88
|
|
|
private $name; |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @var \AntiMattr\MongoDB\Migrations\Version[] |
92
|
|
|
*/ |
93
|
|
|
protected $migrations = []; |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @var \AntiMattr\MongoDB\Migrations\OutputWriter |
97
|
|
|
*/ |
98
|
|
|
private $outputWriter; |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* @var string |
102
|
|
|
*/ |
103
|
|
|
private $file; |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* @param \MongoDB\Client $connection |
107
|
|
|
* @param \AntiMattr\MongoDB\Migrations\OutputWriter $outputWriter |
108
|
|
|
*/ |
109
|
17 |
|
public function __construct(Client $connection, OutputWriter $outputWriter = null) |
110
|
|
|
{ |
111
|
17 |
|
$this->connection = $connection; |
112
|
17 |
|
if (null === $outputWriter) { |
113
|
14 |
|
$outputWriter = new OutputWriter(); |
114
|
|
|
} |
115
|
17 |
|
$this->outputWriter = $outputWriter; |
116
|
17 |
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* Returns a timestamp version as a formatted date. |
120
|
|
|
* |
121
|
|
|
* @param string $version |
122
|
|
|
* |
123
|
|
|
* @return string The formatted version |
124
|
|
|
*/ |
125
|
5 |
|
public static function formatVersion($version) |
126
|
|
|
{ |
127
|
5 |
|
return sprintf('%s-%s-%s %s:%s:%s', |
128
|
5 |
|
substr($version, 0, 4), |
129
|
5 |
|
substr($version, 4, 2), |
130
|
5 |
|
substr($version, 6, 2), |
131
|
5 |
|
substr($version, 8, 2), |
132
|
5 |
|
substr($version, 10, 2), |
133
|
5 |
|
substr($version, 12, 2) |
134
|
|
|
); |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* Returns an array of available migration version numbers. |
139
|
|
|
* |
140
|
|
|
* @return array |
141
|
|
|
*/ |
142
|
2 |
|
public function getAvailableVersions() |
143
|
|
|
{ |
144
|
2 |
|
$availableVersions = []; |
145
|
2 |
|
foreach ($this->migrations as $migration) { |
146
|
1 |
|
$availableVersions[] = $migration->getVersion(); |
147
|
|
|
} |
148
|
|
|
|
149
|
2 |
|
return $availableVersions; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* @return \MongoDB\Collection |
154
|
|
|
*/ |
155
|
7 |
|
public function getCollection() |
156
|
|
|
{ |
157
|
7 |
|
if (isset($this->collection)) { |
158
|
6 |
|
return $this->collection; |
159
|
|
|
} |
160
|
|
|
|
161
|
7 |
|
$this->collection = $this->getDatabase()->selectCollection($this->migrationsCollectionName); |
162
|
|
|
|
163
|
7 |
|
return $this->collection; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* @return \MongoDB\Client |
168
|
|
|
*/ |
169
|
4 |
|
public function getConnection() |
170
|
|
|
{ |
171
|
4 |
|
return $this->connection; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* @return \MongoDB\Database |
176
|
|
|
*/ |
177
|
9 |
|
public function getDatabase(): ?\MongoDB\Database |
178
|
|
|
{ |
179
|
9 |
|
if (isset($this->database)) { |
180
|
|
|
return $this->database; |
181
|
|
|
} |
182
|
|
|
|
183
|
9 |
|
$this->database = $this->connection->selectDatabase($this->migrationsDatabaseName); |
184
|
|
|
|
185
|
9 |
|
return $this->database; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Get the array of registered migration versions. |
190
|
|
|
* |
191
|
|
|
* @return Version[] $migrations |
192
|
|
|
*/ |
193
|
2 |
|
public function getMigrations() |
194
|
|
|
{ |
195
|
2 |
|
return $this->migrations; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* @param string $databaseName |
200
|
|
|
*/ |
201
|
12 |
|
public function setMigrationsDatabaseName($databaseName) |
202
|
|
|
{ |
203
|
12 |
|
$this->migrationsDatabaseName = $databaseName; |
204
|
|
|
|
205
|
12 |
|
return $this; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* @return string |
210
|
|
|
*/ |
211
|
2 |
|
public function getMigrationsDatabaseName() |
212
|
|
|
{ |
213
|
2 |
|
return $this->migrationsDatabaseName; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* @param string $collectionName |
218
|
|
|
*/ |
219
|
11 |
|
public function setMigrationsCollectionName($collectionName) |
220
|
|
|
{ |
221
|
11 |
|
$this->migrationsCollectionName = $collectionName; |
222
|
|
|
|
223
|
11 |
|
return $this; |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* @return string |
228
|
|
|
*/ |
229
|
2 |
|
public function getMigrationsCollectionName() |
230
|
|
|
{ |
231
|
2 |
|
return $this->migrationsCollectionName; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* @param string $migrationsDirectory |
236
|
|
|
*/ |
237
|
9 |
|
public function setMigrationsDirectory($migrationsDirectory) |
238
|
|
|
{ |
239
|
9 |
|
$this->migrationsDirectory = $migrationsDirectory; |
240
|
|
|
|
241
|
9 |
|
return $this; |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
/** |
245
|
|
|
* @return string |
246
|
|
|
*/ |
247
|
2 |
|
public function getMigrationsDirectory() |
248
|
|
|
{ |
249
|
2 |
|
return $this->migrationsDirectory; |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* Set the migrations namespace. |
254
|
|
|
* |
255
|
|
|
* @param string $migrationsNamespace The migrations namespace |
256
|
|
|
*/ |
257
|
11 |
|
public function setMigrationsNamespace($migrationsNamespace) |
258
|
|
|
{ |
259
|
11 |
|
$this->migrationsNamespace = $migrationsNamespace; |
260
|
|
|
|
261
|
11 |
|
return $this; |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
/** |
265
|
|
|
* @return string $migrationsNamespace |
266
|
|
|
*/ |
267
|
2 |
|
public function getMigrationsNamespace() |
268
|
|
|
{ |
269
|
2 |
|
return $this->migrationsNamespace; |
270
|
|
|
} |
271
|
|
|
|
272
|
|
|
/** |
273
|
|
|
* @param string $scriptsDirectory |
274
|
|
|
*/ |
275
|
2 |
|
public function setMigrationsScriptDirectory($scriptsDirectory) |
276
|
|
|
{ |
277
|
2 |
|
$this->migrationsScriptDirectory = $scriptsDirectory; |
278
|
|
|
|
279
|
2 |
|
return $this; |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
/** |
283
|
|
|
* @return string |
284
|
|
|
*/ |
285
|
2 |
|
public function getMigrationsScriptDirectory() |
286
|
|
|
{ |
287
|
2 |
|
return $this->migrationsScriptDirectory; |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
/** |
291
|
|
|
* @param string $file |
292
|
|
|
*/ |
293
|
3 |
|
public function setFile($file) |
294
|
|
|
{ |
295
|
3 |
|
$this->file = $file; |
296
|
|
|
|
297
|
3 |
|
return $this; |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
/** |
301
|
|
|
* @return string|null |
302
|
|
|
*/ |
303
|
|
|
public function getFile(): ?string |
304
|
|
|
{ |
305
|
|
|
return $this->file; |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
/** |
309
|
|
|
* Returns all migrated versions from the versions collection, in an array. |
310
|
|
|
* |
311
|
|
|
* @return \AntiMattr\MongoDB\Migrations\Version[] |
312
|
|
|
*/ |
313
|
1 |
|
public function getMigratedVersions() |
314
|
|
|
{ |
315
|
1 |
|
$this->createMigrationCollection(); |
316
|
|
|
|
317
|
1 |
|
$cursor = $this->getCollection()->find(); |
318
|
1 |
|
$versions = []; |
319
|
1 |
|
foreach ($cursor as $record) { |
320
|
1 |
|
$versions[] = $record['v']; |
321
|
|
|
} |
322
|
|
|
|
323
|
1 |
|
return $versions; |
324
|
|
|
} |
325
|
|
|
|
326
|
|
|
/** |
327
|
|
|
* Returns the time a migration occurred. |
328
|
|
|
* |
329
|
|
|
* @param string $version |
330
|
|
|
* |
331
|
|
|
* @return int |
332
|
|
|
* |
333
|
|
|
* @throws AntiMattr\MongoDB\Migrations\Exception\UnknownVersionException Throws exception if migration version does not exist |
334
|
|
|
* @throws DomainException If more than one version exists |
335
|
|
|
*/ |
336
|
2 |
|
public function getMigratedTimestamp($version): int |
337
|
|
|
{ |
338
|
2 |
|
$this->createMigrationCollection(); |
339
|
|
|
|
340
|
2 |
|
$cursor = $this->getCollection()->find( |
341
|
2 |
|
['v' => $version] |
342
|
|
|
); |
343
|
|
|
|
344
|
2 |
|
$result = $cursor->toArray(); |
345
|
2 |
|
if (!count($result)) { |
346
|
|
|
throw new UnknownVersionException($version); |
347
|
|
|
} |
348
|
|
|
|
349
|
2 |
|
if (count($result) > 1) { |
350
|
1 |
|
throw new \DomainException( |
351
|
1 |
|
'Unexpected duplicate version records in the database' |
352
|
|
|
); |
353
|
|
|
} |
354
|
|
|
|
355
|
1 |
|
$returnVersion = $result[0]; |
356
|
|
|
|
357
|
|
|
// Convert to normalised timestamp |
358
|
1 |
|
$ts = new Timestamp($returnVersion['t']); |
359
|
|
|
|
360
|
1 |
|
return $ts->getTimestamp(); |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
/** |
364
|
|
|
* Return all migrated versions from versions collection that have migration files deleted. |
365
|
|
|
* |
366
|
|
|
* @return array |
367
|
|
|
*/ |
368
|
1 |
|
public function getUnavailableMigratedVersions() |
369
|
|
|
{ |
370
|
1 |
|
return array_diff($this->getMigratedVersions(), $this->getAvailableVersions()); |
371
|
|
|
} |
372
|
|
|
|
373
|
|
|
/** |
374
|
|
|
* @param string $name |
375
|
|
|
*/ |
376
|
3 |
|
public function setName($name) |
377
|
|
|
{ |
378
|
3 |
|
$this->name = $name; |
379
|
|
|
|
380
|
3 |
|
return $this; |
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
/** |
384
|
|
|
* @return string $name |
385
|
|
|
*/ |
386
|
2 |
|
public function getName() |
387
|
|
|
{ |
388
|
2 |
|
return ($this->name) ?: 'Database Migrations'; |
389
|
|
|
} |
390
|
|
|
|
391
|
|
|
/** |
392
|
|
|
* @return int |
393
|
|
|
*/ |
394
|
1 |
|
public function getNumberOfAvailableMigrations() |
395
|
|
|
{ |
396
|
1 |
|
return count($this->migrations); |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
/** |
400
|
|
|
* @return int |
401
|
|
|
*/ |
402
|
1 |
|
public function getNumberOfExecutedMigrations() |
403
|
|
|
{ |
404
|
1 |
|
$this->createMigrationCollection(); |
405
|
|
|
|
406
|
1 |
|
return $this->getCollection()->countDocuments(); |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
/** |
410
|
|
|
* @return \AntiMattr\MongoDB\Migrations\OutputWriter |
411
|
|
|
*/ |
412
|
5 |
|
public function getOutputWriter() |
413
|
|
|
{ |
414
|
5 |
|
return $this->outputWriter; |
415
|
|
|
} |
416
|
|
|
|
417
|
|
|
/** |
418
|
|
|
* Register a single migration version to be executed by a AbstractMigration |
419
|
|
|
* class. |
420
|
|
|
* |
421
|
|
|
* @param string $version The version of the migration in the format YYYYMMDDHHMMSS |
422
|
|
|
* @param string $class The migration class to execute for the version |
423
|
|
|
* |
424
|
|
|
* @return Version |
425
|
|
|
* |
426
|
|
|
* @throws AntiMattr\MongoDB\Migrations\Exception\DuplicateVersionException |
427
|
|
|
*/ |
428
|
2 |
|
public function registerMigration($version, $class) |
429
|
|
|
{ |
430
|
2 |
|
$version = (string) $version; |
431
|
2 |
|
$class = (string) $class; |
432
|
2 |
|
if (isset($this->migrations[$version])) { |
433
|
|
|
$message = sprintf( |
434
|
|
|
'Migration version %s already registered with class %s', |
435
|
|
|
$version, |
436
|
|
|
get_class($this->migrations[$version]) |
437
|
|
|
); |
438
|
|
|
throw new DuplicateVersionException($message); |
439
|
|
|
} |
440
|
2 |
|
$version = new Version($this, $version, $class); |
441
|
2 |
|
$this->migrations[$version->getVersion()] = $version; |
442
|
2 |
|
ksort($this->migrations); |
443
|
|
|
|
444
|
2 |
|
return $version; |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
/** |
448
|
|
|
* Register an array of migrations. Each key of the array is the version and |
449
|
|
|
* the value is the migration class name. |
450
|
|
|
* |
451
|
|
|
* |
452
|
|
|
* @param array $migrations |
453
|
|
|
* |
454
|
|
|
* @return Version[] |
455
|
|
|
*/ |
456
|
|
|
public function registerMigrations(array $migrations) |
457
|
|
|
{ |
458
|
|
|
$versions = []; |
459
|
|
|
foreach ($migrations as $version => $class) { |
460
|
|
|
$versions[] = $this->registerMigration($version, $class); |
461
|
|
|
} |
462
|
|
|
|
463
|
|
|
return $versions; |
464
|
|
|
} |
465
|
|
|
|
466
|
|
|
/** |
467
|
|
|
* Register migrations from a given directory. Recursively finds all files |
468
|
|
|
* with the pattern VersionYYYYMMDDHHMMSS.php as the filename and registers |
469
|
|
|
* them as migrations. |
470
|
|
|
* |
471
|
|
|
* @param string $path The root directory to where some migration classes live |
472
|
|
|
* |
473
|
|
|
* @return Version[] The array of migrations registered |
474
|
|
|
*/ |
475
|
4 |
|
public function registerMigrationsFromDirectory($path) |
476
|
|
|
{ |
477
|
4 |
|
$path = realpath($path); |
478
|
4 |
|
$path = rtrim($path, '/'); |
479
|
4 |
|
$files = glob($path . '/Version*.php'); |
480
|
4 |
|
$versions = []; |
481
|
4 |
|
if ($files) { |
|
|
|
|
482
|
2 |
|
foreach ($files as $file) { |
483
|
2 |
|
require_once $file; |
484
|
2 |
|
$info = pathinfo($file); |
485
|
2 |
|
$version = substr($info['filename'], 7); |
486
|
2 |
|
$class = $this->migrationsNamespace . '\\' . $info['filename']; |
487
|
2 |
|
$versions[] = $this->registerMigration($version, $class); |
488
|
|
|
} |
489
|
|
|
} |
490
|
|
|
|
491
|
4 |
|
return $versions; |
492
|
|
|
} |
493
|
|
|
|
494
|
|
|
/** |
495
|
|
|
* Returns the Version instance for a given version in the format YYYYMMDDHHMMSS. |
496
|
|
|
* |
497
|
|
|
* @param string $version The version string in the format YYYYMMDDHHMMSS |
498
|
|
|
* |
499
|
|
|
* @return \AntiMattr\MongoDB\Migrations\Version |
500
|
|
|
* |
501
|
|
|
* @throws AntiMattr\MongoDB\Migrations\Exception\UnknownVersionException Throws exception if migration version does not exist |
502
|
|
|
*/ |
503
|
2 |
|
public function getVersion($version) |
504
|
|
|
{ |
505
|
2 |
|
if (!isset($this->migrations[$version])) { |
506
|
1 |
|
throw new UnknownVersionException($version); |
507
|
|
|
} |
508
|
|
|
|
509
|
1 |
|
return $this->migrations[$version]; |
510
|
|
|
} |
511
|
|
|
|
512
|
|
|
/** |
513
|
|
|
* Check if a version exists. |
514
|
|
|
* |
515
|
|
|
* @param string $version |
516
|
|
|
* |
517
|
|
|
* @return bool |
518
|
|
|
*/ |
519
|
1 |
|
public function hasVersion($version) |
520
|
|
|
{ |
521
|
1 |
|
return isset($this->migrations[$version]); |
522
|
|
|
} |
523
|
|
|
|
524
|
|
|
/** |
525
|
|
|
* Check if a version has been migrated or not yet. |
526
|
|
|
* |
527
|
|
|
* @param \AntiMattr\MongoDB\Migrations\Version $version |
528
|
|
|
* |
529
|
|
|
* @return bool |
530
|
|
|
*/ |
531
|
1 |
|
public function hasVersionMigrated(Version $version) |
532
|
|
|
{ |
533
|
1 |
|
$this->createMigrationCollection(); |
534
|
|
|
|
535
|
1 |
|
$record = $this->getCollection()->findOne(['v' => $version->getVersion()]); |
536
|
|
|
|
537
|
1 |
|
return null !== $record; |
538
|
|
|
} |
539
|
|
|
|
540
|
|
|
/** |
541
|
|
|
* @return string |
542
|
|
|
*/ |
543
|
1 |
|
public function getCurrentVersion() |
544
|
|
|
{ |
545
|
1 |
|
$this->createMigrationCollection(); |
546
|
|
|
|
547
|
1 |
|
$migratedVersions = []; |
548
|
1 |
|
if (!empty($this->migrations)) { |
549
|
1 |
|
foreach ($this->migrations as $migration) { |
550
|
1 |
|
$migratedVersions[] = $migration->getVersion(); |
551
|
|
|
} |
552
|
|
|
} |
553
|
|
|
|
554
|
1 |
|
$cursor = $this->getCollection() |
555
|
1 |
|
->find( |
556
|
1 |
|
['v' => ['$in' => $migratedVersions]], |
557
|
1 |
|
['sort' => ['v' => -1], 'limit' => 1] |
558
|
|
|
); |
559
|
|
|
|
560
|
1 |
|
$versions = $cursor->toArray(); |
561
|
1 |
|
if (0 === \count($versions)) { |
562
|
|
|
return '0'; |
563
|
|
|
} |
564
|
|
|
|
565
|
1 |
|
$version = $versions[0]; |
566
|
1 |
|
return $version['v']; |
567
|
|
|
} |
568
|
|
|
|
569
|
|
|
/** |
570
|
|
|
* Returns the latest available migration version. |
571
|
|
|
* |
572
|
|
|
* @return string The version string in the format YYYYMMDDHHMMSS |
573
|
|
|
*/ |
574
|
|
|
public function getLatestVersion() |
575
|
|
|
{ |
576
|
|
|
$versions = array_keys($this->migrations); |
577
|
|
|
$latest = end($versions); |
578
|
|
|
|
579
|
|
|
return false !== $latest ? (string) $latest : '0'; |
580
|
|
|
} |
581
|
|
|
|
582
|
|
|
/** |
583
|
|
|
* Create the migration collection to track migrations with. |
584
|
|
|
* |
585
|
|
|
* @return bool Whether or not the collection was created |
586
|
|
|
*/ |
587
|
6 |
|
public function createMigrationCollection() |
588
|
|
|
{ |
589
|
6 |
|
$this->validate(); |
590
|
|
|
|
591
|
6 |
|
if (true !== $this->migrationCollectionCreated) { |
592
|
6 |
|
$collection = $this->getCollection(); |
593
|
6 |
|
$collection->createIndex(['v' => -1], ['name' => 'version', 'unique' => true]); |
594
|
6 |
|
$this->migrationCollectionCreated = true; |
595
|
|
|
} |
596
|
|
|
|
597
|
6 |
|
return true; |
598
|
|
|
} |
599
|
|
|
|
600
|
|
|
/** |
601
|
|
|
* Returns the array of migrations to executed based on the given direction |
602
|
|
|
* and target version number. |
603
|
|
|
* |
604
|
|
|
* @param string $direction The direction we are migrating |
605
|
|
|
* @param string $to The version to migrate to |
606
|
|
|
* |
607
|
|
|
* @return Version[] $migrations The array of migrations we can execute |
608
|
|
|
*/ |
609
|
|
|
public function getMigrationsToExecute($direction, $to) |
610
|
|
|
{ |
611
|
|
|
if ('down' === $direction) { |
612
|
|
|
if (count($this->migrations)) { |
613
|
|
|
$allVersions = array_reverse(array_keys($this->migrations)); |
614
|
|
|
$classes = array_reverse(array_values($this->migrations)); |
615
|
|
|
$allVersions = array_combine($allVersions, $classes); |
616
|
|
|
} else { |
617
|
|
|
$allVersions = []; |
618
|
|
|
} |
619
|
|
|
} else { |
620
|
|
|
$allVersions = $this->migrations; |
621
|
|
|
} |
622
|
|
|
$versions = []; |
623
|
|
|
$migrated = $this->getMigratedVersions(); |
624
|
|
|
foreach ($allVersions as $version) { |
625
|
|
|
if ($this->shouldExecuteMigration($direction, $version, $to, $migrated)) { |
626
|
|
|
$versions[$version->getVersion()] = $version; |
627
|
|
|
} |
628
|
|
|
} |
629
|
|
|
|
630
|
|
|
return $versions; |
631
|
|
|
} |
632
|
|
|
|
633
|
|
|
/** |
634
|
|
|
* Check if we should execute a migration for a given direction and target |
635
|
|
|
* migration version. |
636
|
|
|
* |
637
|
|
|
* @param string $direction The direction we are migrating |
638
|
|
|
* @param Version $version The Version instance to check |
639
|
|
|
* @param string $to The version we are migrating to |
640
|
|
|
* @param array $migrated Migrated versions array |
641
|
|
|
* |
642
|
|
|
* @return bool |
643
|
|
|
*/ |
644
|
|
|
private function shouldExecuteMigration($direction, Version $version, $to, $migrated) |
645
|
|
|
{ |
646
|
|
|
if ('down' === $direction) { |
647
|
|
|
if (!in_array($version->getVersion(), $migrated)) { |
648
|
|
|
return false; |
649
|
|
|
} |
650
|
|
|
|
651
|
|
|
return $version->getVersion() > $to; |
652
|
|
|
} |
653
|
|
|
|
654
|
|
|
if ('up' === $direction) { |
655
|
|
|
if (in_array($version->getVersion(), $migrated)) { |
656
|
|
|
return false; |
657
|
|
|
} |
658
|
|
|
|
659
|
|
|
return $version->getVersion() <= $to; |
660
|
|
|
} |
661
|
|
|
} |
662
|
|
|
|
663
|
|
|
/** |
664
|
|
|
* Validation that this instance has all the required properties configured. |
665
|
|
|
* |
666
|
|
|
* @throws AntiMattr\MongoDB\Migrations\Exception\ConfigurationValidationException |
667
|
|
|
*/ |
668
|
8 |
|
public function validate() |
669
|
|
|
{ |
670
|
8 |
|
if (!$this->migrationsDatabaseName) { |
671
|
1 |
|
$message = 'Migrations Database Name must be configured in order to use AntiMattr migrations.'; |
672
|
1 |
|
throw new ConfigurationValidationException($message); |
673
|
|
|
} |
674
|
7 |
|
if (!$this->migrationsNamespace) { |
675
|
|
|
$message = 'Migrations namespace must be configured in order to use AntiMattr migrations.'; |
676
|
|
|
throw new ConfigurationValidationException($message); |
677
|
|
|
} |
678
|
7 |
|
if (!$this->migrationsDirectory) { |
679
|
|
|
$message = 'Migrations directory must be configured in order to use AntiMattr migrations.'; |
680
|
|
|
throw new ConfigurationValidationException($message); |
681
|
|
|
} |
682
|
7 |
|
} |
683
|
|
|
|
684
|
|
|
/** |
685
|
|
|
* @return array |
686
|
|
|
*/ |
687
|
|
|
public function getDetailsMap() |
688
|
|
|
{ |
689
|
|
|
// Executed migration count |
690
|
|
|
$executedMigrations = $this->getMigratedVersions(); |
691
|
|
|
$numExecutedMigrations = count($executedMigrations); |
692
|
|
|
|
693
|
|
|
// Available migration count |
694
|
|
|
$availableMigrations = $this->getAvailableVersions(); |
695
|
|
|
$numAvailableMigrations = count($availableMigrations); |
696
|
|
|
|
697
|
|
|
// Executed Unavailable migration count |
698
|
|
|
$numExecutedUnavailableMigrations = count($this->getUnavailableMigratedVersions()); |
699
|
|
|
|
700
|
|
|
// New migration count |
701
|
|
|
$numNewMigrations = $numAvailableMigrations - ($numExecutedMigrations - $numExecutedUnavailableMigrations); |
702
|
|
|
|
703
|
|
|
return [ |
704
|
|
|
'name' => $this->getName(), |
705
|
|
|
'database_driver' => 'MongoDB', |
706
|
|
|
'migrations_database_name' => $this->getMigrationsDatabaseName(), |
707
|
|
|
'migrations_collection_name' => $this->getMigrationsCollectionName(), |
708
|
|
|
'migrations_namespace' => $this->getMigrationsNamespace(), |
709
|
|
|
'migrations_directory' => $this->getMigrationsDirectory(), |
710
|
|
|
'current_version' => $this->getCurrentVersion(), |
711
|
|
|
'latest_version' => $this->getLatestVersion(), |
712
|
|
|
'num_executed_migrations' => $numExecutedMigrations, |
713
|
|
|
'num_executed_unavailable_migrations' => $numExecutedUnavailableMigrations, |
714
|
|
|
'num_available_migrations' => $numAvailableMigrations, |
715
|
|
|
'num_new_migrations' => $numNewMigrations, |
716
|
|
|
]; |
717
|
|
|
} |
718
|
|
|
} |
719
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.