Passed
Push — master ( 8edd7c...9d0a3d )
by Dawid
03:01
created

DataCollector::extractRoutesData()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4.0058

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 22
ccs 13
cts 14
cp 0.9286
rs 8.9197
cc 4
eloc 13
nc 4
nop 0
crap 4.0058
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spiechu\SymfonyCommonsBundle\Service;
6
7
use Doctrine\Common\Annotations\Reader;
8
use Spiechu\SymfonyCommonsBundle\Annotation\Controller\ControllerAnnotationExtractorTrait;
9
use Spiechu\SymfonyCommonsBundle\Annotation\Controller\ResponseSchemaValidator;
10
use Spiechu\SymfonyCommonsBundle\Event\ApiVersion\ApiVersionSetEvent;
11
use Spiechu\SymfonyCommonsBundle\Event\ApiVersion\Events as ApiVersionEvents;
12
use Spiechu\SymfonyCommonsBundle\Event\ResponseSchemaCheck\CheckResult;
13
use Spiechu\SymfonyCommonsBundle\Event\ResponseSchemaCheck\Events as ResponseSchemaCheckEvents;
14
use Spiechu\SymfonyCommonsBundle\EventListener\RequestSchemaValidatorListener;
15
use Spiechu\SymfonyCommonsBundle\Service\SchemaValidator\ValidationViolation;
16
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpFoundation\Response;
19
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
20
use Symfony\Component\HttpKernel\DataCollector\DataCollector as BaseDataCollector;
21
use Symfony\Component\Routing\RouterInterface;
22
23
class DataCollector extends BaseDataCollector implements EventSubscriberInterface
24
{
25
    use ControllerAnnotationExtractorTrait;
26
27
    public const COLLECTOR_NAME = 'spiechu_symfony_commons.data_collector';
28
29
    /**
30
     * @var RouterInterface
31
     */
32
    protected $router;
33
34
    /**
35
     * @var Reader
36
     */
37
    protected $reader;
38
39
    /**
40
     * @var ControllerResolverInterface
41
     */
42
    protected $controllerResolver;
43
44
    /**
45
     * @param RouterInterface $router
46
     * @param Reader $reader
47
     * @param ControllerResolverInterface $controllerResolver
48
     */
49 12
    public function __construct(
50
        RouterInterface $router,
51
        Reader $reader,
52
        ControllerResolverInterface $controllerResolver
53
    ) {
54 12
        $this->router = $router;
55 12
        $this->reader = $reader;
56 12
        $this->controllerResolver = $controllerResolver;
57 12
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62 12
    public function collect(Request $request, Response $response, \Exception $exception = null): void
63
    {
64 12
        $this->data['known_response_schemas'] = $request->attributes->has(RequestSchemaValidatorListener::ATTRIBUTE_RESPONSE_SCHEMAS)
65 2
            ? $request->attributes->get(RequestSchemaValidatorListener::ATTRIBUTE_RESPONSE_SCHEMAS)
66 10
            : null;
67
68 12
        $this->extractRoutesData();
69 12
    }
70
71
    /**
72
     * {@inheritdoc}
73
     */
74 12
    public function getName(): string
75
    {
76 12
        return static::COLLECTOR_NAME;
77
    }
78
79
    /**
80
     * Forward compatibility with Symfony 3.4.
81
     */
82
    public function reset(): void
83
    {
84
        $this->data = [];
85
    }
86
87
    /**
88
     * @return array
89
     */
90
    public function getGlobalResponseSchemas(): array
91
    {
92
        return $this->data['global_response_schemas'];
93
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98 6
    public static function getSubscribedEvents(): array
99
    {
100
        return [
101 6
            ResponseSchemaCheckEvents::CHECK_RESULT => ['onCheckResult', 100],
102 6
            ApiVersionEvents::API_VERSION_SET => ['onApiVersionSet', 100],
103
        ];
104
    }
105
106
    /**
107
     * @param CheckResult $checkResult
108
     */
109 2
    public function onCheckResult(CheckResult $checkResult): void
110
    {
111 2
        $this->data['validation_result'] = $checkResult->getValidationResult();
112 2
    }
113
114
    /**
115
     * @param ApiVersionSetEvent $apiVersionSetEvent
116
     */
117 9
    public function onApiVersionSet(ApiVersionSetEvent $apiVersionSetEvent): void
118
    {
119 9
        $this->data['api_version_set'] = $apiVersionSetEvent->getApiVersion();
120 9
    }
121
122
    /**
123
     * @return array
124
     */
125
    public function getKnownResponseSchemas(): array
126
    {
127
        return empty($this->data['known_response_schemas']) ? [] : $this->data['known_response_schemas'];
128
    }
129
130
    /**
131
     * @return int
132
     */
133
    public function getKnownResponseSchemaNumber(): int
134
    {
135
        $counter = 0;
136
137
        foreach ($this->getKnownResponseSchemas() as $format) {
138
            $counter += \count($format);
139
        }
140
141
        return $counter;
142
    }
143
144
    /**
145
     * @return bool
146
     */
147 2
    public function responseWasChecked(): bool
148
    {
149 2
        return array_key_exists('validation_result', $this->data);
150
    }
151
152
    /**
153
     * @return bool
154
     */
155 5
    public function apiVersionWasSet(): bool
156
    {
157 5
        return array_key_exists('api_version_set', $this->data);
158
    }
159
160
    /**
161
     * @return null|string
162
     */
163 5
    public function getApiVersion(): ?string
164
    {
165 5
        return $this->apiVersionWasSet() ? $this->data['api_version_set'] : null;
166
    }
167
168
    /**
169
     * @return ValidationViolation[]
170
     */
171
    public function getValidationErrors(): array
172
    {
173
        if (!$this->responseWasChecked()) {
174
            return [];
175
        }
176
177
        return $this->data['validation_result']->getViolations();
178
    }
179
180 12
    protected function extractRoutesData(): void
181
    {
182 12
        $this->data['global_response_schemas'] = [];
183
184 12
        foreach ($this->router->getRouteCollection() as $name => $route) {
185 12
            if (empty($controllerDefinition = $route->getDefault('_controller'))) {
186
                continue;
187
            }
188
189 12
            $methodAnnotation = $this->extractControllerResponseValidator($controllerDefinition);
190 12
            if (!$methodAnnotation instanceof ResponseSchemaValidator) {
191 12
                continue;
192
            }
193
194 11
            $this->data['global_response_schemas'][] = [
195 11
                'path' => $route->getPath(),
196 11
                'name' => $name,
197 11
                'controller' => $controllerDefinition,
198 11
                'response_schemas' => $methodAnnotation->getSchemas(),
199
            ];
200
        }
201 12
    }
202
203
    /**
204
     * @param string $controllerDefinition
205
     *
206
     * @throws \Exception
207
     *
208
     * @return null|ResponseSchemaValidator
209
     */
210 12
    protected function extractControllerResponseValidator(string $controllerDefinition): ?ResponseSchemaValidator
211
    {
212 12
        $resolvedController = $this->controllerResolver->getController(new Request(
213 12
            [],
214 12
            [],
215
            [
216 12
                '_controller' => $controllerDefinition,
217
            ]
218
        ));
219
220 12
        if (!\is_callable($resolvedController)) {
221
            return null;
222
        }
223
224 12
        return $this->getMethodAnnotationFromController($resolvedController, ResponseSchemaValidator::class);
225
    }
226
227
    /**
228
     * {@inheritdoc}
229
     */
230 12
    protected function getAnnotationReader(): Reader
231
    {
232 12
        return $this->reader;
233
    }
234
}
235