FileDateMigrator   A
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 335
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
wmc 27
lcom 1
cbo 7
dl 0
loc 335
c 0
b 0
f 0
rs 10

17 Methods

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