1 | <?php |
||
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( |
|
86 | |||
87 | /** |
||
88 | * @inheritdoc |
||
89 | */ |
||
90 | public function getFactory() |
||
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) |
|
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) |
|
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) |
|
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) |
|
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) |
|
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) |
|
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) |
|
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) |
|
374 | } |
||
375 |