Passed
Push — master ( 207765...57309d )
by Rutger
03:12
created

generateMigrations()   F

Complexity

Conditions 21
Paths 211

Size

Total Lines 102
Code Lines 64

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 462

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 64
c 2
b 0
f 1
dl 0
loc 102
ccs 0
cts 66
cp 0
rs 3.1958
cc 21
nc 211
nop 1
crap 462

How to fix   Long Method    Complexity   

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
namespace rhertogh\Yii2Oauth2Server\controllers\console\migrations\base;
4
5
use rhertogh\Yii2Oauth2Server\controllers\console\Oauth2MigrationsController;
6
use rhertogh\Yii2Oauth2Server\migrations\base\Oauth2BaseMigration;
7
use Yii;
8
use yii\base\Action;
9
use yii\base\InvalidConfigException;
10
use yii\console\controllers\BaseMigrateController;
11
use yii\console\ExitCode;
12
use yii\helpers\Console;
13
use yii\helpers\FileHelper;
14
use yii\helpers\StringHelper;
0 ignored issues
show
Coding Style introduced by
Header blocks must be separated by a single blank line
Loading history...
15
use function rhertogh\Yii2Oauth2Server\controllers\console\migrations\sort;
0 ignored issues
show
introduced by
The function rhertogh\Yii2Oauth2Serve...console\migrations\sort was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
16
17
/**
18
 * @property Oauth2MigrationsController $controller
19
 */
20
abstract class Oauth2BaseGenerateMigrationsAction extends Action
21
{
22
    /**
23
     * Template to use for the generated migrations.
24
     * @var string
25
     */
26
    public $templateFile = __DIR__ . DIRECTORY_SEPARATOR . 'generate' . DIRECTORY_SEPARATOR . 'migration.php';
27
28
    /**
29
     * @param class-string<Oauth2BaseMigration>[]|array<class-string<Oauth2BaseMigration>, array> $sourceMigrationClasses
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<Oauth2BaseM...2BaseMigration>, array> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<Oauth2BaseMigration>[]|array<class-string<Oauth2BaseMigration>, array>.
Loading history...
30
     * @return int
31
     * @throws InvalidConfigException
32
     * @throws \yii\base\Exception
33
     */
34
    protected function generateMigrations($sourceMigrationClasses)
35
    {
36
        $module = $this->controller->module;
37
        $migrationsNamespace = $module->migrationsNamespace;
38
39
        if (empty($migrationsNamespace)) {
40
            throw new InvalidConfigException('Oauth2Module::$migrationsNamespace must be set.');
41
        }
42
43
        $migrationsPath = $this->getNamespacePath($migrationsNamespace);
44
        $existingMigrations = $this->getExistingMigrations($migrationsPath);
45
46
        $generateMigrations = [];
47
        foreach ($sourceMigrationClasses as $sourceMigrationClass => $config) {
48
            if (is_int($sourceMigrationClass)) {
49
                $sourceMigrationClass = $config;
50
                $config = [];
51
            }
52
            $sourceMigrationName = StringHelper::basename($sourceMigrationClass);
53
            $wrapperName = $sourceMigrationName . 'Wrapper';
54
            /** @var string|Oauth2BaseMigration $sourceMigrationWrapper */
55
            $sourceMigrationWrapper = __NAMESPACE__ . '\\' . $wrapperName;
56
            if (!class_exists($sourceMigrationWrapper, false)) {
57
                eval(
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
58
                    'namespace ' . __NAMESPACE__ . ';'
59
                    . ' class ' . $wrapperName . ' extends \\' . $sourceMigrationClass . ' {}'
60
                );
61
            }
62
63
            if (
64
                $sourceMigrationWrapper::generationIsActive($module)
65
                && ($this->controller->force || !array_key_exists($sourceMigrationName, $existingMigrations))
66
            ) {
67
                if ($this->controller->force && array_key_exists($sourceMigrationName, $existingMigrations)) {
68
                    $generateClass = $migrationsNamespace . '\\' . $existingMigrations[$sourceMigrationName];
69
                } else {
70
                    $generateClass = $this->generateNewMigrationClassName($migrationsNamespace, $sourceMigrationName);
71
                }
72
73
                $file = $migrationsPath . DIRECTORY_SEPARATOR . StringHelper::basename($generateClass) . '.php';
74
                $content = $this->generateMigrationSourceCode([
75
                    'class' => $generateClass,
76
                    'sourceClass' => $sourceMigrationClass,
77
                    'config' => $config,
78
                ]);
79
80
                if (
81
                    !file_exists($file)
82
                    || file_get_contents($file) !== $content
83
                ) {
84
                    $generateMigrations[$file] = $content;
85
                }
86
            }
87
        }
88
89
        $applyInfo = $this->generateApplyInfo($migrationsNamespace);
90
91
        if (empty($generateMigrations)) {
92
            $this->controller->stdout(
93
                'No new to generate. However, they might still need to be applied.' . PHP_EOL . $applyInfo,
94
                Console::FG_GREEN
95
            );
96
97
            return ExitCode::OK;
98
        }
99
100
        $n = count($generateMigrations);
101
        $this->controller->stdout(
102
            "There " . ($n === 1 ? 'is' : 'are') . " $n " . ($n === 1 ? 'migration' : 'migrations') . ' to generate:' . PHP_EOL,
103
            Console::FG_YELLOW
104
        );
105
        foreach ($generateMigrations as $file => $content) {
106
            $this->controller->stdout("\t$file ");
107
            if (file_exists($file)) {
108
                $this->controller->stdout('[update]', Console::BG_YELLOW);
109
            } else {
110
                $this->controller->stdout('[new]', Console::BG_GREEN);
111
            }
112
            $this->controller->stdout( PHP_EOL);
113
        }
114
        $this->controller->stdout( PHP_EOL);
115
116
        if ($this->controller->confirm('Generate new migration?', true)) {
117
            FileHelper::createDirectory($migrationsPath);
118
            FileHelper::changeOwnership($migrationsPath, $module->migrationsFileOwnership);
119
120
            foreach ($generateMigrations as $file => $content) {
121
                if (!$this->writeFile($file, $content)) {
122
                    $this->controller->stdout("Failed to create new migration $file." . PHP_EOL, Console::FG_RED);
123
                    return ExitCode::IOERR;
124
                }
125
126
                FileHelper::changeOwnership($file, $module->migrationsFileOwnership, $module->migrationsFileMode);
127
            }
128
129
            $this->controller->stdout(
130
                "Successfully generated $n " . ($n === 1 ? 'migration' : 'migrations') . '.'  . PHP_EOL . $applyInfo,
131
                Console::FG_GREEN
132
            );
133
        }
134
135
        return ExitCode::OK;
136
    }
137
138
    protected function writeFile($file, $data)
139
    {
140
        return file_put_contents($file, $data, LOCK_EX) !== false;
141
    }
142
143
    protected function getNamespacePath($namespace)
144
    {
145
        return str_replace('/', DIRECTORY_SEPARATOR, Yii::getAlias('@' . str_replace('\\', '/', $namespace)));
146
    }
147
148
    protected function getExistingMigrations($migrationPath)
149
    {
150
        if (!file_exists($migrationPath)) {
151
            return [];
152
        }
153
154
        $migrations = [];
155
        $handle = opendir($migrationPath);
156
        while (($file = readdir($handle)) !== false) {
157
            if ($file === '.' || $file === '..') {
158
                continue;
159
            }
160
            $path = $migrationPath . DIRECTORY_SEPARATOR . $file;
161
            if (preg_match('/^(m\d{12}.*_(Oauth2_\d{5}_.+Migration).*?)\.php$/is', $file, $matches) && is_file($path)) {
162
                $migrations[$matches[2]] = $matches[1];
163
            }
164
        }
165
        closedir($handle);
166
167
        ksort($migrations);
168
169
        return $migrations;
170
    }
171
172
    protected function generateMigrationSourceCode($params)
173
    {
174
        return $this->controller->renderFile(Yii::getAlias($this->templateFile), $params);
0 ignored issues
show
Bug introduced by
It seems like Yii::getAlias($this->templateFile) can also be of type false; however, parameter $file of yii\base\Controller::renderFile() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

174
        return $this->controller->renderFile(/** @scrutinizer ignore-type */ Yii::getAlias($this->templateFile), $params);
Loading history...
175
    }
176
177
    /**
178
     * @param string $migrationsNamespace
179
     * @param string $sourceMigrationName
180
     * @return string
181
     */
182
    protected function generateNewMigrationClassName($migrationsNamespace, $sourceMigrationName)
183
    {
184
        return $migrationsNamespace
185
            . '\\' . 'M' . gmdate('ymdHis')
186
            . $this->controller->module->migrationsPrefix . '_' . $sourceMigrationName;
187
    }
188
189
    /**
190
     * @param string $migrationsNamespace
191
     * @return string
192
     */
193
    protected function generateApplyInfo($migrationsNamespace)
194
    {
195
        $migrateControllerId = 'migrate';
196
        $oauth2MigrationNameSpaceFound = false;
197
        foreach (Yii::$app->controllerMap as $controllerId => $controllerConfig) {
198
            if (
199
                !is_array($controllerConfig)
200
                || empty($controllerConfig['class'])
201
                || !is_a($controllerConfig['class'], BaseMigrateController::class, true)
202
            ) {
203
                continue;
204
            }
205
            $migrateControllerId = $controllerId;
206
            if (
207
                !empty($controllerConfig['migrationNamespaces'])
208
                && in_array($migrationsNamespace, $controllerConfig['migrationNamespaces'])
209
            ) {
210
                $oauth2MigrationNameSpaceFound = true;
211
                break;
212
            }
213
        }
214
215
        if (!$oauth2MigrationNameSpaceFound) {
0 ignored issues
show
introduced by
The condition $oauth2MigrationNameSpaceFound is always false.
Loading history...
216
            $applyInfo = 'Add the "' . addslashes($migrationsNamespace) . '" namespace to `$migrationNamespaces` of the'
217
                . ' migration controller'
218
                . ' (https://www.yiiframework.com/doc/guide/2.0/en/db-migrations#namespaced-migrations)'
219
                . ' and run ';
220
        } else {
221
            $applyInfo = 'Run ';
222
        }
223
        $applyInfo .= 'the`yii ' . $migrateControllerId . '/up` command to apply them.' . PHP_EOL;
224
225
        return $applyInfo;
226
    }
227
}
228