Completed
Push — master ( 566d1a...ee0428 )
by Mihail
02:27
created

MigrationsManager::search()   D

Complexity

Conditions 9
Paths 12

Size

Total Lines 34
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 34
rs 4.909
cc 9
eloc 17
nc 12
nop 2
1
<?php
2
3
namespace Ffcms\Core\Managers;
4
5
6
use Apps\ActiveRecord\Migration;
7
use Ffcms\Core\Helper\FileSystem\File;
8
use Ffcms\Core\Helper\FileSystem\Normalize;
9
use Ffcms\Core\Helper\Type\Arr;
10
use Ffcms\Core\Helper\Type\Obj;
11
use Ffcms\Core\Helper\Type\Str;
12
13
/**
14
 * Class MigrationsManager. Manage migration files and database.
15
 * @package Ffcms\Core\Managers
16
 */
17
class MigrationsManager
18
{
19
    const DEFAULT_DIR = '/Private/Migrations';
20
21
    private $dir;
22
    private $connection;
23
    private $customDir = false;
24
25
    /**
26
     * MigrationsManager constructor. Pass directory inside or use default
27
     * @param string|null $dir
28
     * @param string|null $connectionName
29
     */
30
    public function __construct($dir = null, $connectionName = null)
31
    {
32
        if ($dir === null || !Obj::isString($dir)) {
33
            $dir = static::DEFAULT_DIR;
34
        }
35
36
        $this->dir = rtrim($dir, '/');
37
        $this->connection = $connectionName;
38
39
        if ($this->dir !== static::DEFAULT_DIR) {
40
            $this->customDir = true;
41
        }
42
    }
43
44
    /**
45
     * Search migration files. If $exists = false search only not installed files, if true - only installed
46
     * @param string|null $query
47
     * @param bool $exist
48
     * @return array|false
49
     */
50
    public function search($query = null, $exist = false)
51
    {
52
        // initialize db migration record
53
        $records = new Migration();
54
        if ($this->connection !== null) {
55
            $records->setConnection($this->connection);
56
        }
57
        // get installed migrations
58
        $dbmigrations = Arr::pluck('migration', $records->get()->toArray());
59
60
        // list migrations
61
        $migrations = File::listFiles($this->dir, ['.php'], true);
62
        if (!Obj::isArray($migrations) || count($migrations) < 1) {
63
            return false;
64
        }
65
66
        $found = false;
67
        foreach ($migrations as $migration) {
68
            // parse migration fullname
69
            $fullName = Str::cleanExtension($migration);
70
            // check if name contains search query conditions
71
            if (!Str::likeEmpty($query) && !Str::contains($query, $fullName)) {
72
                continue;
73
            }
74
            // check initialize conditions (equals to $exist)
75
            if (File::exist($this->dir . '/' . $migration)) {
76
                if (Arr::in($fullName, $dbmigrations) === $exist) {
77
                    $found[] = $migration;
78
                }
79
            }
80
        }
81
82
        return $found;
83
    }
84
85
    /**
86
     * Run migration up
87
     * @param string|array $file
88
     * @return bool
89
     */
90
    public function makeUp($file)
91
    {
92
        // check if argument is array of files and run recursion
93
        if (Obj::isArray($file)) {
94
            $success = true;
95
            foreach ($file as $single) {
0 ignored issues
show
Bug introduced by
The expression $file of type string|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
96
                $exec = $this->makeUp($single);
97
                if (!$exec) {
98
                    $success = false;
99
                }
100
            }
101
            return $success;
102
        }
103
104
        // check if migration file is exists
105
        if (!File::exist($this->dir . '/' . $file)) {
106
            return false;
107
        }
108
109
        // check if migration file located in extend directory and copy to default
110
        if (Normalize::diskFullPath($this->dir) !== Normalize::diskFullPath(static::DEFAULT_DIR)) {
111
            File::copy($this->dir . DIRECTORY_SEPARATOR . $file, static::DEFAULT_DIR . DIRECTORY_SEPARATOR . $file);
112
        }
113
114
        // include migration and get class name
115
        File::inc($this->dir . '/' . $file, false, false);
116
        $fullName = Str::cleanExtension($file);
0 ignored issues
show
Bug introduced by
It seems like $file defined by parameter $file on line 90 can also be of type array; however, Ffcms\Core\Helper\Type\Str::cleanExtension() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
117
        $class = Str::firstIn($fullName, '-');
118
119
        // check if class is instance of migration interface
120 View Code Duplication
        if (!class_exists($class) || !is_a($class, 'Ffcms\Core\Migrations\MigrationInterface', true)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
121
            return false;
122
        }
123
124
        // implement migration
125
        $init = new $class($fullName, $this->connection);
126
        $init->up();
127
        $init->seed();
128
129
        return true;
130
    }
131
132
    /**
133
     * Make migration down
134
     * @param array|string $file
135
     * @return bool
136
     */
137
    public function makeDown($file)
138
    {
139
        if (Obj::isArray($file)) {
140
            $success = true;
141
            foreach ($file as $item) {
0 ignored issues
show
Bug introduced by
The expression $file of type array|string is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
142
                $exec = $this->makeDown($file);
143
                if (!$exec) {
144
                    $success = false;
145
                }
146
                return $success;
147
            }
148
        }
149
150
        // check if exists
151
        if (!File::exist($this->dir . '/' . $file)) {
152
            return false;
153
        }
154
155
        File::inc($this->dir . '/' . $file, false, false);
156
        $fullName = Str::cleanExtension($file);
0 ignored issues
show
Bug introduced by
It seems like $file defined by parameter $file on line 137 can also be of type array; however, Ffcms\Core\Helper\Type\Str::cleanExtension() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
157
        $class = Str::firstIn($fullName, '-');
158
159
        // check if class is instance of migration interface
160 View Code Duplication
        if (!class_exists($class) || !is_a($class, 'Ffcms\Core\Migrations\MigrationInterface', true)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
161
            return false;
162
        }
163
164
        // init migration and execute down method
165
        $init = new $class($fullName, $this->connection);
166
        $init->down();
167
168
        return true;
169
    }
170
}