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.

MigrationController   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 310
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 10
Bugs 0 Features 0
Metric Value
wmc 43
c 10
b 0
f 0
lcom 1
cbo 6
dl 0
loc 310
rs 8.3157

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getMigrationFolder() 0 9 2
B executeAction() 0 28 5
C applyMigration() 0 49 11
B createAction() 0 43 5
C upgradeAction() 0 76 12
A lastAction() 0 23 3
A isApplySchema() 0 16 4
A includeMigration() 0 6 1

How to fix   Complexity   

Complex Class

Complex classes like MigrationController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MigrationController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace ConsoleTools\Controller;
4
5
use Zend\Db\Adapter\Adapter;
6
use Zend\Mvc\Controller\AbstractActionController;
7
use Zend\Console\ColorInterface as Color;
8
use Zend\Console\Adapter\AdapterInterface as Console;
9
use Zend\Console\Exception\RuntimeException;
10
use ConsoleTools\Model\Migration;
11
use Zend\Console\Prompt\Char;
12
13
/**
14
 * Controller for console operations as create, upgrate and current migrations
15
 *
16
 * @author     V.Leontiev <[email protected]>
17
 * @license    http://opensource.org/licenses/MIT MIT
18
 * @since      php 5.6 or higher
19
 * @see        https://github.com/newage/console-tools
20
 */
21
class MigrationController extends AbstractActionController
22
{
23
    const UPGRADE_KEY = 'up';
24
    const DOWNGRADE_KEY = 'down';
25
26
    /**
27
     * Destination to folder with migration files
28
     *
29
     * @var string
30
     */
31
    protected $migrationFolder = null;
32
33
    /**
34
     * Execute one migration
35
     *
36
     */
37
    public function executeAction()
38
    {
39
        /* @var $console Console */
40
        $console   = $this->getServiceLocator()->get('console');
41
        $request   = $this->getRequest();
42
        $migration = $request->getParam('number');
43
        $percona = $request->getParam('percona');
44
        $port = $request->getParam('port');
45
46
        $migrationPath = $this->getMigrationFolder();
47
        $filePath = $migrationPath . $migration . '.php';
48
49
        if (!file_exists($filePath)) {
50
            $console->writeLine('Migration does not exists: ' . $filePath, Color::RED);
51
        } else {
52
            if (!$this->isApplySchema($console)) {
53
                false;
54
            }
55
56
            $migrationArray = $this->includeMigration($filePath);
57
58
            if ($request->getParam(self::UPGRADE_KEY)) {
59
                $this->applyMigration(self::UPGRADE_KEY, $migration, $migrationArray, $percona, $port);
60
            } elseif ($request->getParam(self::DOWNGRADE_KEY)) {
61
                $this->applyMigration(self::DOWNGRADE_KEY, $migration, $migrationArray, $percona, $port);
62
            }
63
        }
64
    }
65
66
    /**
67
     * Show confirm for migration
68
     *
69
     * @param string $action
70
     * @param string $migration
71
     * @param array $migrationArray
72
     * @return bool
73
     */
74
    protected function applyMigration($action, $migration, $migrationArray, $percona, $port)
75
    {
76
        /* @var $adapter \Zend\Db\Adapter\Adapter */
77
        /* @var $console Console */
78
        $adapter    = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
79
        $console    = $this->getServiceLocator()->get('console');
80
        $model      = new Migration($adapter, $this->getServiceLocator(), $percona, $port);
0 ignored issues
show
Documentation introduced by
$adapter is of type object|array, but the function expects a object<Zend\Db\Adapter\Adapter>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
81
        $methodName = $action == self::UPGRADE_KEY ? 'upgrade' : 'downgrade';
82
83
        $console->writeLine();
84
        $console->write('Current migration: ');
85
        $console->writeLine($this->getMigrationFolder() . $migration . '.php', Color::YELLOW);
86
        $console->writeLine($migrationArray[$action], Color::BLUE);
87
        $exist = $model->get(array('migration' => $migration));
88
        $doNotSaveAsExecuted = false;
89
        if (!empty($exist) && empty($exist['ignored'])) {
90
            $console->writeLine('This migration was already executed', Color::YELLOW);
91
            $doNotSaveAsExecuted = true;
92
        } elseif (!empty($exist) && !empty($exist['ignored'])) {
93
            $console->writeLine('This migration was already pseudo-executed (ignored)', Color::LIGHT_CYAN);
94
        }
95
        $answer = Char::prompt('Apply this migration (Yes / no / ignore forever)? [y/n/i]', 'yni');
96
        switch ($answer) {
97
            case 'y':
98
                if ($action == self::UPGRADE_KEY) {
99
                    $model->$methodName($migration, $migrationArray, $ignore = false, $doNotSaveAsExecuted);
100
                    $console->writeLine('This migration successful upgraded', Color::GREEN);
101
                } else {
102
                    $model->$methodName($migration, $migrationArray, $ignore = false);
103
                    $console->writeLine('This migration successful downgraded', Color::GREEN);
104
                }
105
                break;
106
            case 'i':
107
                $model->$methodName($migration, $migrationArray, $ignore = true);
108
                if ($action == self::UPGRADE_KEY) {
109
                    $console->writeLine('This migration pseudo-upgraded', Color::LIGHT_CYAN);
110
                } else {
111
                    $console->writeLine('This migration pseudo-downgraded', Color::LIGHT_CYAN);
112
                }
113
                break;
114
            case 'n':
115
            default:
116
                $console->writeLine('This migration discarded', Color::RED);
117
                return false;
118
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
119
        }
120
121
        return true;
122
    }
123
124
    /**
125
     * Create new migration file
126
     *
127
     * @throws RuntimeException
128
     */
129
    public function createAction()
130
    {
131
        $console = $this->getServiceLocator()->get('console');
132
133
        if (!$console instanceof Console) {
134
            throw new RuntimeException('Cannot obtain console adapter. Are we running in a console?');
135
        }
136
        $request = $this->getRequest();
137
        $short_name = $request->getParam('short_name', '');
138
139
        $config = $this->getServiceLocator()->get('Config');
140
        if (isset($config['console-tools']['migration_template'])) {
141
            $dateTemplate = $config['console-tools']['migration_template'];
142
        } else {
143
            $dateTemplate = 'YmdHis';
144
        }
145
146
        $migrationPath = $this->getMigrationFolder();
147
        if (!is_dir($migrationPath)) {
148
            mkdir($migrationPath, 0777);
149
        }
150
151
        $date = new \DateTime();
152
        if ($short_name) {
153
            $short_name = '_' . $short_name;
154
        }
155
156
        $migrationName = $date->format($dateTemplate) . $short_name . '.php';
157
158
        $migrationContent = <<<EOD
159
<?php
160
        
161
return [
162
    'up' => "",
163
    'down' => ""
164
];
165
166
EOD;
167
168
        file_put_contents($migrationPath . $migrationName, $migrationContent);
169
170
        $console->writeLine('Created migration file: ' . $migrationPath . $migrationName, Color::GREEN);
171
    }
172
173
    /**
174
     * Upgrade/downgrade to migration
175
     *
176
     * @throws RuntimeException
177
     */
178
    public function upgradeAction()
179
    {
180
        $console = $this->getServiceLocator()->get('console');
181
        if (!$console instanceof Console) {
182
            throw new RuntimeException('Cannot obtain console adapter. Are we running in a console?');
183
        }
184
185
        $adapter             = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
186
        $request             = $this->getRequest();
187
        $toMigration         = $request->getParam('number', 'all');
188
        $percona             = $request->getParam('percona');
189
        $port                = $request->getParam('port');
190
        $model               = new Migration($adapter, $this->getServiceLocator(), $percona, $port);
0 ignored issues
show
Documentation introduced by
$adapter is of type object|array, but the function expects a object<Zend\Db\Adapter\Adapter>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
191
        $migrationsFromBase  = $model->applied();
192
        $migrationFolderPath = $this->getMigrationFolder();
193
        $files               = array();
194
195
        if (!$this->isApplySchema($console, $adapter)) {
0 ignored issues
show
Documentation introduced by
$adapter is of type object|array, but the function expects a null|object<Zend\Db\Adapter\Adapter>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
196
            false;
197
        }
198
199
        if ($toMigration == 'all') {
200
            $filesDirty = scandir($migrationFolderPath);
201
            for ($i=0; $i<count($filesDirty); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
202
                if (substr($filesDirty[$i], 0, 1) != '.') {
203
                    array_push($files, substr($filesDirty[$i], 0, -4));
204
                }
205
            }
206
            $filesFromDrive = array_diff($files, $migrationsFromBase);
207
            asort($files, SORT_NATURAL);
208
            $files = array_diff($filesFromDrive, $migrationsFromBase);
209
            asort($files, SORT_NATURAL);
210
            $upgradeAction = self::UPGRADE_KEY;
211
        } elseif (in_array($toMigration, $migrationsFromBase)) {
212
            $key = array_search($toMigration, $migrationsFromBase);
213
            $files = array_slice($migrationsFromBase, $key);
214
            rsort($files, SORT_NATURAL);
215
            $upgradeAction = self::DOWNGRADE_KEY;
216
        } else {
217
            $console->writeLine('Did not apply the migration: ' . $toMigration, Color::RED);
218
            return false;
219
        }
220
221
        if (!count($files)) {
222
            $console->writeLine('You have last version of database', Color::GREEN);
223
            return false;
224
        }
225
226
        foreach ($files as $migration) {
227
            $migrationPath = $migrationFolderPath .
228
                DIRECTORY_SEPARATOR . $migration . '.php';
229
230
            $migrationArray = $this->includeMigration($migrationPath);
231
232
            try {
233
                switch ($upgradeAction) {
234
                    case self::DOWNGRADE_KEY:
235
                        //downgrade action
236
                        $this->applyMigration(self::DOWNGRADE_KEY, $migration, $migrationArray, $percona, $port);
237
                        break;
238
                    case self::UPGRADE_KEY:
239
                        //upgrade action
240
                        $this->applyMigration(self::UPGRADE_KEY, $migration, $migrationArray, $percona, $port);
241
                        break;
242
                    default:
243
                        throw new \Exception('Not set action');
244
                        break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
245
                }
246
                continue;
247
            } catch (\Exception $err) {
248
                $console->writeLine('Current migration failed commit', Color::RED);
249
                $console->writeLine($err->getMessage(), Color::RED);
250
                return false;
251
            }
252
        }
253
    }
254
255
    /**
256
     * Show last applied migration number
257
     *
258
     */
259
    public function lastAction()
260
    {
261
        $console = $this->getServiceLocator()->get('console');
262
        if (!$console instanceof Console) {
263
            throw new RuntimeException('Cannot obtain console adapter. Are we running in a console?');
264
        }
265
266
        $request = $this->getRequest();
267
        $adapter = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
268
        $model = new Migration($adapter, $this->getServiceLocator());
0 ignored issues
show
Bug introduced by
The call to Migration::__construct() misses some required arguments starting with $percona.
Loading history...
Documentation introduced by
$adapter is of type object|array, but the function expects a object<Zend\Db\Adapter\Adapter>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
269
        $lastMigration = $model->last();
270
271
        $migrationName = $this->getMigrationFolder() . $lastMigration->last . '.php';
272
        if ($request->getParam('show')) {
273
            $console->writeLine('Last applied the migration: ' . $migrationName, Color::GREEN);
274
            $console->writeLine('=== Up SQL ===', Color::YELLOW);
275
            $console->writeLine($lastMigration->up, Color::GREEN);
276
            $console->writeLine('=== Down SQL ===', Color::YELLOW);
277
            $console->writeLine($lastMigration->down, Color::GREEN);
278
        } else {
279
            $console->writeLine('Last applied the migration: ' . $migrationName, Color::GREEN);
280
        }
281
    }
282
283
    /**
284
     * @param Console|null $console
285
     * @param Adapter|null $adapter
286
     * @return bool
287
     */
288
    protected function isApplySchema(Console $console = null, Adapter $adapter = null)
289
    {
290
        if ($console === null) {
291
            $console = $this->getServiceLocator()->get('console');
292
        }
293
        if ($adapter === null) {
294
            $adapter = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
295
        }
296
297
        $console->writeLine('Current DSN: ' . $adapter->getDriver()->getConnection()->getDsn(), Color::GREEN);
298
        $answer = Char::prompt('The schema is correct (Yes/No)? [y/n]', 'yn');
299
        if ($answer == 'n') {
300
            return false;
301
        }
302
        return true;
303
    }
304
305
    /**
306
     * Get migration folder from config file
307
     *
308
     * @return string
309
     */
310
    protected function getMigrationFolder()
311
    {
312
        if ($this->migrationFolder === null) {
313
            $config = $this->getServiceLocator()->get('config');
314
            $this->migrationFolder = getcwd() . '/' . $config['console-tools']['migration_folder'] . '/';
315
        }
316
317
        return $this->migrationFolder;
318
    }
319
320
    /**
321
     * @param $migrationPath
322
     * @return mixed
323
     */
324
    protected function includeMigration($migrationPath)
325
    {
326
        $migrationArray = include $migrationPath;
327
328
        return $migrationArray;
329
    }
330
}
331