JsonApiTrait::initJsonApiSupport()   B
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 1

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 26
ccs 19
cts 19
cp 1
rs 8.8571
cc 1
eloc 17
nc 1
nop 1
crap 1
1
<?php namespace Neomerx\Limoncello\Http;
2
3
/**
4
 * Copyright 2015 [email protected] (www.neomerx.com)
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
use \Neomerx\Limoncello\Config\Config as C;
20
use \Symfony\Component\HttpFoundation\Response;
21
use \Neomerx\Limoncello\Contracts\IntegrationInterface;
22
use \Neomerx\JsonApi\Contracts\Schema\ContainerInterface;
23
use \Neomerx\JsonApi\Contracts\Factories\FactoryInterface;
24
use \Neomerx\JsonApi\Contracts\Codec\CodecMatcherInterface;
25
use \Neomerx\JsonApi\Contracts\Responses\ResponsesInterface;
26
use \Neomerx\JsonApi\Contracts\Parameters\ParametersInterface;
27
use \Neomerx\JsonApi\Contracts\Parameters\ParametersParserInterface;
28
use \Neomerx\JsonApi\Contracts\Parameters\ParametersCheckerInterface;
29
use \Neomerx\JsonApi\Contracts\Integration\ExceptionThrowerInterface;
30
use \Neomerx\JsonApi\Contracts\Parameters\Headers\MediaTypeInterface;
31
use \Neomerx\JsonApi\Contracts\Parameters\SupportedExtensionsInterface;
32
33
/**
34
 * @package Neomerx\Limoncello
35
 */
36
trait JsonApiTrait
37
{
38
    /**
39
     * If unrecognized parameters should be allowed in input parameters.
40
     *
41
     * @var bool
42
     */
43
    protected $allowUnrecognizedParams = false;
44
45
    /**
46
     * A list of allowed include paths in input parameters.
47
     *
48
     * Empty array [] means clients are not allowed to specify include paths and 'null' means all paths are allowed.
49
     *
50
     * @var string[]|null
51
     */
52
    protected $allowedIncludePaths = [];
53
54
    /**
55
     * A list of JSON API types which clients can sent field sets to.
56
     *
57
     * Possible values
58
     *
59
     * $allowedFieldSetTypes = null; // <-- for all types all fields are allowed
60
     *
61
     * $allowedFieldSetTypes = []; // <-- non of the types and fields are allowed
62
     *
63
     * $allowedFieldSetTypes = [
64
     *      'people'   => null,              // <-- all fields for 'people' are allowed
65
     *      'comments' => [],                // <-- no fields for 'comments' are allowed (all denied)
66
     *      'posts'    => ['title', 'body'], // <-- only 'title' and 'body' fields are allowed for 'posts'
67
     * ];
68
     *
69
     * @var array|null
70
     */
71
    protected $allowedFieldSetTypes = null;
72
73
    /**
74
     * A list of allowed sort field names in input parameters.
75
     *
76
     * Empty array [] means clients are not allowed to specify sort fields and 'null' means all fields are allowed.
77
     *
78
     * @var string[]|null
79
     */
80
    protected $allowedSortFields = [];
81
82
    /**
83
     * A list of allowed pagination input parameters (e.g 'number', 'size', 'offset' and etc).
84
     *
85
     * Empty array [] means clients are not allowed to specify paging and 'null' means all parameters are allowed.
86
     *
87
     * @var string[]|null
88
     */
89
    protected $allowedPagingParameters = [];
90
91
    /**
92
     * A list of allowed filtering input parameters.
93
     *
94
     * Empty array [] means clients are not allowed to specify filtering and 'null' means all parameters are allowed.
95
     *
96
     * @var string[]|null
97
     */
98
    protected $allowedFilteringParameters = [];
99
100
    /**
101
     * JSON API extensions supported by this controller (comma separated).
102
     *
103
     * @var string
104
     */
105
    protected $extensions = MediaTypeInterface::NO_EXT;
106
107
    /**
108
     * If JSON API extension should be allowed.
109
     *
110
     * @var bool
111
     */
112
    protected $allowExtensionsSupport = false;
113
114
    /**
115
     * @var IntegrationInterface
116
     */
117
    private $integration;
118
119
    /**
120
     * @var CodecMatcherInterface
121
     */
122
    private $codecMatcher;
123
124
    /**
125
     * @var ParametersParserInterface
126
     */
127
    private $parametersParser;
128
129
    /**
130
     * @var ParametersCheckerInterface
131
     */
132
    private $parametersChecker;
133
134
    /**
135
     * @var ExceptionThrowerInterface
136
     */
137
    private $exceptionThrower;
138
139
    /**
140
     * @var ParametersInterface
141
     */
142
    private $parameters = null;
143
144
    /**
145
     * @var bool
146
     */
147
    private $parametersChecked = false;
148
149
    /**
150
     * @var SupportedExtensionsInterface
151
     */
152
    private $supportedExtensions;
153
154
    /**
155
     * Init integrations with JSON API implementation.
156
     *
157
     * @param IntegrationInterface $integration
158
     *
159
     * @return void
160
     */
161 7
    private function initJsonApiSupport(IntegrationInterface $integration)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
162
    {
163 7
        $this->integration = $integration;
164
165
        /** @var FactoryInterface $factory */
166 7
        $factory = $this->getIntegration()->getFromContainer(FactoryInterface::class);
167
168 7
        $this->codecMatcher     = $integration->getFromContainer(CodecMatcherInterface::class);
169 7
        $this->exceptionThrower = $integration->getFromContainer(ExceptionThrowerInterface::class);
170
171 7
        $this->parametersParser    = $factory->createParametersParser();
172 7
        $this->supportedExtensions = $factory->createSupportedExtensions($this->extensions);
173 7
        $this->parametersChecker   = $factory->createParametersChecker(
174 7
            $this->exceptionThrower,
175 7
            $this->codecMatcher,
176 7
            $this->allowUnrecognizedParams,
177 7
            $this->allowedIncludePaths,
178 7
            $this->allowedFieldSetTypes,
179 7
            $this->allowedSortFields,
180 7
            $this->allowedPagingParameters,
181 7
            $this->allowedFilteringParameters
182 7
        );
183
184
        // information about extensions supported by the current controller might be used in exception handler
185 7
        $integration->setInContainer(SupportedExtensionsInterface::class, $this->supportedExtensions);
186 7
    }
187
188
    /**
189
     * @return mixed
190
     */
191 1
    protected function getDocument()
192
    {
193 1
        if ($this->codecMatcher->getDecoder() === null) {
194 1
            $this->codecMatcher->findDecoder($this->getParameters()->getContentTypeHeader());
195 1
        }
196
197 1
        $decoder = $this->codecMatcher->getDecoder();
198 1
        return $decoder->decode($this->getIntegration()->getContent());
199
    }
200
201
    /**
202
     * @return ParametersInterface
203
     */
204 6
    protected function getUncheckedParameters()
205
    {
206 6
        if ($this->parameters === null) {
207 6
            $this->parameters = $this->parametersParser->parse($this->getIntegration(), $this->exceptionThrower);
208 6
        }
209
210 6
        return $this->parameters;
211
    }
212
213
    /**
214
     * @return void
215
     */
216 6
    protected function checkParameters()
217
    {
218 6
        $this->parametersChecker->check($this->getUncheckedParameters());
219 6
        $this->parametersChecked = true;
220 6
    }
221
222
    /**
223
     * @return void
224
     */
225 1
    protected function checkParametersEmpty()
226
    {
227 1
        $this->getParameters()->isEmpty() === true ?: $this->exceptionThrower->throwBadRequest();
228 1
    }
229
230
    /**
231
     * @return ParametersInterface
232
     */
233 4
    protected function getParameters()
234
    {
235 4
        if ($this->parametersChecked === false) {
236 4
            $this->checkParameters();
237 4
        }
238
239 4
        return $this->getUncheckedParameters();
240
    }
241
242
    /**
243
     * Get response with HTTP code only.
244
     *
245
     * @param $statusCode
246
     *
247
     * @return Response
248
     */
249 1
    protected function getCodeResponse($statusCode)
250
    {
251 1
        $this->checkParameters();
252
253
        /** @var ResponsesInterface $responses */
254 1
        $responses = $this->getIntegration()->getFromContainer(ResponsesInterface::class);
255 1
        $outputMediaType = $this->codecMatcher->getEncoderRegisteredMatchedType();
256
257 1
        return $responses->getResponse($statusCode, $outputMediaType, null, $this->supportedExtensions);
258
    }
259
260
    /**
261
     * Get response with meta information only.
262
     *
263
     * @param array|object $meta       Meta information.
264
     * @param int          $statusCode
265
     *
266
     * @return Response
267
     */
268 1
    protected function getMetaResponse($meta, $statusCode = Response::HTTP_OK)
269
    {
270 1
        $this->checkParameters();
271
272
        /** @var ResponsesInterface $responses */
273 1
        $responses       = $this->getIntegration()->getFromContainer(ResponsesInterface::class);
274 1
        $encoder         = $this->codecMatcher->getEncoder();
275 1
        $outputMediaType = $this->codecMatcher->getEncoderRegisteredMatchedType();
276 1
        $content         = $encoder->encodeMeta($meta);
277
278 1
        return $responses->getResponse($statusCode, $outputMediaType, $content, $this->supportedExtensions);
279
    }
280
281
    /**
282
     * @return SupportedExtensionsInterface
283
     */
284 1
    protected function getSupportedExtensions()
285
    {
286 1
        return $this->supportedExtensions;
287
    }
288
289
    /**
290
     * Get response with regular JSON API Document in body.
291
     *
292
     * @param object|array                                                       $data
293
     * @param int                                                                $statusCode
294
     * @param array<string,\Neomerx\JsonApi\Contracts\Schema\LinkInterface>|null $links
295
     * @param mixed                                                              $meta
296
     *
297
     * @return Response
298
     */
299 1
    protected function getContentResponse(
300
        $data,
301
        $statusCode = Response::HTTP_OK,
302
        $links = null,
303
        $meta = null
304
    ) {
305 1
        $parameters      = $this->getParameters();
306 1
        $encoder         = $this->codecMatcher->getEncoder();
307 1
        $outputMediaType = $this->codecMatcher->getEncoderRegisteredMatchedType();
308
309 1
        $links === null ?: $encoder->withLinks($links);
310 1
        $meta  === null ?: $encoder->withMeta($meta);
311
312
        /** @var ResponsesInterface $responses */
313 1
        $responses = $this->getIntegration()->getFromContainer(ResponsesInterface::class);
314 1
        $content   = $encoder->encodeData($data, $parameters);
315
316 1
        return $responses->getResponse($statusCode, $outputMediaType, $content, $this->supportedExtensions);
317
    }
318
319
    /**
320
     * @param object                                                             $resource
321
     * @param array<string,\Neomerx\JsonApi\Contracts\Schema\LinkInterface>|null $links
322
     * @param mixed                                                              $meta
323
     *
324
     * @return Response
325
     */
326 1
    protected function getCreatedResponse(
327
        $resource,
328
        $links = null,
329
        $meta = null
330
    ) {
331 1
        $integration     = $this->getIntegration();
332 1
        $parameters      = $this->getParameters();
333 1
        $encoder         = $this->codecMatcher->getEncoder();
334 1
        $outputMediaType = $this->codecMatcher->getEncoderRegisteredMatchedType();
335
336 1
        $links === null ?: $encoder->withLinks($links);
337 1
        $meta  === null ?: $encoder->withMeta($meta);
338
339 1
        $content = $encoder->encodeData($resource, $parameters);
340
341
        /** @var ResponsesInterface $responses */
342 1
        $responses = $integration->getFromContainer(ResponsesInterface::class);
343
        /** @var ContainerInterface $schemaContainer */
344 1
        $schemaContainer = $integration->getFromContainer(ContainerInterface::class);
345
346 1
        $config    = $integration->getFromContainer(C::class);
347 1
        $urlPrefix = isset($config[C::JSON][C::JSON_URL_PREFIX]) === true ? $config[C::JSON][C::JSON_URL_PREFIX] : null;
348 1
        $location  = $urlPrefix . $schemaContainer->getSchema($resource)->getSelfSubLink($resource)->getSubHref();
349
350 1
        return $responses->getCreatedResponse($location, $outputMediaType, $content, $this->supportedExtensions);
351
    }
352
353
    /**
354
     * @return IntegrationInterface
355
     */
356 7
    private function getIntegration()
357
    {
358 7
        assert('$this->integration !== null', 'Haven\'t you forgotten to init integration with framework?');
359 7
        return $this->integration;
360
    }
361
}
362