GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 642c1a...b5d278 )
by Sergey
12s
created

JsonApiService::parseQuery()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 9
cts 9
cp 1
rs 9.7666
c 0
b 0
f 0
cc 3
nc 3
nop 2
crap 3
1
<?php
2
/*
3
 * This file is part of the reva2/jsonapi.
4
 *
5
 * (c) Sergey Revenko <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Reva2\JsonApi\Services;
12
13
use Doctrine\Common\Proxy\Exception\InvalidArgumentException;
14
use Neomerx\JsonApi\Contracts\Codec\CodecMatcherInterface;
15
use Neomerx\JsonApi\Contracts\Schema\ContainerInterface;
16
use Neomerx\JsonApi\Document\Error;
17
use Neomerx\JsonApi\Exceptions\JsonApiException;
18
use Reva2\JsonApi\Contracts\Decoders\DataParserInterface;
19
use Reva2\JsonApi\Contracts\Decoders\DecoderInterface;
20
use Reva2\JsonApi\Contracts\Factories\FactoryInterface;
21
use Reva2\JsonApi\Contracts\Http\Query\QueryParametersParserInterface;
22
use Reva2\JsonApi\Contracts\Http\RequestInterface;
23
use Reva2\JsonApi\Contracts\Services\EnvironmentInterface;
24
use Reva2\JsonApi\Contracts\Services\JsonApiRegistryInterface;
25
use Reva2\JsonApi\Contracts\Services\JsonApiServiceInterface;
26
use Reva2\JsonApi\Contracts\Services\ValidationServiceInterface;
27
use Reva2\JsonApi\Http\ResponseFactory;
28
use Symfony\Component\HttpFoundation\Request;
29
use Neomerx\JsonApi\Http\Request as Psr7Request;
30
31
/**
32
 * Service for JSON API requests processing
33
 *
34
 * @package Reva2\JsonApi\Services
35
 * @author Sergey Revenko <[email protected]>
36
 */
37
class JsonApiService implements JsonApiServiceInterface
38
{
39
    /**
40
     * @var FactoryInterface
41
     */
42
    protected $factory;
43
44
    /**
45
     * @var JsonApiRegistryInterface
46
     */
47
    protected $registry;
48
49
    /**
50
     * @var ContainerInterface
51
     */
52
    protected $schemas;
53
54
    /**
55
     * @var ValidationServiceInterface
56
     */
57
    protected $validator;
58
59
    /**
60
     * @var DataParserInterface
61
     */
62
    protected $parser;
63
64
    /**
65
     * Constructor
66
     *
67
     * @param FactoryInterface $factory
68
     * @param JsonApiRegistryInterface $registry
69
     * @param ContainerInterface $schemas
70
     * @param DataParserInterface $parser
71
     * @param ValidationServiceInterface $validator
72
     */
73 6
    public function __construct(
74
        FactoryInterface $factory,
75
        JsonApiRegistryInterface $registry,
76
        ContainerInterface $schemas,
77
        DataParserInterface $parser,
78
        ValidationServiceInterface $validator
79
    ) {
80 6
        $this->factory = $factory;
81 6
        $this->registry = $registry;
82 6
        $this->parser = $parser;
83 6
        $this->schemas = $schemas;
84 6
        $this->validator = $validator;
85 6
    }
86
87
    /**
88
     * @inheritdoc
89
     */
90
    public function getFactory()
91
    {
92
        return $this->factory;
93
    }
94
95
    /**
96
     * @inheritdoc
97
     */
98 6
    public function parseRequest(Request $request, EnvironmentInterface $environment = null)
99
    {
100 6
        if (null === $environment) {
101 6
            $environment = $this->getRequestEnvironment($request);
102 4
        }
103
104 4
        $this->initializeEnvironment($environment, $request);
105
106 3
        $prevGroups = $this->parser->getSerializationGroups();
107
108 3
        $this->parser->setSerializationGroups($environment->getSerializationGroups());
109
110 3
        $apiRequest = $this->factory->createRequest($environment);
111
        $apiRequest
112 3
            ->setQuery($this->parseQuery($request, $environment))
113 3
            ->setBody($this->parseBody($request, $environment));
114
115 3
        $this->parser->setSerializationGroups($prevGroups);
116
117 3
        if (null !== $environment->getValidationGroups()) {
118 2
            $this->validateRequest($apiRequest);
119 2
        }
120
121 3
        return $apiRequest;
122
    }
123
124
    /**
125
     * @inheritdoc
126
     */
127 2
    public function validateRequest(RequestInterface $request)
128
    {
129 2
        $validationGroups = $request->getEnvironment()->getValidationGroups();
130 2
        if (is_bool($validationGroups)) {
131
            if (false === $validationGroups) {
132
                return;
133
            } else {
134
                $validationGroups = null;
135
            }
136
        }
137
138 2
        $errors = $this->validateData($request->getQuery(), $validationGroups);
139 2
        $errors = array_merge($errors, $this->validateData($request->getBody(), $validationGroups));
140
141 2
        if (0 === count($errors)) {
142 2
            return;
143
        }
144
145
        $code = null;
146
        foreach ($errors as $error) {
147
            /* @var $error Error */
148
            if (null === $code) {
149
                $code = $error->getStatus();
150
            } elseif ($code !== $error->getStatus()) {
151
                $code = 400;
152
                break;
153
            }
154
        }
155
156
        throw new JsonApiException($errors, $code);
157
    }
158
159
    /**
160
     * @inheritdoc
161
     */
162 1
    public function getResponseFactory(RequestInterface $request)
163
    {
164 1
        return new ResponseFactory($this->schemas, $request->getEnvironment(), $request->getQuery());
165
    }
166
167
    /**
168
     * Returns JSON API environment configured in request
169
     *
170
     * @param Request $request
171
     * @return EnvironmentInterface
172
     */
173 6
    public function getRequestEnvironment(Request $request)
174
    {
175 6
        if (false === $request->attributes->has('_jsonapi')) {
176 1
            throw new \RuntimeException('JSON API environment is not provided');
177
        }
178
179 5
        $environment = $request->attributes->get('_jsonapi');
180 5
        if (!$environment instanceof EnvironmentInterface) {
181 1
            throw new \InvalidArgumentException(sprintf(
182 1
                "JSON API environment should implement %s interface",
183
                EnvironmentInterface::class
184 1
            ));
185
        }
186
187 4
        return $environment;
188
    }
189
190
    /**
191
     * Initialize JSON API environment for specified request
192
     *
193
     * @param EnvironmentInterface $environment
194
     * @param Request $request
195
     */
196 4
    private function initializeEnvironment(EnvironmentInterface $environment, Request $request)
197
    {
198 4
        $matcher = $this->createMatcher($environment);
199
200 3
        $this->parseRequestHeaders($request, $matcher);
201
202
        $environment
203 3
            ->setDecoder($matcher->getDecoder())
204 3
            ->setEncoder($matcher->getEncoder())
205 3
            ->setEncoderMediaType($matcher->getEncoderRegisteredMatchedType());
206 3
    }
207
208
    /**
209
     * Create codec matcher for specified environment
210
     *
211
     * @param EnvironmentInterface $environment
212
     * @return \Neomerx\JsonApi\Contracts\Codec\CodecMatcherInterface
213
     */
214 4
    private function createMatcher(EnvironmentInterface $environment)
215
    {
216 4
        $matcher = $this->factory->createCodecMatcher();
217
218 4
        $config = $environment->getMatcherConfiguration();
219 4
        if ((array_key_exists('decoders', $config)) && (is_array($config['decoders']))) {
220 4
            $this->registerDecoders($config['decoders'], $matcher);
221 3
        }
222
223 3
        if ((array_key_exists('encoders', $config)) && (is_array($config['encoders']))) {
224 3
            $this->registerEncoders($config['encoders'], $matcher);
225 3
        }
226
227 3
        return $matcher;
228
    }
229
230
    /**
231
     * Convert media type string to media type object
232
     *
233
     * @param string $type
234
     * @return \Neomerx\JsonApi\Contracts\Http\Headers\MediaTypeInterface
235
     */
236 4
    private function parseMediaTypeString($type)
237
    {
238 4
        $parts = explode('/', $type);
239 4
        if (2 !== count($parts)) {
240 1
            throw new InvalidArgumentException(sprintf("Invalid media type '%s' specified", $type));
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\Common\Proxy\Ex...nvalidArgumentException has been deprecated with message: The Doctrine\Common\Proxy component is deprecated, please use ocramius/proxy-manager instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
241
        }
242
243 3
        return $this->factory->createMediaType($parts[0], $parts[1]);
244
    }
245
246
    /**
247
     * Parse request headers and detect appropriate decoder and encoder
248
     *
249
     * @param Request $request
250
     * @param CodecMatcherInterface $matcher
251
     */
252 3
    private function parseRequestHeaders(Request $request, CodecMatcherInterface $matcher)
253
    {
254 3
        $psr7Request = $this->createPsr7Request($request);
255 3
        $headers = $this->factory->createHeaderParametersParser()->parse($psr7Request);
256 3
        $checker = $this->factory->createHeadersChecker($matcher);
257
258 3
        $checker->checkHeaders($headers);
259 3
    }
260
261
    /**
262
     * Create PSR7 request from symfony http foundation request
263
     *
264
     * @param Request $request
265
     * @return Psr7Request
266
     */
267 3
    private function createPsr7Request(Request $request)
268 1
    {
269 3
        return new Psr7Request(
270
            function () use ($request) {
271 3
                return $request->getMethod();
272 3
            },
273
            function ($name) use ($request) {
274 3
                $header = $request->headers->get($name);
275 3
                if (!is_array($header)) {
276 3
                    $header = array($header);
277 3
                }
278
279 3
                return $header;
280 3
            },
281 2
            function () use ($request) {
282 2
                return $request->query->all();
283
            }
284 3
        );
285
    }
286
287
    /**
288
     * Parse request query parameters
289
     *
290
     * @param Request $request
291
     * @param EnvironmentInterface $environment
292
     * @return \Neomerx\JsonApi\Contracts\Encoder\Parameters\EncodingParametersInterface|null
293
     */
294 3
    private function parseQuery(Request $request, EnvironmentInterface $environment)
295
    {
296 3
        if (null === $environment->getQueryType()) {
297 1
            return null;
298
        }
299
300 2
        $queryParser = $this->factory->createQueryParametersParser();
301 2
        if ($queryParser instanceof QueryParametersParserInterface) {
302
            $queryParser
303 2
                ->setDataParser($this->parser)
304 2
                ->setQueryType($environment->getQueryType());
305 2
        }
306
307 2
        return $queryParser->parse($this->createPsr7Request($request));
308
    }
309
310
    /**
311
     * Parse request body
312
     *
313
     * @param Request $request
314
     * @param EnvironmentInterface $environment
315
     * @return mixed|null
316
     */
317 3
    private function parseBody(Request $request, EnvironmentInterface $environment)
318
    {
319 3
        if (null === $environment->getBodyType()) {
320 2
            return null;
321
        }
322
323 1
        $decoder = $environment->getDecoder();
324 1
        if ($decoder instanceof DecoderInterface) {
325 1
            $decoder->setContentType($environment->getBodyType());
326 1
        }
327
328 1
        return $decoder->decode($request->getContent());
329
    }
330
331
    /**
332
     * Validate specified data
333
     *
334
     * @param mixed $data
335
     * @param array|null $validationGroups
336
     * @return Error[]
337
     */
338 2
    private function validateData($data = null, array $validationGroups = null)
339
    {
340 2
        return (null !== $data) ? $this->validator->validate($data, $validationGroups) : [];
341
    }
342
343
    /**
344
     * Register specified decoders
345
     *
346
     * @param array $decoders
347
     * @param CodecMatcherInterface $matcher
348
     */
349 4
    private function registerDecoders(array $decoders, CodecMatcherInterface $matcher)
350
    {
351 4
        foreach ($decoders as $mediaType => $decoderType) {
352 4
            $matcher->registerDecoder(
353 4
                $this->parseMediaTypeString($mediaType),
354 3
                $this->registry->getDecoder($decoderType)
355 3
            );
356 3
        }
357 3
    }
358
359
    /**
360
     * Register specified encoders
361
     *
362
     * @param array $encoders
363
     * @param CodecMatcherInterface $matcher
364
     */
365 3
    private function registerEncoders(array $encoders, CodecMatcherInterface $matcher)
366
    {
367 3
        foreach ($encoders as $mediaType => $encoderType) {
368 3
            $matcher->registerEncoder(
369 3
                $this->parseMediaTypeString($mediaType),
370 3
                $this->registry->getEncoder($encoderType)
371 3
            );
372 3
        }
373 3
    }
374
}
375