Passed
Pull Request — master (#58)
by Dmitriy
13:13 queued 10:22
created

DefaultController::preview()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 28
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 17
c 2
b 0
f 0
dl 0
loc 28
ccs 0
cts 16
cp 0
rs 9.0777
cc 6
nc 5
nop 2
crap 42
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
     */
95
    private function findReflectionParameter(string $name, array $constructorParameters): ReflectionParameter|null
96
    {
97
        foreach ($constructorParameters as $parameter) {
98
            if ($parameter->getName() === $name) {
99
                return $parameter;
100
            }
101
        }
102
        return null;
103
    }
104
105
    public function generate(
106
        GeneratorRequest $request,
107
        CodeFileWriter $codeFileWriter,
108
        CommandHydrator $commandHydrator
109
    ): ResponseInterface {
110
        $generator = $request->getGenerator();
111
        $command = $commandHydrator->hydrate($generator::getCommandClass(), $request->getBody());
112
        $answers = $request->getAnswers();
113
        try {
114
            $files = $generator->generate($command);
115
        } catch (InvalidGeneratorCommandException $e) {
116
            return $this->createErrorResponse($e);
117
        }
118
        $params = [];
119
        $results = [];
120
        // TODO: get answers from the request
121
        $answers = [];
122
        foreach ($files as $file) {
123
            $answers[$file->getId()] = true;
124
        }
125
        $params['hasError'] = !$codeFileWriter->write($command, $files, $answers, $results);
126
        $params['results'] = $results;
127
        return $this->responseFactory->createResponse($params);
128
    }
129
130
    public function preview(
131
        GeneratorRequest $request,
132
        CommandHydrator $commandHydrator,
133
        #[Query('file')] ?string $file = null
134
    ): ResponseInterface {
135
        $generator = $request->getGenerator();
136
        $command = $commandHydrator->hydrate($generator::getCommandClass(), $request->getBody());
137
138
        try {
139
            $files = $generator->generate($command);
140
        } catch (InvalidGeneratorCommandException $e) {
141
            return $this->createErrorResponse($e);
142
        }
143
        if ($file === null) {
144
            return $this->responseFactory->createResponse([
145
                'files' => array_map($this->serializeCodeFile(...), $files),
146
                // todo: fix showing operations' keys. they are skipped because of serialization numerical arrays
147
                'operations' => CodeFile::OPERATIONS_MAP,
148
            ]);
149
        }
150
151
        foreach ($files as $generatedFile) {
152
            if ($generatedFile->getId() === $file) {
153
                $content = $generatedFile->preview();
154
                return $this->responseFactory->createResponse(
155
                    ['content' => $content ?: 'Preview is not available for this file type.']
156
                );
157
            }
158
        }
159
160
        return $this->responseFactory->createResponse(
161
            ['message' => "Code file not found: $file"],
162
            Status::UNPROCESSABLE_ENTITY
163
        );
164
    }
165
166
    public function diff(
167
        GeneratorRequest $request,
168
        CommandHydrator $commandHydrator,
169
        #[Query('file')] string $file
170
    ): ResponseInterface {
171
        $generator = $request->getGenerator();
172
        $command = $commandHydrator->hydrate($generator::getCommandClass(), $request->getBody());
173
174
        try {
175
            $files = $generator->generate($command);
176
        } catch (InvalidGeneratorCommandException $e) {
177
            return $this->createErrorResponse($e);
178
        }
179
180
        foreach ($files as $generatedFile) {
181
            if ($generatedFile->getId() === $file) {
182
                return $this->responseFactory->createResponse(['diff' => $generatedFile->diff()]);
183
            }
184
        }
185
        return $this->responseFactory->createResponse(
186
            ['message' => "Code file not found: $file"],
187
            Status::UNPROCESSABLE_ENTITY
188
        );
189
    }
190
191
    private function createErrorResponse(InvalidGeneratorCommandException $e): DataResponse
192
    {
193
        return $this->responseFactory->createResponse(
194
        // TODO: fix
195
            ['errors' => $e->getResult()->getErrorMessagesIndexedByAttribute()],
196
            Status::UNPROCESSABLE_ENTITY
197
        );
198
    }
199
200
    private function serializeCodeFile(CodeFile $file): array
201
    {
202
        return [
203
            'id' => $file->getId(),
204
            'content' => $file->getContent(),
205
            'operation' => $file->getOperation(),
206
            'path' => $file->getPath(),
207
            'relativePath' => $file->getRelativePath(),
208
            'type' => $file->getType(),
209
            'preview' => $file->preview(),
210
        ];
211
    }
212
}
213