Test Failed
Pull Request — master (#58)
by Alexander
05:19 queued 02:39
created

BaseGenerateCommand::generateCode()   C

Complexity

Conditions 15
Paths 65

Size

Total Lines 81
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 240

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 55
c 1
b 1
f 0
dl 0
loc 81
rs 5.9166
ccs 0
cts 38
cp 0
cc 15
nc 65
nop 4
crap 240

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
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Gii\Command;
6
7
use ReflectionException;
8
use Symfony\Component\Console\Command\Command;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Command\Command was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use Symfony\Component\Console\Input\InputArgument;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Output\OutputInterface;
12
use Symfony\Component\Console\Question\ChoiceQuestion;
13
use Symfony\Component\Console\Question\ConfirmationQuestion;
14
use Yiisoft\Validator\Result;
15
use Yiisoft\Yii\Console\ExitCode;
16
use Yiisoft\Yii\Gii\CodeFile;
17
use Yiisoft\Yii\Gii\CodeFileWriteOperationEnum;
18
use Yiisoft\Yii\Gii\CodeFileWriter;
19
use Yiisoft\Yii\Gii\CodeFileWriteStatusEnum;
20
use Yiisoft\Yii\Gii\Exception\InvalidConfigException;
21
use Yiisoft\Yii\Gii\Exception\InvalidGeneratorCommandException;
22
use Yiisoft\Yii\Gii\Generator\AbstractGeneratorCommand;
23
use Yiisoft\Yii\Gii\GeneratorInterface;
24
use Yiisoft\Yii\Gii\GiiInterface;
25
26
use function count;
27
28
abstract class BaseGenerateCommand extends Command
29
{
30
    public function __construct(
31
        protected GiiInterface $gii,
32
        protected CodeFileWriter $codeFileWriter,
33
    ) {
34
        parent::__construct();
35
    }
36
37
    protected function configure(): void
38
    {
39
        $this->addOption('overwrite', 'o', InputArgument::OPTIONAL, '')
40
            ->addOption('template', 't', InputArgument::OPTIONAL, '');
41
    }
42
43
    protected function execute(InputInterface $input, OutputInterface $output): int
44
    {
45
        /** @var GeneratorInterface $generator */
46
        $generator = $this->getGenerator();
47
        $generatorCommand = $this->createGeneratorCommand($input);
48
49
        $output->writeln("Running '{$generator->getName()}'...\n");
50
        try {
51
            $files = $generator->generate($generatorCommand);
52
        } catch (InvalidGeneratorCommandException $e) {
53
            $this->displayValidationErrors($e->getResult(), $output);
54
            return ExitCode::UNSPECIFIED_ERROR;
55
        }
56
        $this->generateCode($files, $generatorCommand, $input, $output);
57
        return ExitCode::OK;
58
    }
59
60
    abstract protected function getGenerator(): GeneratorInterface;
61
62
    protected function displayValidationErrors(Result $result, OutputInterface $output): void
63
    {
64
        $output->writeln("<fg=red>Code not generated. Please fix the following errors:</>\n");
65
        foreach ($result->getErrorMessages() as $attribute => $errorMessage) {
66
            $output->writeln(sprintf(' - <fg=cyan>%s</>: <fg=green>%s</>', $attribute, $errorMessage));
67
        }
68
        $output->writeln('');
69
    }
70
71
    /**
72
     * @param CodeFile[] $files
73
     * @param AbstractGeneratorCommand $generatorCommand
74
     * @param InputInterface $input
75
     * @param OutputInterface $output
76
     *
77
     * @throws ReflectionException
78
     * @throws InvalidConfigException
79
     */
80
    protected function generateCode(
81
        array $files,
82
        AbstractGeneratorCommand $generatorCommand,
83
        InputInterface $input,
84
        OutputInterface $output
85
    ): void {
86
        if (count($files) === 0) {
87
            $output->writeln('<fg=cyan>No code to be generated.</>');
88
            return;
89
        }
90
        $output->writeln("<fg=magenta>The following files will be generated</>:\n");
91
        $skipAll = $input->isInteractive() ? null : !$input->getArgument('overwrite');
92
        $answers = [];
93
        foreach ($files as $file) {
94
            $path = $file->getRelativePath();
95
            if ($file->getOperation() === CodeFileWriteOperationEnum::OP_CREATE) {
96
                $output->writeln("    <fg=green>[new]</>       <fg=blue>$path</>");
97
                $answers[$file->getId()] = $file->getOperation()->value;
98
            } elseif ($file->getOperation() === CodeFileWriteOperationEnum::OP_SKIP) {
99
                $output->writeln("    <fg=green>[unchanged]</> <fg=blue>$path</>");
100
                $answers[$file->getId()] = $file->getOperation()->value;
101
            } else {
102
                $output->writeln("    <fg=green>[changed]</>   <fg=blue>$path</>");
103
                if ($skipAll !== null) {
104
                    $answers[$file->getId()] = CodeFileWriteOperationEnum::OP_OVERWRITE->value;
105
                } else {
106
                    $answer = $this->choice($input, $output);
107
                    $answers[$file->getId()] = ($answer === 'y' || $answer === 'ya')
108
                        ? CodeFileWriteOperationEnum::OP_OVERWRITE->value
109
                        : CodeFileWriteOperationEnum::OP_SKIP->value;
110
                    if ($answer === 'ya') {
111
                        $skipAll = false;
112
                    } elseif ($answer === 'na') {
113
                        $skipAll = true;
114
                    }
115
                }
116
            }
117
        }
118
119
//        if (!array_sum($answers)) {
120
//            $output->writeln("\n<fg=cyan>No files were chosen to be generated.</>");
121
//            return;
122
//        }
123
124
        if (!$this->confirm($input, $output)) {
125
            $output->writeln("\n<fg=cyan>No file was generated.</>");
126
            return;
127
        }
128
129
        $result = $this->codeFileWriter->write($files, $answers);
130
131
        $hasError = false;
132
        foreach ($result->getResults() as $fileId => $result) {
133
            $file = $files[$fileId];
134
            $color = match ($result['status']) {
135
                CodeFileWriteStatusEnum::CREATED->value => 'green',
136
                CodeFileWriteStatusEnum::OVERWROTE->value => 'blue',
137
                CodeFileWriteStatusEnum::ERROR->value => 'red',
138
                default => 'yellow',
139
            };
140
            $output->writeln(sprintf(
141
                '<fg=%s>%s</>: %s',
142
                $color,
143
                $result['status'],
144
                $file->getRelativePath(),
145
            ));
146
            if (CodeFileWriteStatusEnum::ERROR->value === $result['status']) {
147
                var_dump($result);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($result) looks like debug code. Are you sure you do not want to remove it?
Loading history...
148
                exit();
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...
149
                $hasError = true;
0 ignored issues
show
Unused Code introduced by
$hasError = true is not 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...
150
                $output->writeln(sprintf(
151
                    '<fg=red>%s</>',
152
                    $result['error']
153
                ));
154
            }
155
        }
156
157
        if ($hasError) {
0 ignored issues
show
introduced by
The condition $hasError is always false.
Loading history...
158
            $output->writeln("\n<fg=red>Some errors occurred while generating the files.</>");
159
        } else {
160
            $output->writeln("\n<fg=green>Files were generated successfully!</>");
161
        }
162
    }
163
164
    abstract protected function createGeneratorCommand(InputInterface $input): AbstractGeneratorCommand;
165
166
    /**
167
     * @return bool|mixed|string|null
168
     */
169
    protected function confirm(InputInterface $input, OutputInterface $output)
170
    {
171
        $question = new ConfirmationQuestion("\nReady to generate the selected files? (yes|no) [yes]:", true);
172
        return $this->getHelper('question')->ask($input, $output, $question);
173
    }
174
175
    /**
176
     * @return bool|mixed|string|null
177
     */
178
    protected function choice(InputInterface $input, OutputInterface $output)
179
    {
180
        $question = new ChoiceQuestion(
181
            "\nDo you want to overwrite this file?",
182
            [
183
                'y' => 'Overwrite this file.',
184
                'n' => 'Skip this file.',
185
                'ya' => 'Overwrite this and the rest of the changed files.',
186
                'na' => 'Skip this and the rest of the changed files.',
187
            ]
188
        );
189
        return $this->getHelper('question')->ask($input, $output, $question);
190
    }
191
}
192