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 ( 32f0eb...60a577 )
by Sergey
03:32
created

JsonApiService::parseRequest()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 25
ccs 13
cts 13
cp 1
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 14
nc 4
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 3
110
        $apiRequest = $this->factory->createRequest($environment);
111 3
        $apiRequest
112 2
            ->setQuery($this->parseQuery($request, $environment))
113 2
            ->setBody($this->parseBody($request, $environment));
114
115 3
        $this->parser->setSerializationGroups($prevGroups);
116
117
        if (null !== $environment->getValidationGroups()) {
118
            $this->validateRequest($apiRequest);
119
        }
120
121 2
        return $apiRequest;
122
    }
123 2
124 2
    /**
125
     * @inheritdoc
126
     */
127
    public function validateRequest(RequestInterface $request)
128
    {
129
        $validationGroups = $request->getEnvironment()->getValidationGroups();
130
        if (is_bool($validationGroups)) {
131
            if (false === $validationGroups) {
132 2
                return;
133 2
            } else {
134
                $validationGroups = null;
135 2
            }
136 2
        }
137
138
        $errors = $this->validateData($request->getQuery(), $validationGroups);
139
        $errors = array_merge($errors, $this->validateData($request->getBody(), $validationGroups));
140
141
        if (0 === count($errors)) {
142
            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 1
        throw new JsonApiException($errors, $code);
157
    }
158 1
159
    /**
160
     * @inheritdoc
161
     */
162
    public function getResponseFactory(RequestInterface $request)
163
    {
164
        return new ResponseFactory($this->schemas, $request->getEnvironment(), $request->getQuery());
165
    }
166
167 6
    /**
168
     * Returns JSON API environment configured in request
169 6
     *
170 1
     * @param Request $request
171
     * @return EnvironmentInterface
172
     */
173 5
    public function getRequestEnvironment(Request $request)
174 5
    {
175 1
        if (false === $request->attributes->has('_jsonapi')) {
176 1
            throw new \RuntimeException('JSON API environment is not provided');
177
        }
178 1
179
        $environment = $request->attributes->get('_jsonapi');
180
        if (!$environment instanceof EnvironmentInterface) {
181 4
            throw new \InvalidArgumentException(sprintf(
182
                "JSON API environment should implement %s interface",
183
                EnvironmentInterface::class
184
            ));
185
        }
186
187
        return $environment;
188
    }
189
190 4
    /**
191
     * Initialize JSON API environment for specified request
192 4
     *
193
     * @param EnvironmentInterface $environment
194 3
     * @param Request $request
195
     */
196
    private function initializeEnvironment(EnvironmentInterface $environment, Request $request)
197 3
    {
198 3
        $matcher = $this->createMatcher($environment);
199 3
200 3
        $this->parseRequestHeaders($request, $matcher);
201
202
        $environment
203
            ->setDecoder($matcher->getDecoder())
204
            ->setEncoder($matcher->getEncoder())
205
            ->setEncoderMediaType($matcher->getEncoderRegisteredMatchedType());
206
    }
207
208 4
    /**
209
     * Create codec matcher for specified environment
210 4
     *
211
     * @param EnvironmentInterface $environment
212 4
     * @return \Neomerx\JsonApi\Contracts\Codec\CodecMatcherInterface
213 4
     */
214 4
    private function createMatcher(EnvironmentInterface $environment)
215 3
    {
216
        $matcher = $this->factory->createCodecMatcher();
217 3
218 3
        $config = $environment->getMatcherConfiguration();
219 3
        if ((array_key_exists('decoders', $config)) && (is_array($config['decoders']))) {
220
            $this->registerDecoders($config['decoders'], $matcher);
221 3
        }
222
223
        if ((array_key_exists('encoders', $config)) && (is_array($config['encoders']))) {
224
            $this->registerEncoders($config['encoders'], $matcher);
225
        }
226
227
        return $matcher;
228
    }
229
230 4
    /**
231
     * Convert media type string to media type object
232 4
     *
233 4
     * @param string $type
234 1
     * @return \Neomerx\JsonApi\Contracts\Http\Headers\MediaTypeInterface
235
     */
236
    private function parseMediaTypeString($type)
237 3
    {
238
        $parts = explode('/', $type);
239
        if (2 !== count($parts)) {
240
            throw new InvalidArgumentException(sprintf("Invalid media type '%s' specified", $type));
241
        }
242
243
        return $this->factory->createMediaType($parts[0], $parts[1]);
244
    }
245
246 3
    /**
247
     * Parse request headers and detect appropriate decoder and encoder
248 3
     *
249 3
     * @param Request $request
250 3
     * @param CodecMatcherInterface $matcher
251
     */
252 3
    private function parseRequestHeaders(Request $request, CodecMatcherInterface $matcher)
253 3
    {
254
        $psr7Request = $this->createPsr7Request($request);
255
        $headers = $this->factory->createHeaderParametersParser()->parse($psr7Request);
256
        $checker = $this->factory->createHeadersChecker($matcher);
257
258
        $checker->checkHeaders($headers);
259
    }
260
261 3
    /**
262
     * Create PSR7 request from symfony http foundation request
263 3
     *
264
     * @param Request $request
265 3
     * @return Psr7Request
266 3
     */
267
    private function createPsr7Request(Request $request)
268 3
    {
269 3
        return new Psr7Request(
270 3
            function () use ($request) {
271 3
                return $request->getMethod();
272
            },
273 3
            function ($name) use ($request) {
274 3
                $header = $request->headers->get($name);
275 2
                if (!is_array($header)) {
276 2
                    $header = array($header);
277
                }
278 3
279
                return $header;
280
            },
281
            function () use ($request) {
282
                return $request->query->all();
283
            }
284
        );
285
    }
286
287
    /**
288 3
     * Parse request query parameters
289
     *
290 3
     * @param Request $request
291 1
     * @param EnvironmentInterface $environment
292
     * @return \Neomerx\JsonApi\Contracts\Encoder\Parameters\EncodingParametersInterface|null
293
     */
294 2
    private function parseQuery(Request $request, EnvironmentInterface $environment)
295 2
    {
296
        if (null === $environment->getQueryType()) {
297 2
            return null;
298 2
        }
299 2
300
        $queryParser = $this->factory->createQueryParametersParser();
301 2
        if ($queryParser instanceof QueryParametersParserInterface) {
302
            $queryParser
303
                ->setDataParser($this->parser)
304
                ->setQueryType($environment->getQueryType());
305
        }
306
307
        return $queryParser->parse($this->createPsr7Request($request));
308
    }
309
310
    /**
311 3
     * Parse request body
312
     *
313 3
     * @param Request $request
314 2
     * @param EnvironmentInterface $environment
315
     * @return mixed|null
316
     */
317 1
    private function parseBody(Request $request, EnvironmentInterface $environment)
318 1
    {
319 1
        if (null === $environment->getBodyType()) {
320 1
            return null;
321
        }
322 1
323
        $decoder = $environment->getDecoder();
324
        if ($decoder instanceof DecoderInterface) {
325
            $decoder->setContentType($environment->getBodyType());
326
        }
327
328
        return $decoder->decode($request->getContent());
329
    }
330
331
    /**
332 2
     * Validate specified data
333
     *
334 2
     * @param mixed $data
335
     * @param array|null $validationGroups
336
     * @return Error[]
337
     */
338
    private function validateData($data = null, array $validationGroups = null)
339
    {
340
        return (null !== $data) ? $this->validator->validate($data, $validationGroups) : [];
341
    }
342
343 4
    /**
344
     * Register specified decoders
345 4
     *
346 4
     * @param array $decoders
347 4
     * @param CodecMatcherInterface $matcher
348 3
     */
349 3
    private function registerDecoders(array $decoders, CodecMatcherInterface $matcher)
350 3
    {
351 3
        foreach ($decoders as $mediaType => $decoderType) {
352
            $matcher->registerDecoder(
353
                $this->parseMediaTypeString($mediaType),
354
                $this->registry->getDecoder($decoderType)
355
            );
356
        }
357
    }
358
359 3
    /**
360
     * Register specified encoders
361 3
     *
362 3
     * @param array $encoders
363 3
     * @param CodecMatcherInterface $matcher
364 3
     */
365 3
    private function registerEncoders(array $encoders, CodecMatcherInterface $matcher)
366 3
    {
367 3
        foreach ($encoders as $mediaType => $encoderType) {
368
            $matcher->registerEncoder(
369
                $this->parseMediaTypeString($mediaType),
370
                $this->registry->getEncoder($encoderType)
371
            );
372
        }
373
    }
374
}
375