Passed
Pull Request — master (#58)
by Dmitriy
02:31
created

DefaultController::generate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 14
c 0
b 0
f 0
dl 0
loc 19
ccs 0
cts 14
cp 0
rs 9.7998
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Gii\Controller;
6
7
use Psr\Http\Message\ResponseInterface;
8
use ReflectionClass;
9
use ReflectionParameter;
10
use Yiisoft\DataResponse\DataResponse;
11
use Yiisoft\DataResponse\DataResponseFactoryInterface;
12
use Yiisoft\Http\Status;
13
use Yiisoft\RequestModel\Attribute\Query;
14
use Yiisoft\Validator\RulesDumper;
15
use Yiisoft\Validator\RulesProvider\AttributesRulesProvider;
16
use Yiisoft\Yii\Gii\CodeFile;
17
use Yiisoft\Yii\Gii\CodeFileWriter;
18
use Yiisoft\Yii\Gii\Exception\InvalidGeneratorCommandException;
19
use Yiisoft\Yii\Gii\Generator\CommandHydrator;
20
use Yiisoft\Yii\Gii\GeneratorCommandInterface;
21
use Yiisoft\Yii\Gii\GeneratorInterface;
22
use Yiisoft\Yii\Gii\GiiInterface;
23
use Yiisoft\Yii\Gii\Request\GeneratorRequest;
24
25
final class DefaultController
26
{
27
    public function __construct(private DataResponseFactoryInterface $responseFactory)
28
    {
29
    }
30
31
    public function list(GiiInterface $gii): ResponseInterface
32
    {
33
        $generators = $gii->getGenerators();
34
35
        return $this->responseFactory->createResponse([
36
            'generators' => array_map($this->serializeGenerator(...), array_values($generators)),
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected ')' on line 36 at column 67
Loading history...
37
        ]);
38
    }
39
40
    private function serializeGenerator(GeneratorInterface $generator): array
41
    {
42
        /**
43
         * @psalm-var $commandClass class-string<GeneratorCommandInterface>
44
         */
45
        $commandClass = $generator::getCommandClass();
46
47
        $dataset = new AttributesRulesProvider($commandClass);
48
        $rules = $dataset->getRules();
49
        $dumpedRules = (new RulesDumper())->asArray($rules);
50
        $attributes = $commandClass::getAttributes();
51
        $hints = $commandClass::getHints();
52
        $labels = $commandClass::getAttributeLabels();
53
54
        $reflection = new ReflectionClass($commandClass);
55
        $constructorParameters = $reflection->getConstructor()->getParameters();
56
57
        $attributesResult = [];
58
        foreach ($attributes as $attributeName) {
59
            $reflectionProperty = $reflection->getProperty($attributeName);
60
            $defaultValue = $reflectionProperty->hasDefaultValue()
61
                ? $reflectionProperty->getDefaultValue()
62
                : $this->findReflectionParameter($attributeName, $constructorParameters)?->getDefaultValue();
63
            $attributesResult[$attributeName] = [
64
                'defaultValue' => $defaultValue,
65
                'hint' => $hints[$attributeName] ?? null,
66
                'label' => $labels[$attributeName] ?? null,
67
                'rules' => $dumpedRules[$attributeName] ?? [],
68
            ];
69
        }
70
71
        return [
72
            'id' => $generator::getId(),
73
            'name' => $generator::getName(),
74
            'description' => $generator::getDescription(),
75
            'commandClass' => $commandClass,
76
            'attributes' => $attributesResult,
77
            //            'templatePath' => $generator->getTemplatePath(),
78
            //            'templates' => $generator->getTemplates(),
79
            'directory' => $generator->getDirectory(),
80
        ];
81
    }
82
83
    public function get(GeneratorRequest $request): ResponseInterface
84
    {
85
        $generator = $request->getGenerator();
86
87
        return $this->responseFactory->createResponse(
88
            $this->serializeGenerator($generator)
89
        );
90
    }
91
92
    /**
93
     * @param ReflectionParameter[] $constructorParameters
94
     * @return void
95
     */
96
    private function findReflectionParameter(string $name, array $constructorParameters): ReflectionParameter|null
97
    {
98
        foreach ($constructorParameters as $parameter) {
99
            if ($parameter->getName() === $name) {
100
                return $parameter;
101
            }
102
        }
103
        return null;
104
    }
105
106
    public function generate(
107
        GeneratorRequest $request,
108
        CodeFileWriter $codeFileWriter,
109
        CommandHydrator $commandHydrator
110
    ): ResponseInterface {
111
        $generator = $request->getGenerator();
112
        $command = $commandHydrator->hydrate($generator::getCommandClass(), $request->getBody());
113
        $answers = $request->getAnswers();
114
        try {
115
            $files = $generator->generate($command);
116
        } catch (InvalidGeneratorCommandException $e) {
117
            return $this->createErrorResponse($e);
118
        }
119
        $params = [];
120
        $results = [];
121
        // TODO: get answers from the request
122
        $answers = [];
123
        foreach ($files as $file) {
124
            $answers[$file->getId()] = true;
125
        }
126
        $params['hasError'] = !$codeFileWriter->write($command, $files, $answers, $results);
127
        $params['results'] = $results;
128
        return $this->responseFactory->createResponse($params);
129
    }
130
131
    public function preview(
132
        GeneratorRequest $request,
133
        CommandHydrator $commandHydrator,
134
        #[Query('file')] ?string $file = null
135
    ): ResponseInterface {
136
        $generator = $request->getGenerator();
137
        $command = $commandHydrator->hydrate($generator::getCommandClass(), $request->getBody());
138
139
        try {
140
            $files = $generator->generate($command);
141
        } catch (InvalidGeneratorCommandException $e) {
142
            return $this->createErrorResponse($e);
143
        }
144
        if ($file === null) {
145
            return $this->responseFactory->createResponse([
146
                'files' => array_map($this->serializeCodeFile(...), $files),
147
                // todo: fix showing operations' keys. they are skipped because of serialization numerical arrays
148
                'operations' => CodeFile::OPERATIONS_MAP,
149
            ]);
150
        }
151
152
        foreach ($files as $generatedFile) {
153
            if ($generatedFile->getId() === $file) {
154
                $content = $generatedFile->preview();
155
                return $this->responseFactory->createResponse(
156
                    ['content' => $content ?: 'Preview is not available for this file type.']
157
                );
158
            }
159
        }
160
161
        return $this->responseFactory->createResponse(
162
            ['message' => "Code file not found: $file"],
163
            Status::UNPROCESSABLE_ENTITY
164
        );
165
    }
166
167
    public function diff(
168
        GeneratorRequest $request,
169
        CommandHydrator $commandHydrator,
170
        #[Query('file')] string $file
171
    ): ResponseInterface {
172
        $generator = $request->getGenerator();
173
        $command = $commandHydrator->hydrate($generator::getCommandClass(), $request->getBody());
174
175
        try {
176
            $files = $generator->generate($command);
177
        } catch (InvalidGeneratorCommandException $e) {
178
            return $this->createErrorResponse($e);
179
        }
180
181
        foreach ($files as $generatedFile) {
182
            if ($generatedFile->getId() === $file) {
183
                return $this->responseFactory->createResponse(['diff' => $generatedFile->diff()]);
184
            }
185
        }
186
        return $this->responseFactory->createResponse(
187
            ['message' => "Code file not found: $file"],
188
            Status::UNPROCESSABLE_ENTITY
189
        );
190
    }
191
192
    private function createErrorResponse(InvalidGeneratorCommandException $e): DataResponse
193
    {
194
        return $this->responseFactory->createResponse(
195
        // TODO: fix
196
            ['errors' => $e->getResult()->getErrorMessagesIndexedByAttribute()],
197
            Status::UNPROCESSABLE_ENTITY
198
        );
199
    }
200
201
    private function serializeCodeFile(CodeFile $file): array
202
    {
203
        return [
204
            'id' => $file->getId(),
205
            'content' => $file->getContent(),
206
            'operation' => $file->getOperation(),
207
            'path' => $file->getPath(),
208
            'relativePath' => $file->getRelativePath(),
209
            'type' => $file->getType(),
210
            'preview' => $file->preview(),
211
        ];
212
    }
213
}
214