GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Migrate::run()
last analyzed

Size

Total Lines 75
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 50
c 1
b 0
f 1
nc 11
nop 2
dl 0
loc 75

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of the O2System Framework package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author         Steeve Andrian Salim
9
 * @copyright      Copyright (c) Steeve Andrian Salim
10
 */
11
12
// ------------------------------------------------------------------------
13
14
namespace O2System\Framework\Cli\Commanders;
15
16
// ------------------------------------------------------------------------
17
18
use O2System\Framework\Cli\Commander;
19
use O2System\Framework\Models\Sql\Model;
20
use O2System\Kernel\Cli\Writers\Format;
21
22
/**
23
 * Class Migrate
24
 * @package O2System\Framework\Cli\Commanders
25
 */
26
class Migrate extends Commander
27
{
28
    /**
29
     * Migrate::$commandVersion
30
     *
31
     * Command version.
32
     *
33
     * @var string
34
     */
35
    protected $commandVersion = '1.0.0';
36
37
    /**
38
     * Migrate::$commandDescription
39
     *
40
     * Command description.
41
     *
42
     * @var string
43
     */
44
    protected $commandDescription = 'CLI_MIGRATION_DESC';
45
46
    /**
47
     * Migrate::$commandOptions
48
     *
49
     * Command options.
50
     *
51
     * @var array
52
     */
53
    protected $commandOptions = [
54
        'version'  => [
55
            'description' => 'CLI_MIGRATION_VERSION_HELP',
56
            'required'    => false,
57
        ],
58
        'reset'    => [
59
            'description' => 'CLI_MIGRATION_RESET_HELP',
60
            'required'    => true,
61
        ],
62
        'rollback' => [
63
            'description' => 'CLI_MIGRATION_ROLLBACK_HELP',
64
            'required'    => false,
65
        ],
66
        'refresh'  => [
67
            'description' => 'CLI_MIGRATION_REFRESH_HELP',
68
            'required'    => false,
69
        ],
70
        'fresh'    => [
71
            'description' => 'CLI_MIGRATION_FRESH_HELP',
72
            'required'    => false,
73
        ],
74
        'seed'     => [
75
            'description' => 'CLI_MIGRATION_SEED_HELP',
76
            'required'    => false,
77
        ],
78
    ];
79
80
    /**
81
     * Migrate::$model
82
     *
83
     * @var \O2System\Framework\Models\Sql\Model|\O2System\Framework\Models\NoSql\Model
84
     */
85
    protected $model;
86
87
    /**
88
     * Migrate::$optionGroup
89
     *
90
     * @var string
91
     */
92
    protected $optionGroup = 'default';
93
94
    /**
95
     * Migrate::$optionSeed
96
     *
97
     * @var bool
98
     */
99
    protected $optionSeed = true;
100
101
    /**
102
     * Migrate::$optionSql
103
     *
104
     * @var string
105
     */
106
    protected $optionSql;
107
108
    /**
109
     * Migrate::$optionFilename
110
     *
111
     * @var string
112
     */
113
    protected $optionFilename;
114
115
    /**
116
     * Migrate::$optionBatch
117
     *
118
     * @var int
119
     */
120
    protected $optionBatch;
121
122
    // ------------------------------------------------------------------------
123
124
    /**
125
     * Migrate::optionGroup
126
     *
127
     * @param string $group
128
     */
129
    public function optionGroup($group)
130
    {
131
        if (database()->exists($group)) {
132
            $this->optionGroup = $group;
133
        } else {
134
            output()->write(
0 ignored issues
show
Bug introduced by
The method write() does not exist on O2System\Kernel\Http\Output. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

134
            output()->/** @scrutinizer ignore-call */ write(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
135
                (new Format())
136
                    ->setContextualClass(Format::DANGER)
137
                    ->setString(language()->getLine('CLI_DATABASE_GROUP_NOT_EXISTS', [$group]))
138
                    ->setNewLinesAfter(1)
139
            );
140
141
            exit(EXIT_ERROR);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
142
        }
143
    }
144
145
    // ------------------------------------------------------------------------
146
147
    /**
148
     * Migrate::optionReset
149
     */
150
    public function optionReset()
151
    {
152
        $this->optionReset = true;
0 ignored issues
show
Bug introduced by
The property optionReset does not exist on O2System\Framework\Cli\Commanders\Migrate. Did you mean optionSeed?
Loading history...
153
    }
154
155
    // ------------------------------------------------------------------------
156
157
    /**
158
     * Migrate::optionRefresh
159
     *
160
     * @param string $sql
161
     */
162
    public function optionSql($sql)
163
    {
164
        $this->optionSql = $sql;
165
    }
166
167
    /**
168
     * Migrate::optionFilename
169
     *
170
     * @param string $filename
171
     */
172
    public function optionFilename($filename)
173
    {
174
        $this->optionFilename = $filename;
175
    }
176
177
    /**
178
     * Migrate::optionBatch
179
     *
180
     * @param int $batch
181
     */
182
    public function optionBatch($batch)
183
    {
184
        $this->optionBatch = intval($batch);
185
    }
186
187
    // ------------------------------------------------------------------------
188
189
    /**
190
     * Migrate::optionRefresh
191
     */
192
    public function optionSeed()
193
    {
194
        $this->optionSeed = true;
195
    }
196
197
    // ------------------------------------------------------------------------
198
199
    /**
200
     * Migrate::__call
201
     *
202
     * @param string $method
203
     * @param array  $args
204
     *
205
     * @return mixed
206
     */
207
    public function __call($method, array $args = [])
208
    {
209
        $this->setup(); // always run setup first
210
211
        return parent::__call($method, $args);
212
    }
213
214
    // ------------------------------------------------------------------------
215
216
    /**
217
     * Migrate::setup
218
     */
219
    protected function setup()
220
    {
221
        /**
222
         * Setup System Migrate Database
223
         */
224
        $db = database()->loadConnection($this->optionGroup);
225
226
        if (method_exists($db, 'hasTable')) {
227
            // SQL Migrate Setup
228
            if ( ! $db->hasTable('sys_migrations')) {
229
                $forge = $db->getForge();
230
                $forge->createTable('sys_migrations', [
231
                    'id'                      => [
232
                        'type'           => 'INT',
233
                        'length'         => 10,
234
                        'unsigned'       => true,
235
                        'auto_increment' => true,
236
                        'null'           => false,
237
                        'primary_key'    => true,
238
                    ],
239
                    'filename'                => [
240
                        'type'   => 'VARCHAR',
241
                        'length' => 255,
242
                        'null'   => false,
243
                    ],
244
                    'version'                 => [
245
                        'type'    => 'VARCHAR',
246
                        'length'  => 255,
247
                        'null'    => false,
248
                        'default' => 'v0.0.0',
249
                    ],
250
                    'timestamp'               => [
251
                        'type' => 'datetime',
252
                        'null' => false,
253
                    ],
254
                    'batch'                   => [
255
                        'type'     => 'INT',
256
                        'length'   => 10,
257
                        'unsigned' => true,
258
                        'null'     => false,
259
                        'default'  => 0,
260
                    ],
261
                    'record_status'           => [
262
                        'type'    => 'enum',
263
                        'value'   => ['DELETE', 'TRASH', 'DRAFT', 'UNPUBLISH', 'PUBLISH'],
264
                        'null'    => false,
265
                        'default' => 'PUBLISH',
266
                    ],
267
                    'record_create_timestamp' => [
268
                        'type' => 'datetime',
269
                        'null' => true,
270
                    ],
271
                    'record_create_user'      => [
272
                        'type'     => 'int',
273
                        'length'   => 10,
274
                        'unsigned' => true,
275
                        'null'     => true,
276
                        'default'  => 0,
277
                    ],
278
                    'record_update_timestamp' => [
279
                        'type'      => 'datetime',
280
                        'null'      => true,
281
                        'timestamp' => true,
282
                    ],
283
                    'record_update_user'      => [
284
                        'type'     => 'int',
285
                        'length'   => 10,
286
                        'unsigned' => true,
287
                        'null'     => true,
288
                        'default'  => 0,
289
                    ],
290
                ], true);
291
            }
292
293
            $this->model = new class extends Model
294
            {
295
                /**
296
                 * Model::$table
297
                 *
298
                 * @var string
299
                 */
300
                public $table = 'sys_migrations';
301
302
                /**
303
                 * Model::$visibleColumns
304
                 *
305
                 * @var array
306
                 */
307
                public $visibleColumns = [
308
                    'id',
309
                    'filename',
310
                    'version',
311
                    'timestamp',
312
                    'batch',
313
                ];
314
315
                // ------------------------------------------------------------------------
316
317
                /**
318
                 * Model::__construct
319
                 */
320
                public function register()
321
                {
322
                    $batch = $this->getLatestBatch();
323
                    $files = glob(PATH_DATABASE . "migrations/*.php");
324
325
                    foreach ($files as $filename) {
326
                        $sets = [
327
                            'filename'  => $this->getFilename($filename),
328
                            'version'   => $this->getFileVersion($filename),
329
                            'timestamp' => $this->getFileTimestamp($filename),
330
                            'batch'     => $batch,
331
                        ];
332
333
                        $this->insertOrUpdate($sets, ['filename' => $sets[ 'filename' ]]);
334
                    }
335
                }
336
337
                // ------------------------------------------------------------------------
338
339
                /**
340
                 * Migrate::getFilename
341
                 *
342
                 * Extracts the migration timestamp from a filename
343
                 *
344
                 * @param string $filename
345
                 *
346
                 * @return false|string
347
                 */
348
                protected function getFilename($filename)
349
                {
350
                    return str_replace(PATH_DATABASE . 'migrations' . DIRECTORY_SEPARATOR, '', $filename);
351
                }
352
353
                // ------------------------------------------------------------------------
354
355
                /**
356
                 * Migrate::getFileTimestamp
357
                 *
358
                 * Extracts the migration timestamp from a filename
359
                 *
360
                 * @param string $filename
361
                 *
362
                 * @return false|string
363
                 */
364
                protected function getFileTimestamp($filename)
365
                {
366
                    $timestamp = filemtime($filename);
367
                    preg_match('/\d{4}[-]?\d{2}[-]?\d{2}[-]?\d{2}[-]?\d{2}[-]?\d{2}/', $filename, $matches);
368
369
                    $timestamp = count($matches) ? strtotime($matches[ 0 ]) : $timestamp;
370
371
                    return date('Y-m-d H:i:s', $timestamp);
372
                }
373
374
                // ------------------------------------------------------------------------
375
376
                /**
377
                 * Migrate::getFileVersion
378
                 *
379
                 * Extracts the migration timestamp from a filename
380
                 *
381
                 * @param string $filename
382
                 *
383
                 * @return false|string
384
                 */
385
                protected function getFileVersion($filename)
386
                {
387
                    $version = 'v0.0.0';
388
                    preg_match('/v\d*[.]?\d*[.]\d*/', $filename, $matches);
389
390
                    return count($matches) ? $matches[ 0 ] : $version;
391
                }
392
393
                // ------------------------------------------------------------------------
394
395
                /**
396
                 * Model::getLatestBatch
397
                 */
398
                public function getLatestBatch()
399
                {
400
                    $batch = 1;
401
                    if ($result = $this->qb->table('sys_migrations')->max('batch', 'lastBatch')->get()) {
402
                        if ($result->count()) {
403
                            $batch = (int)$result->first()->lastBatch;
404
                        }
405
                    }
406
407
                    return $batch == 0 ? 1 : $batch;
408
                }
409
            };
410
411
            $this->model->register();
412
        } elseif (method_exists($db, 'hasCollection')) {
413
            // NoSQL Migrate Setup
414
            if ( ! $db->hasCollection('sys_migrations')) {
415
                // Coming Soon
416
            }
417
        }
418
    }
419
420
    // ------------------------------------------------------------------------
421
422
    /**
423
     * Migrate::import
424
     */
425
    public function import()
426
    {
427
        if( ! empty($this->optionSql)) {
428
            $filePath = PATH_DATABASE . str_replace(['/','\\'], DIRECTORY_SEPARATOR, $this->optionSql);
429
430
            if(is_file($filePath)) {
431
                $sqlStatement = file_get_contents($filePath);
432
433
                if($this->model->db->query($sqlStatement)) {
0 ignored issues
show
Bug introduced by
The method query() does not exist on O2System\Database\NoSql\...ts\AbstractQueryBuilder. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

433
                if($this->model->db->/** @scrutinizer ignore-call */ query($sqlStatement)) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method query() does not exist on O2System\Database\Sql\Ab...ts\AbstractQueryBuilder. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

433
                if($this->model->db->/** @scrutinizer ignore-call */ query($sqlStatement)) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
434
435
                } else {
436
437
                }
438
            }
439
        }
440
    }
441
442
    // ------------------------------------------------------------------------
443
444
    /**
445
     * Migrate::latest
446
     */
447
    public function latest()
448
    {
449
        if($result = $this->model->findWhere(['batch' => $this->model->getLatestBatch()])) {
0 ignored issues
show
Bug introduced by
The method getLatestBatch() does not exist on O2System\Framework\Models\NoSql\Model. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

449
        if($result = $this->model->findWhere(['batch' => $this->model->/** @scrutinizer ignore-call */ getLatestBatch()])) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method getLatestBatch() does not exist on O2System\Framework\Models\Sql\Model. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

449
        if($result = $this->model->findWhere(['batch' => $this->model->/** @scrutinizer ignore-call */ getLatestBatch()])) {
Loading history...
450
            if($result->count()) {
451
                foreach($result as $row) {
452
                    $this->run($row->filename, 'up');
453
                }
454
            }
455
        }
456
    }
457
458
    // ------------------------------------------------------------------------
459
460
    /**
461
     * Migrate::rollback
462
     */
463
    public function rollback()
464
    {
465
        $latestBatch = $this->model->getLatestBatch();
466
        $requestBatch = ($latestBatch - 1);
467
        $requestBatch = $requestBatch < 1 ? 1 : $requestBatch;
468
469
        if( ! empty($this->optionBatch) ) {
470
            $requestBatch = $this->optionBatch;
471
        }
472
473
        $batches = range($requestBatch, $latestBatch, 1);
474
        $batches = array_reverse($batches);
475
476
        foreach($batches as $batch) {
477
            if($result = $this->model->findWhere(['batch' => $batch])) {
478
                if($result->count()) {
479
                    foreach($result as $row) {
480
                        $this->run($row->filename, 'down');
481
                        $this->run($row->filename, 'up');
482
                    }
483
                }
484
            }
485
        }
486
    }
487
488
    // ------------------------------------------------------------------------
489
490
    /**
491
     * Migrate::refresh
492
     */
493
    public function refresh()
494
    {
495
        $batch = $this->model->getLatestBatch();
496
        $batches = range(1, $batch, 1);
497
        $batches = array_reverse($batches);
498
499
        foreach($batches as $batch) {
500
            if($result = $this->model->findWhere(['batch' => $batch])) {
501
                if($result->count()) {
502
                    foreach($result as $row) {
503
                        $this->run($row->filename, 'down');
504
                        $this->run($row->filename, 'up');
505
                    }
506
                }
507
            }
508
        }
509
    }
510
511
    // ------------------------------------------------------------------------
512
513
    /**
514
     * Migrate::refresh
515
     */
516
    public function fresh()
517
    {
518
        if($result = $this->model->findWhere(['batch' => 1])) {
519
            if($result->count()) {
520
                foreach($result as $row) {
521
                    $this->run($row->filename, 'up');
522
                }
523
            }
524
        }
525
    }
526
527
    // ------------------------------------------------------------------------
528
529
    /**
530
     * Migrate::run
531
     *
532
     * @param string $filename
533
     * @param string $method
534
     *
535
     * @throws \O2System\Spl\Exceptions\RuntimeException
536
     * @throws \Psr\Cache\InvalidArgumentException
537
     */
538
    protected function run($filename, $method = 'up')
539
    {
540
        $filePaths = [
541
            PATH_DATABASE . 'migrations' . DIRECTORY_SEPARATOR . str_replace(['/','\\'], DIRECTORY_SEPARATOR, $filename),
542
            PATH_DATABASE . str_replace(['/','\\'], DIRECTORY_SEPARATOR, $filename)
543
        ];
544
545
        foreach($filePaths as $filePath) {
546
            if(is_file($filePath)) {
547
                if(pathinfo($filePath, PATHINFO_EXTENSION) == 'php') {
548
                    require_once($filePath);
549
                    $filename = pathinfo($filePath, PATHINFO_FILENAME);
550
                    $filename = explode('_', $filename);
551
                    array_shift($filename);
552
                    $filename = implode('_', $filename);
553
554
                    $className = studlycase($filename);
555
556
                    output()->write(
557
                        (new Format())
558
                            ->setContextualClass(Format::INFO)
559
                            ->setString(language()->getLine('CLI_MIGRATION_RUN_FILENAME', [$filename]))
560
                            ->setNewLinesAfter(1)
561
                    );
562
563
                    if(class_exists($className)) {
564
                        $migration = new $className();
565
566
                        if(method_exists($migration, $method)) {
567
                            call_user_func([$migration, $method]);
568
569
                            output()->write(
570
                                (new Format())
571
                                    ->setContextualClass(Format::SUCCESS)
572
                                    ->setString(language()->getLine('CLI_MIGRATION_RUN_'.strtoupper($method).'_SUCCESS', [$filename]))
573
                                    ->setNewLinesAfter(1)
574
                            );
575
576
                            if($method === 'up') {
577
                                if(method_exists($migration, 'seed')) {
578
                                    if($this->optionSeed) {
579
                                        call_user_func([$migration, 'seed']);
580
581
                                        output()->write(
582
                                            (new Format())
583
                                                ->setContextualClass(Format::SUCCESS)
584
                                                ->setString(language()->getLine('CLI_MIGRATION_RUN_SEED_SUCCESS', [$filename]))
585
                                                ->setNewLinesAfter(1)
586
                                        );
587
                                    }
588
                                }
589
                            }
590
                        }
591
                    }
592
                } elseif(pathinfo($filePath, PATHINFO_EXTENSION) == 'sql') {
593
                    $sqlStatement = file_get_contents($filePath);
594
595
                    if($this->model->db->query($sqlStatement)) {
596
                        output()->write(
597
                            (new Format())
598
                                ->setContextualClass(Format::SUCCESS)
599
                                ->setString(language()->getLine('CLI_MIGRATION_SQL_STATEMENT_EXEC_SUCCESS'))
600
                                ->setNewLinesAfter(1)
601
                        );
602
                    } else {
603
                        output()->write(
604
                            (new Format())
605
                                ->setContextualClass(Format::DANGER)
606
                                ->setString(language()->getLine('CLI_MIGRATION_SQL_STATEMENT_EXEC_FAILED', [$this->model->db->getErrors()]))
0 ignored issues
show
Bug introduced by
The method getErrors() does not exist on O2System\Database\Sql\Abstracts\AbstractConnection. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

606
                                ->setString(language()->getLine('CLI_MIGRATION_SQL_STATEMENT_EXEC_FAILED', [$this->model->db->/** @scrutinizer ignore-call */ getErrors()]))

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method getErrors() does not exist on O2System\Database\Sql\Ab...ts\AbstractQueryBuilder. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

606
                                ->setString(language()->getLine('CLI_MIGRATION_SQL_STATEMENT_EXEC_FAILED', [$this->model->db->/** @scrutinizer ignore-call */ getErrors()]))

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method getErrors() does not exist on O2System\Database\NoSql\...ts\AbstractQueryBuilder. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

606
                                ->setString(language()->getLine('CLI_MIGRATION_SQL_STATEMENT_EXEC_FAILED', [$this->model->db->/** @scrutinizer ignore-call */ getErrors()]))

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
607
                                ->setNewLinesAfter(1)
608
                        );
609
                    }
610
                }
611
612
                break;
613
            }
614
        }
615
    }
616
617
    // ------------------------------------------------------------------------
618
619
    /**
620
     * Migrate::execute
621
     */
622
    public function execute()
623
    {
624
        if($this->optionFilename) {
625
            $this->run($this->optionFilename);
626
        }
627
    }
628
}