|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Yarak\Migrations\FileDate; |
|
4
|
|
|
|
|
5
|
|
|
use Yarak\Helpers\Str; |
|
6
|
|
|
use Yarak\Config\Config; |
|
7
|
|
|
use Yarak\Helpers\Loggable; |
|
8
|
|
|
use Yarak\Helpers\Filesystem; |
|
9
|
|
|
use Yarak\Migrations\Migrator; |
|
10
|
|
|
use Yarak\DB\ConnectionResolver; |
|
11
|
|
|
use Yarak\Migrations\Repositories\MigrationRepository; |
|
12
|
|
|
|
|
13
|
|
|
class FileDateMigrator implements Migrator |
|
14
|
|
|
{ |
|
15
|
|
|
use Filesystem, Loggable; |
|
16
|
|
|
|
|
17
|
|
|
/** |
|
18
|
|
|
* Yarak config. |
|
19
|
|
|
* |
|
20
|
|
|
* @var Config |
|
21
|
|
|
*/ |
|
22
|
|
|
protected $config; |
|
23
|
|
|
|
|
24
|
|
|
/** |
|
25
|
|
|
* Database connection resolver. |
|
26
|
|
|
* |
|
27
|
|
|
* @var ConnectionResolver |
|
28
|
|
|
*/ |
|
29
|
|
|
protected $resolver; |
|
30
|
|
|
|
|
31
|
|
|
/** |
|
32
|
|
|
* Repository for logging migration activity. |
|
33
|
|
|
* |
|
34
|
|
|
* @var MigrationRepository |
|
35
|
|
|
*/ |
|
36
|
|
|
protected $repository; |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* The active database connection. |
|
40
|
|
|
* |
|
41
|
|
|
* @var Phalcon\Db\Adapter\Pdo |
|
42
|
|
|
*/ |
|
43
|
|
|
protected $connection = null; |
|
44
|
|
|
|
|
45
|
|
|
/** |
|
46
|
|
|
* Construct. |
|
47
|
|
|
* |
|
48
|
|
|
* @param Config $config |
|
49
|
|
|
* @param ConnectionResolver $resolver |
|
50
|
|
|
* @param MigrationRepositoryInterface $repository |
|
51
|
|
|
*/ |
|
52
|
|
|
public function __construct( |
|
53
|
|
|
Config $config, |
|
54
|
|
|
ConnectionResolver $resolver, |
|
55
|
|
|
MigrationRepository $repository |
|
56
|
|
|
) { |
|
57
|
|
|
$this->config = $config; |
|
58
|
|
|
$this->resolver = $resolver; |
|
59
|
|
|
$this->repository = $repository; |
|
60
|
|
|
} |
|
61
|
|
|
|
|
62
|
|
|
/** |
|
63
|
|
|
* Run migrations. |
|
64
|
|
|
* |
|
65
|
|
|
* @return array |
|
66
|
|
|
*/ |
|
67
|
|
|
public function run() |
|
68
|
|
|
{ |
|
69
|
|
|
$this->setUp(); |
|
70
|
|
|
|
|
71
|
|
|
$pendingMigrations = $this->getPendingMigrations(); |
|
72
|
|
|
|
|
73
|
|
|
return $this->runPending($pendingMigrations); |
|
74
|
|
|
} |
|
75
|
|
|
|
|
76
|
|
|
/** |
|
77
|
|
|
* Get all migration filenames that have not been run. |
|
78
|
|
|
* |
|
79
|
|
|
* @return array |
|
80
|
|
|
*/ |
|
81
|
|
|
protected function getPendingMigrations() |
|
82
|
|
|
{ |
|
83
|
|
|
return array_diff( |
|
84
|
|
|
$this->getMigrationFiles(), |
|
85
|
|
|
$this->repository->getRanMigrations() |
|
86
|
|
|
); |
|
87
|
|
|
} |
|
88
|
|
|
|
|
89
|
|
|
/** |
|
90
|
|
|
* Get array of migration file names from directory listed in config. |
|
91
|
|
|
* |
|
92
|
|
|
* @return array |
|
93
|
|
|
*/ |
|
94
|
|
|
protected function getMigrationFiles() |
|
95
|
|
|
{ |
|
96
|
|
|
$files = scandir($this->config->getMigrationDirectory()); |
|
97
|
|
|
|
|
98
|
|
|
$files = array_filter($files, function ($file) { |
|
99
|
|
|
return strpos($file, '.php') !== false; |
|
100
|
|
|
}); |
|
101
|
|
|
|
|
102
|
|
|
$files = array_map(function ($file) { |
|
103
|
|
|
return str_replace('.php', '', $file); |
|
104
|
|
|
}, $files); |
|
105
|
|
|
|
|
106
|
|
|
return array_values($files); |
|
107
|
|
|
} |
|
108
|
|
|
|
|
109
|
|
|
/** |
|
110
|
|
|
* Run pending migrations. |
|
111
|
|
|
* |
|
112
|
|
|
* @param array $migrations |
|
113
|
|
|
* |
|
114
|
|
|
* @return array |
|
115
|
|
|
*/ |
|
116
|
|
|
protected function runPending(array $migrations) |
|
117
|
|
|
{ |
|
118
|
|
|
if (count($migrations) === 0) { |
|
119
|
|
|
$this->log('<info>No pending migrations to run.</info>'); |
|
120
|
|
|
|
|
121
|
|
|
return []; |
|
122
|
|
|
} |
|
123
|
|
|
|
|
124
|
|
|
$batch = $this->repository->getNextBatchNumber(); |
|
125
|
|
|
|
|
126
|
|
|
$this->connection->begin(); |
|
127
|
|
|
|
|
128
|
|
|
foreach ($migrations as $migration) { |
|
129
|
|
|
$this->runUp($migration, $batch); |
|
130
|
|
|
} |
|
131
|
|
|
|
|
132
|
|
|
$this->connection->commit(); |
|
133
|
|
|
|
|
134
|
|
|
return $migrations; |
|
135
|
|
|
} |
|
136
|
|
|
|
|
137
|
|
|
/** |
|
138
|
|
|
* Run the migration. |
|
139
|
|
|
* |
|
140
|
|
|
* @param string $migration |
|
141
|
|
|
* @param int $batch |
|
142
|
|
|
*/ |
|
143
|
|
View Code Duplication |
protected function runUp($migration, $batch) |
|
|
|
|
|
|
144
|
|
|
{ |
|
145
|
|
|
$migrationClass = $this->resolveMigrationClass($migration); |
|
146
|
|
|
|
|
147
|
|
|
try { |
|
148
|
|
|
$migrationClass->up($this->connection); |
|
149
|
|
|
} catch (\Exception $e) { |
|
150
|
|
|
return $this->log("<error>{$e->getMessage()}</error>"); |
|
151
|
|
|
} |
|
152
|
|
|
|
|
153
|
|
|
$this->log("<info>Migrated {$migration}.</info>"); |
|
154
|
|
|
|
|
155
|
|
|
$this->repository->insertRecord($migration, $batch); |
|
156
|
|
|
} |
|
157
|
|
|
|
|
158
|
|
|
/** |
|
159
|
|
|
* Resolve the migration class from the file name. |
|
160
|
|
|
* |
|
161
|
|
|
* @param string $migration |
|
162
|
|
|
* |
|
163
|
|
|
* @return Yarak\Migrations\Migration |
|
164
|
|
|
*/ |
|
165
|
|
|
protected function resolveMigrationClass($migration) |
|
166
|
|
|
{ |
|
167
|
|
|
require_once $this->config->getMigrationDirectory().$migration.'.php'; |
|
168
|
|
|
|
|
169
|
|
|
$class = Str::studly(implode('_', array_slice(explode('_', $migration), 4))); |
|
170
|
|
|
|
|
171
|
|
|
return new $class(); |
|
172
|
|
|
} |
|
173
|
|
|
|
|
174
|
|
|
/** |
|
175
|
|
|
* Rollback migrations. |
|
176
|
|
|
* |
|
177
|
|
|
* @param int $steps |
|
178
|
|
|
* |
|
179
|
|
|
* @return array |
|
180
|
|
|
*/ |
|
181
|
|
|
public function rollback($steps = 1) |
|
182
|
|
|
{ |
|
183
|
|
|
$this->setUp(); |
|
184
|
|
|
|
|
185
|
|
|
$toRollback = $this->repository->getRanMigrations(null, $steps); |
|
186
|
|
|
|
|
187
|
|
|
return $this->runRollback($toRollback); |
|
188
|
|
|
} |
|
189
|
|
|
|
|
190
|
|
|
/** |
|
191
|
|
|
* Rollback given migrations. |
|
192
|
|
|
* |
|
193
|
|
|
* @param array $migrations |
|
194
|
|
|
* |
|
195
|
|
|
* @return array |
|
196
|
|
|
*/ |
|
197
|
|
|
protected function runRollback(array $migrations) |
|
198
|
|
|
{ |
|
199
|
|
|
if (count($migrations) === 0) { |
|
200
|
|
|
$this->log('<info>Nothing to rollback.</info>'); |
|
201
|
|
|
|
|
202
|
|
|
return []; |
|
203
|
|
|
} |
|
204
|
|
|
|
|
205
|
|
|
$this->connection->begin(); |
|
206
|
|
|
|
|
207
|
|
|
foreach (array_reverse($migrations) as $migration) { |
|
208
|
|
|
$this->runDown($migration); |
|
209
|
|
|
} |
|
210
|
|
|
|
|
211
|
|
|
$this->connection->commit(); |
|
212
|
|
|
|
|
213
|
|
|
return $migrations; |
|
214
|
|
|
} |
|
215
|
|
|
|
|
216
|
|
|
/** |
|
217
|
|
|
* Rollback the migration. |
|
218
|
|
|
* |
|
219
|
|
|
* @param string $migration |
|
220
|
|
|
*/ |
|
221
|
|
View Code Duplication |
protected function runDown($migration) |
|
|
|
|
|
|
222
|
|
|
{ |
|
223
|
|
|
$migrationClass = $this->resolveMigrationClass($migration); |
|
224
|
|
|
|
|
225
|
|
|
try { |
|
226
|
|
|
$migrationClass->down($this->connection); |
|
227
|
|
|
} catch (\Exception $e) { |
|
228
|
|
|
return $this->log("<error>{$e->getMessage()}</error>"); |
|
229
|
|
|
} |
|
230
|
|
|
|
|
231
|
|
|
$this->log("<info>Rolled back {$migration}.</info>"); |
|
232
|
|
|
|
|
233
|
|
|
$this->repository->deleteRecord($migration); |
|
234
|
|
|
} |
|
235
|
|
|
|
|
236
|
|
|
/** |
|
237
|
|
|
* Reset the database by rolling back all migrations. |
|
238
|
|
|
* |
|
239
|
|
|
* @return array |
|
240
|
|
|
*/ |
|
241
|
|
|
public function reset() |
|
242
|
|
|
{ |
|
243
|
|
|
$this->setUp(); |
|
244
|
|
|
|
|
245
|
|
|
$toRollback = $this->repository->getRanMigrations(); |
|
246
|
|
|
|
|
247
|
|
|
return $this->runRollback($toRollback); |
|
248
|
|
|
} |
|
249
|
|
|
|
|
250
|
|
|
/** |
|
251
|
|
|
* Reset the database and run all migrations. |
|
252
|
|
|
* |
|
253
|
|
|
* @return array |
|
254
|
|
|
*/ |
|
255
|
|
|
public function refresh() |
|
256
|
|
|
{ |
|
257
|
|
|
$this->setUp(); |
|
258
|
|
|
|
|
259
|
|
|
$toRollback = $this->repository->getRanMigrations(); |
|
260
|
|
|
|
|
261
|
|
|
$this->runRollback($toRollback); |
|
262
|
|
|
|
|
263
|
|
|
$pendingMigrations = $this->getPendingMigrations(); |
|
264
|
|
|
|
|
265
|
|
|
return $this->runPending($pendingMigrations); |
|
266
|
|
|
} |
|
267
|
|
|
|
|
268
|
|
|
/** |
|
269
|
|
|
* Perform setup procedures for migrations. |
|
270
|
|
|
*/ |
|
271
|
|
|
protected function setUp() |
|
272
|
|
|
{ |
|
273
|
|
|
if (!$this->connection) { |
|
274
|
|
|
$this->setConnection(); |
|
275
|
|
|
} |
|
276
|
|
|
|
|
277
|
|
|
$this->createMigrationsRepository(); |
|
278
|
|
|
|
|
279
|
|
|
$this->makeDirectoryStructure($this->config->getAllDatabaseDirectories()); |
|
280
|
|
|
} |
|
281
|
|
|
|
|
282
|
|
|
/** |
|
283
|
|
|
* Set connection to database on object. |
|
284
|
|
|
* |
|
285
|
|
|
* @return Pdo |
|
286
|
|
|
*/ |
|
287
|
|
|
public function setConnection() |
|
288
|
|
|
{ |
|
289
|
|
|
$dbConfig = $this->config->get('database'); |
|
290
|
|
|
|
|
291
|
|
|
$this->connection = $this->resolver->getConnection($dbConfig); |
|
|
|
|
|
|
292
|
|
|
|
|
293
|
|
|
$this->repository->setConnection($this->connection); |
|
294
|
|
|
|
|
295
|
|
|
return $this; |
|
|
|
|
|
|
296
|
|
|
} |
|
297
|
|
|
|
|
298
|
|
|
/** |
|
299
|
|
|
* Return the connection. |
|
300
|
|
|
* |
|
301
|
|
|
* @return Phalcon\Db\Adapter\Pdo |
|
302
|
|
|
*/ |
|
303
|
|
|
public function getConnection() |
|
304
|
|
|
{ |
|
305
|
|
|
return $this->connection; |
|
|
|
|
|
|
306
|
|
|
} |
|
307
|
|
|
|
|
308
|
|
|
/** |
|
309
|
|
|
* Create the migrations table if it doesn't exist. |
|
310
|
|
|
*/ |
|
311
|
|
|
protected function createMigrationsRepository() |
|
312
|
|
|
{ |
|
313
|
|
|
if (!$this->repository->exists()) { |
|
314
|
|
|
$this->repository->create(); |
|
315
|
|
|
} |
|
316
|
|
|
|
|
317
|
|
|
return $this; |
|
318
|
|
|
} |
|
319
|
|
|
} |
|
320
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.