Completed
Push — master ( 5f1b15...566d1a )
by Mihail
40:15
created

MigrationsManager   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 155
Duplicated Lines 3.87 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 27
lcom 1
cbo 5
dl 6
loc 155
rs 10
c 1
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 4
C search() 0 35 8
C makeUp() 3 41 8
C makeDown() 3 33 7

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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 $query
47
     * @param bool $exist
48
     * @return array|false
49
     */
50
    public function search($query, $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::contains($query, $fullName)) {
72
                continue;
73
            }
74
75
            // check initialize conditions (equals to $exist)
76
            if (file_exists($this->dir . '/' . $migration)) {
77
                if (Arr::in($fullName, $dbmigrations) === $exist) {
78
                    $found[] = $migration;
79
                }
80
            }
81
        }
82
83
        return $found;
84
    }
85
86
    /**
87
     * Run migration up
88
     * @param string|array $file
89
     * @return bool
90
     */
91
    public function makeUp($file)
92
    {
93
        // check if argument is array of files and run recursion
94
        if (Obj::isArray($file)) {
95
            $success = true;
96
            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...
97
                $exec = $this->makeUp($single);
98
                if (!$exec) {
99
                    $success = false;
100
                }
101
            }
102
            return $success;
103
        }
104
105
        // check if migration file is exists
106
        if (!File::exist($this->dir . '/' . $file)) {
107
            return false;
108
        }
109
110
        // check if migration file located in extend directory and copy to default
111
        if (Normalize::diskFullPath($this->dir) !== Normalize::diskFullPath(static::DEFAULT_DIR)) {
112
            File::copy($this->dir . DIRECTORY_SEPARATOR . $file, static::DEFAULT_DIR . DIRECTORY_SEPARATOR . $file);
113
        }
114
115
        // include migration and get class name
116
        File::inc($this->dir . '/' . $file, false, false);
117
        $fullName = Str::cleanExtension($file);
0 ignored issues
show
Bug introduced by
It seems like $file defined by parameter $file on line 91 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...
118
        $class = Str::firstIn($fullName, '-');
119
120
        // check if class is instance of migration interface
121 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...
122
            return false;
123
        }
124
125
        // implement migration
126
        $init = new $class($fullName);
127
        $init->up();
128
        $init->seed();
129
130
        return true;
131
    }
132
133
    /**
134
     * Make migration down
135
     * @param array|string $file
136
     * @return bool
137
     */
138
    public function makeDown($file)
139
    {
140
        if (Obj::isArray($file)) {
141
            $success = true;
142
            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...
143
                $exec = $this->makeDown($file);
144
                if (!$exec) {
145
                    $success = false;
146
                }
147
                return $success;
148
            }
149
        }
150
151
        // check if exists
152
        if (!File::exist($this->dir . '/' . $file)) {
153
            return false;
154
        }
155
156
        File::inc($this->dir . '/' . $file, false, false);
157
        $fullName = Str::cleanExtension($file);
0 ignored issues
show
Bug introduced by
It seems like $file defined by parameter $file on line 138 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...
158
        $class = Str::firstIn($fullName, '-');
159
160
        // check if class is instance of migration interface
161 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...
162
            return false;
163
        }
164
165
        // init migration and execute down method
166
        $init = new $class($fullName);
167
        $init->down();
168
169
        return true;
170
    }
171
}