Completed
Push — develop ( 26b032...524257 )
by Neomerx
18:05 queued 09:45
created

DefaultControllerMethodsTrait   D

Complexity

Total Complexity 49

Size/Duplication

Total Lines 628
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 20

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 49
lcom 1
cbo 20
dl 0
loc 628
rs 4.0628
c 0
b 0
f 0
ccs 182
cts 182
cp 1

18 Methods

Rating   Name   Duplication   Size   Complexity  
B defaultIndex() 0 24 4
B defaultRead() 0 26 4
B defaultReadRelationshipWithClosure() 0 27 6
B defaultReadRelationshipIdentifiersWithClosure() 0 27 6
B defaultCreate() 0 28 2
B defaultUpdate() 0 50 5
B defaultUpdateInRelationship() 0 43 2
A defaultDelete() 0 16 1
B defaultDeleteInRelationship() 0 27 2
A createQueryValidator() 0 12 1
A createDataValidator() 0 12 1
A readJsonFromRequest() 0 17 3
A createParameterMapper() 0 16 1
C mapSchemeDataToModelData() 0 37 7
A createApi() 0 10 1
A createResponses() 0 20 1
A assertClassValueDefined() 0 4 1
A assertClassImplements() 0 7 1

How to fix   Complexity   

Complex Class

Complex classes like DefaultControllerMethodsTrait often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DefaultControllerMethodsTrait, and based on these observations, apply Extract Interface, too.

1
<?php namespace Limoncello\Flute\Http\Traits;
2
3
/**
4
 * Copyright 2015-2017 [email protected]
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 Closure;
20
use Limoncello\Contracts\Application\ModelInterface;
21
use Limoncello\Contracts\Data\ModelSchemeInfoInterface;
22
use Limoncello\Contracts\Data\RelationshipTypes;
23
use Limoncello\Contracts\L10n\FormatterFactoryInterface;
24
use Limoncello\Contracts\Settings\SettingsProviderInterface;
25
use Limoncello\Flute\Contracts\Api\CrudInterface;
26
use Limoncello\Flute\Contracts\Encoder\EncoderInterface;
27
use Limoncello\Flute\Contracts\FactoryInterface;
28
use Limoncello\Flute\Contracts\Http\Query\ParametersMapperInterface;
29
use Limoncello\Flute\Contracts\Models\PaginatedDataInterface;
30
use Limoncello\Flute\Contracts\Schema\JsonSchemesInterface;
31
use Limoncello\Flute\Contracts\Schema\SchemaInterface;
32
use Limoncello\Flute\Contracts\Validation\JsonApiDataRulesInterface;
33
use Limoncello\Flute\Contracts\Validation\JsonApiDataValidatingParserInterface;
34
use Limoncello\Flute\Contracts\Validation\JsonApiParserFactoryInterface;
35
use Limoncello\Flute\Contracts\Validation\JsonApiQueryRulesInterface;
36
use Limoncello\Flute\Contracts\Validation\JsonApiQueryValidatingParserInterface;
37
use Limoncello\Flute\Http\Responses;
38
use Limoncello\Flute\Package\FluteSettings as S;
39
use Limoncello\Flute\Resources\Messages\En\Generic;
40
use Limoncello\Flute\Validation\JsonApi\DefaultQueryValidationRules;
41
use Neomerx\JsonApi\Contracts\Document\DocumentInterface as DI;
42
use Neomerx\JsonApi\Contracts\Encoder\Parameters\EncodingParametersInterface;
43
use Neomerx\JsonApi\Contracts\Http\Headers\MediaTypeInterface;
44
use Neomerx\JsonApi\Contracts\Http\ResponsesInterface;
45
use Neomerx\JsonApi\Encoder\Parameters\EncodingParameters;
46
use Neomerx\JsonApi\Exceptions\JsonApiException;
47
use Neomerx\JsonApi\Http\Headers\MediaType;
48
use Psr\Container\ContainerExceptionInterface;
49
use Psr\Container\ContainerInterface;
50
use Psr\Container\NotFoundExceptionInterface;
51
use Psr\Http\Message\ResponseInterface;
52
use Psr\Http\Message\UriInterface;
53
54
/**
55
 * @package Limoncello\Flute
56
 */
57
trait DefaultControllerMethodsTrait
58
{
59
    /** @noinspection PhpTooManyParametersInspection
60
     * @param array                                 $queryParams
61
     * @param UriInterface                          $requestUri
62
     * @param JsonApiQueryValidatingParserInterface $queryParser
63
     * @param ParametersMapperInterface             $mapper
64
     * @param CrudInterface                         $crud
65
     * @param SettingsProviderInterface             $provider
66
     * @param JsonSchemesInterface                  $jsonSchemes
67
     * @param EncoderInterface                      $encoder
68
     *
69
     * @return ResponseInterface
70
     */
71 12
    protected static function defaultIndex(
72
        array $queryParams,
73
        UriInterface $requestUri,
74
        JsonApiQueryValidatingParserInterface $queryParser,
75
        ParametersMapperInterface $mapper,
76
        CrudInterface $crud,
77
        SettingsProviderInterface $provider,
78
        JsonSchemesInterface $jsonSchemes,
79
        EncoderInterface $encoder
80
    ): ResponseInterface {
81 12
        $queryParser->parse($queryParams);
82
83 11
        $models = $mapper->applyQueryParameters($queryParser, $crud)->index();
84
85 10
        $encodingParams = new EncodingParameters(
86 10
            $queryParser->hasIncludes() === true ? array_keys($queryParser->getIncludes()) : null,
0 ignored issues
show
Bug introduced by
It seems like $queryParser->hasInclude...->getIncludes()) : null can also be of type array; however, Neomerx\JsonApi\Encoder\...rameters::__construct() does only seem to accept null|array<integer,string>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
87 10
            $queryParser->hasFields() === true ? $queryParser->getFields() : null
88
        );
89 10
        $responses      = static::createResponses($requestUri, $provider, $jsonSchemes, $encoder, $encodingParams);
90 10
        $response       = ($models->getData()) === null ?
91 10
            $responses->getCodeResponse(404) : $responses->getContentResponse($models);
92
93 10
        return $response;
94
    }
95
96
    /** @noinspection PhpTooManyParametersInspection
97
     * @param string                                $index
98
     * @param array                                 $queryParams
99
     * @param UriInterface                          $requestUri
100
     * @param JsonApiQueryValidatingParserInterface $queryParser
101
     * @param ParametersMapperInterface             $mapper
102
     * @param CrudInterface                         $crud
103
     * @param SettingsProviderInterface             $provider
104
     * @param JsonSchemesInterface                  $jsonSchemes
105
     * @param EncoderInterface                      $encoder
106
     *
107
     * @return ResponseInterface
108
     */
109 1
    protected static function defaultRead(
110
        string $index,
111
        array $queryParams,
112
        UriInterface $requestUri,
113
        JsonApiQueryValidatingParserInterface $queryParser,
114
        ParametersMapperInterface $mapper,
115
        CrudInterface $crud,
116
        SettingsProviderInterface $provider,
117
        JsonSchemesInterface $jsonSchemes,
118
        EncoderInterface $encoder
119
    ): ResponseInterface {
120 1
        $queryParser->parse($queryParams);
121
122 1
        $model = $mapper->applyQueryParameters($queryParser, $crud)->read($index);
123 1
        assert(!($model instanceof PaginatedDataInterface));
124
125 1
        $encodingParams = new EncodingParameters(
126 1
            $queryParser->hasIncludes() === true ? array_keys($queryParser->getIncludes()) : null,
0 ignored issues
show
Bug introduced by
It seems like $queryParser->hasInclude...->getIncludes()) : null can also be of type array; however, Neomerx\JsonApi\Encoder\...rameters::__construct() does only seem to accept null|array<integer,string>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
127 1
            $queryParser->hasFields() === true ? $queryParser->getFields() : null
128
        );
129 1
        $responses      = static::createResponses($requestUri, $provider, $jsonSchemes, $encoder, $encodingParams);
130 1
        $response       = $model === null ?
131 1
            $responses->getCodeResponse(404) : $responses->getContentResponse($model);
132
133 1
        return $response;
134
    }
135
136
    /** @noinspection PhpTooManyParametersInspection
137
     * @param Closure                               $apiHandler
138
     * @param array                                 $queryParams
139
     * @param UriInterface                          $requestUri
140
     * @param JsonApiQueryValidatingParserInterface $queryParser
141
     * @param ParametersMapperInterface             $mapper
142
     * @param CrudInterface                         $crud
143
     * @param SettingsProviderInterface             $provider
144
     * @param JsonSchemesInterface                  $jsonSchemes
145
     * @param EncoderInterface                      $encoder
146
     *
147
     * @return ResponseInterface
148
     */
149 2
    protected static function defaultReadRelationshipWithClosure(
150
        Closure $apiHandler,
151
        array $queryParams,
152
        UriInterface $requestUri,
153
        JsonApiQueryValidatingParserInterface $queryParser,
154
        ParametersMapperInterface $mapper,
155
        CrudInterface $crud,
156
        SettingsProviderInterface $provider,
157
        JsonSchemesInterface $jsonSchemes,
158
        EncoderInterface $encoder
159
    ): ResponseInterface {
160 2
        $queryParser->parse($queryParams);
161 2
        $mapper->applyQueryParameters($queryParser, $crud);
162
163 2
        $relData = call_user_func($apiHandler);
164
165 2
        $encodingParams = new EncodingParameters(
166 2
            $queryParser->hasIncludes() === true ? array_keys($queryParser->getIncludes()) : null,
0 ignored issues
show
Bug introduced by
It seems like $queryParser->hasInclude...->getIncludes()) : null can also be of type array; however, Neomerx\JsonApi\Encoder\...rameters::__construct() does only seem to accept null|array<integer,string>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
167 2
            $queryParser->hasFields() === true ? $queryParser->getFields() : null
168
        );
169 2
        $responses      = static::createResponses($requestUri, $provider, $jsonSchemes, $encoder, $encodingParams);
170
171 2
        $noData   = $relData === null || ($relData instanceof PaginatedDataInterface && $relData->getData() === null);
172 2
        $response = $noData === true ? $responses->getCodeResponse(404) : $responses->getContentResponse($relData);
173
174 2
        return $response;
175
    }
176
177
    /** @noinspection PhpTooManyParametersInspection
178
     * @param Closure                               $apiHandler
179
     * @param array                                 $queryParams
180
     * @param UriInterface                          $requestUri
181
     * @param JsonApiQueryValidatingParserInterface $queryParser
182
     * @param ParametersMapperInterface             $mapper
183
     * @param CrudInterface                         $crud
184
     * @param SettingsProviderInterface             $provider
185
     * @param JsonSchemesInterface                  $jsonSchemes
186
     * @param EncoderInterface                      $encoder
187
     *
188
     * @return ResponseInterface
189
     */
190 1
    protected static function defaultReadRelationshipIdentifiersWithClosure(
191
        Closure $apiHandler,
192
        array $queryParams,
193
        UriInterface $requestUri,
194
        JsonApiQueryValidatingParserInterface $queryParser,
195
        ParametersMapperInterface $mapper,
196
        CrudInterface $crud,
197
        SettingsProviderInterface $provider,
198
        JsonSchemesInterface $jsonSchemes,
199
        EncoderInterface $encoder
200
    ): ResponseInterface {
201 1
        $queryParser->parse($queryParams);
202 1
        $mapper->applyQueryParameters($queryParser, $crud);
203
204 1
        $relData = call_user_func($apiHandler);
205
206 1
        $encodingParams = new EncodingParameters(
207 1
            $queryParser->hasIncludes() === true ? array_keys($queryParser->getIncludes()) : null,
0 ignored issues
show
Bug introduced by
It seems like $queryParser->hasInclude...->getIncludes()) : null can also be of type array; however, Neomerx\JsonApi\Encoder\...rameters::__construct() does only seem to accept null|array<integer,string>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
208 1
            $queryParser->hasFields() === true ? $queryParser->getFields() : null
209
        );
210 1
        $responses      = static::createResponses($requestUri, $provider, $jsonSchemes, $encoder, $encodingParams);
211
212 1
        $noData   = $relData === null || ($relData instanceof PaginatedDataInterface && $relData->getData() === null);
213 1
        $response = $noData === true ? $responses->getCodeResponse(404) : $responses->getIdentifiersResponse($relData);
214
215 1
        return $response;
216
    }
217
218
    /** @noinspection PhpTooManyParametersInspection
219
     * @param UriInterface                         $requestUri
220
     * @param string                               $requestBody
221
     * @param string                               $schemeClass
222
     * @param ModelSchemeInfoInterface             $schemeInfo
223
     * @param JsonApiDataValidatingParserInterface $validator
224
     * @param CrudInterface                        $crud
225
     * @param SettingsProviderInterface            $provider
226
     * @param JsonSchemesInterface                 $jsonSchemes
227
     * @param EncoderInterface                     $encoder
228
     * @param FactoryInterface                     $errorFactory
229
     * @param FormatterFactoryInterface            $formatterFactory
230
     *
231
     * @return ResponseInterface
232
     *
233
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
234
     */
235 1
    protected static function defaultCreate(
236
        UriInterface $requestUri,
237
        string $requestBody,
238
        string $schemeClass,
239
        ModelSchemeInfoInterface $schemeInfo,
240
        JsonApiDataValidatingParserInterface $validator,
241
        CrudInterface $crud,
242
        SettingsProviderInterface $provider,
243
        JsonSchemesInterface $jsonSchemes,
244
        EncoderInterface $encoder,
245
        FactoryInterface $errorFactory,
246
        FormatterFactoryInterface $formatterFactory
247
    ): ResponseInterface {
248 1
        $jsonData = static::readJsonFromRequest($requestBody, $errorFactory, $formatterFactory);
249 1
        $captures = $validator->assert($jsonData)->getJsonApiCaptures();
250
251 1
        list ($index, $attributes, $toMany) = static::mapSchemeDataToModelData($captures, $schemeClass, $schemeInfo);
252
253 1
        $index = $crud->create($index, $attributes, $toMany);
254 1
        $model = $crud->read($index);
255 1
        assert($model !== null && !($model instanceof PaginatedDataInterface));
256
257 1
        $encodingParams = null;
258 1
        $responses      = static::createResponses($requestUri, $provider, $jsonSchemes, $encoder, $encodingParams);
259 1
        $response       = $responses->getCreatedResponse($model);
260
261 1
        return $response;
262
    }
263
264
    /** @noinspection PhpTooManyParametersInspection
265
     * @param string                               $index
266
     * @param UriInterface                         $requestUri
267
     * @param string                               $requestBody
268
     * @param string                               $schemeClass
269
     * @param ModelSchemeInfoInterface             $schemeInfo
270
     * @param JsonApiDataValidatingParserInterface $validator
271
     * @param CrudInterface                        $crud
272
     * @param SettingsProviderInterface            $provider
273
     * @param JsonSchemesInterface                 $jsonSchemes
274
     * @param EncoderInterface                     $encoder
275
     * @param FactoryInterface                     $errorFactory
276
     * @param FormatterFactoryInterface            $formatterFactory
277
     * @param string                               $messagesNamespace
278
     * @param string                               $errorMessage
279
     *
280
     * @return ResponseInterface
281
     *
282
     * @SuppressWarnings(PHPMD.ElseExpression)
283
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
284
     */
285 6
    protected static function defaultUpdate(
286
        string $index,
287
        UriInterface $requestUri,
288
        string $requestBody,
289
        string $schemeClass,
290
        ModelSchemeInfoInterface $schemeInfo,
291
        JsonApiDataValidatingParserInterface $validator,
292
        CrudInterface $crud,
293
        SettingsProviderInterface $provider,
294
        JsonSchemesInterface $jsonSchemes,
295
        EncoderInterface $encoder,
296
        FactoryInterface $errorFactory,
297
        FormatterFactoryInterface $formatterFactory,
298
        string $messagesNamespace = S::GENERIC_NAMESPACE,
299
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
300
    ): ResponseInterface {
301 6
        $jsonData = static::readJsonFromRequest($requestBody, $errorFactory, $formatterFactory);
302
        // check that index in data and URL are identical
303 5
        $indexValue = $jsonData[DI::KEYWORD_DATA][DI::KEYWORD_ID] ?? null;
304 5
        if (empty($indexValue) === false) {
305 4
            if ($indexValue !== $index) {
306 1
                $errors    = $errorFactory->createErrorCollection();
307 1
                $formatter = $formatterFactory->createFormatter($messagesNamespace);
308 1
                $errors->addDataIdError($formatter->formatMessage($errorMessage));
309
310 4
                throw new JsonApiException($errors);
311
            }
312
        } else {
313
            // put the index to data for our convenience
314 1
            $jsonData[DI::KEYWORD_DATA][DI::KEYWORD_ID] = $index;
315
        }
316
        // validate the data
317 4
        $captures = $validator->assert($jsonData)->getJsonApiCaptures();
318
319 3
        list ($index, $attributes, $toMany) = static::mapSchemeDataToModelData($captures, $schemeClass, $schemeInfo);
320
321 3
        $updated = $crud->update($index, $attributes, $toMany);
322
323 3
        $encodingParams = null;
324 3
        $responses      = static::createResponses($requestUri, $provider, $jsonSchemes, $encoder, $encodingParams);
325 3
        if ($updated > 0) {
326 2
            $model = $crud->read($index);
327 2
            assert($model !== null && !($model instanceof PaginatedDataInterface));
328 2
            $response = $responses->getContentResponse($model);
329
        } else {
330 1
            $response = $responses->getCodeResponse(404);
331
        }
332
333 3
        return $response;
334
    }
335
336
    /** @noinspection PhpTooManyParametersInspection
337
     * @param string                               $parentIndex
338
     * @param string                               $modelRelName
339
     * @param string                               $childIndex
340
     * @param UriInterface                         $requestUri
341
     * @param string                               $requestBody
342
     * @param string                               $childSchemeClass
343
     * @param ModelSchemeInfoInterface             $schemeInfo
344
     * @param JsonApiDataValidatingParserInterface $childValidator
345
     * @param CrudInterface                        $parentCrud
346
     * @param CrudInterface                        $childCrud
347
     * @param SettingsProviderInterface            $provider
348
     * @param JsonSchemesInterface                 $jsonSchemes
349
     * @param EncoderInterface                     $encoder
350
     * @param FactoryInterface                     $errorFactory
351
     * @param FormatterFactoryInterface            $formatterFactory
352
     * @param string                               $messagesNamespace
353
     * @param string                               $errorMessage
354
     *
355
     * @return ResponseInterface
356
     *
357
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
358
     */
359 2
    protected static function defaultUpdateInRelationship(
360
        string $parentIndex,
361
        string $modelRelName,
362
        string $childIndex,
363
        UriInterface $requestUri,
364
        string $requestBody,
365
        string $childSchemeClass,
366
        ModelSchemeInfoInterface $schemeInfo,
367
        JsonApiDataValidatingParserInterface $childValidator,
368
        CrudInterface $parentCrud,
369
        CrudInterface $childCrud,
370
        SettingsProviderInterface $provider,
371
        JsonSchemesInterface $jsonSchemes,
372
        EncoderInterface $encoder,
373
        FactoryInterface $errorFactory,
374
        FormatterFactoryInterface $formatterFactory,
375
        string $messagesNamespace = S::GENERIC_NAMESPACE,
376
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
377
    ): ResponseInterface {
378 2
        if ($parentCrud->hasInRelationship($parentIndex, $modelRelName, $childIndex) === true) {
379 1
            return static::defaultUpdate(
380 1
                $childIndex,
381 1
                $requestUri,
382 1
                $requestBody,
383 1
                $childSchemeClass,
384 1
                $schemeInfo,
385 1
                $childValidator,
386 1
                $childCrud,
387 1
                $provider,
388 1
                $jsonSchemes,
389 1
                $encoder,
390 1
                $errorFactory,
391 1
                $formatterFactory,
392 1
                $messagesNamespace,
393 1
                $errorMessage
394
            );
395
        }
396
397 1
        $encodingParams = null;
398 1
        $responses      = static::createResponses($requestUri, $provider, $jsonSchemes, $encoder, $encodingParams);
399
400 1
        return $responses->getCodeResponse(404);
401
    }
402
403
    /**
404
     * @param string                    $index
405
     * @param UriInterface              $requestUri
406
     * @param CrudInterface             $crud
407
     * @param SettingsProviderInterface $provider
408
     * @param JsonSchemesInterface      $jsonSchemes
409
     * @param EncoderInterface          $encoder
410
     *
411
     * @return ResponseInterface
412
     */
413 2
    protected static function defaultDelete(
414
        string $index,
415
        UriInterface $requestUri,
416
        CrudInterface $crud,
417
        SettingsProviderInterface $provider,
418
        JsonSchemesInterface $jsonSchemes,
419
        EncoderInterface $encoder
420
    ): ResponseInterface {
421 2
        $crud->remove($index);
422
423 2
        $encodingParams = null;
424 2
        $responses      = static::createResponses($requestUri, $provider, $jsonSchemes, $encoder, $encodingParams);
425 2
        $response       = $responses->getCodeResponse(204);
426
427 2
        return $response;
428
    }
429
430
    /** @noinspection PhpTooManyParametersInspection
431
     * @param string                    $parentIndex
432
     * @param string                    $modelRelName
433
     * @param string                    $childIndex
434
     * @param UriInterface              $requestUri
435
     * @param CrudInterface             $parentCrud
436
     * @param CrudInterface             $childCrud
437
     * @param SettingsProviderInterface $provider
438
     * @param JsonSchemesInterface      $jsonSchemes
439
     * @param EncoderInterface          $encoder
440
     *
441
     * @return ResponseInterface
442
     */
443 1
    protected static function defaultDeleteInRelationship(
444
        string $parentIndex,
445
        string $modelRelName,
446
        string $childIndex,
447
        UriInterface $requestUri,
448
        CrudInterface $parentCrud,
449
        CrudInterface $childCrud,
450
        SettingsProviderInterface $provider,
451
        JsonSchemesInterface $jsonSchemes,
452
        EncoderInterface $encoder
453
    ): ResponseInterface {
454 1
        if ($parentCrud->hasInRelationship($parentIndex, $modelRelName, $childIndex) === true) {
455 1
            return static::defaultDelete(
456 1
                $childIndex,
457 1
                $requestUri,
458 1
                $childCrud,
459 1
                $provider,
460 1
                $jsonSchemes,
461 1
                $encoder
462
            );
463
        }
464
465 1
        $encodingParams = null;
466 1
        $responses      = static::createResponses($requestUri, $provider, $jsonSchemes, $encoder, $encodingParams);
467
468 1
        return $responses->getCodeResponse(404);
469
    }
470
471
    /**
472
     * @param ContainerInterface $container
473
     * @param string             $rulesClass
474
     *
475
     * @return JsonApiQueryValidatingParserInterface
476
     * @throws ContainerExceptionInterface
477
     * @throws NotFoundExceptionInterface
478
     */
479 16
    protected static function createQueryValidator(
480
        ContainerInterface $container,
481
        string $rulesClass = DefaultQueryValidationRules::class
482
    ): JsonApiQueryValidatingParserInterface {
483 16
        static::assertClassImplements($rulesClass, JsonApiQueryRulesInterface::class);
484
485
        /** @var JsonApiParserFactoryInterface $factory */
486 16
        $factory   = $container->get(JsonApiParserFactoryInterface::class);
487 16
        $validator = $factory->createQueryParser($rulesClass);
488
489 16
        return $validator;
490
    }
491
492
    /**
493
     * @param ContainerInterface $container
494
     * @param string             $rulesClass
495
     *
496
     * @return JsonApiDataValidatingParserInterface
497
     *
498
     * @throws ContainerExceptionInterface
499
     * @throws NotFoundExceptionInterface
500
     */
501 8
    protected static function createDataValidator(
502
        ContainerInterface $container,
503
        string $rulesClass
504
    ): JsonApiDataValidatingParserInterface {
505 8
        static::assertClassImplements($rulesClass, JsonApiDataRulesInterface::class);
506
507
        /** @var JsonApiParserFactoryInterface $factory */
508 8
        $factory   = $container->get(JsonApiParserFactoryInterface::class);
509 8
        $validator = $factory->createDataParser($rulesClass);
510
511 8
        return $validator;
512
    }
513
514
    /**
515
     * @param string                    $requestBody
516
     * @param FactoryInterface          $errorFactory
517
     * @param FormatterFactoryInterface $formatterFactory
518
     * @param string                    $messagesNamespace
519
     * @param string                    $errorMessage
520
     *
521
     * @return array
522
     */
523 7
    protected static function readJsonFromRequest(
524
        string $requestBody,
525
        FactoryInterface $errorFactory,
526
        FormatterFactoryInterface $formatterFactory,
527
        string $messagesNamespace = S::GENERIC_NAMESPACE,
528
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
529
    ): array {
530 7
        if (empty($requestBody) === true || ($json = json_decode($requestBody, true)) === null) {
531 1
            $formatter = $formatterFactory->createFormatter($messagesNamespace);
532 1
            $errors    = $errorFactory->createErrorCollection();
533 1
            $errors->addDataError($formatter->formatMessage($errorMessage));
534
535 1
            throw new JsonApiException($errors);
536
        }
537
538 6
        return $json;
539
    }
540
541
    /**
542
     * @param ContainerInterface $container
543
     * @param string             $schemaClass
544
     *
545
     * @return ParametersMapperInterface
546
     * @throws ContainerExceptionInterface
547
     * @throws NotFoundExceptionInterface
548
     */
549 16
    protected static function createParameterMapper(
550
        ContainerInterface $container,
551
        string $schemaClass
552
    ): ParametersMapperInterface {
553 16
        static::assertClassImplements($schemaClass, SchemaInterface::class);
554
555
        /** @var SchemaInterface $schemaClass */
556 16
        $schemaClass      = static::SCHEMA_CLASS;
557 16
        $jsonResourceType = $schemaClass::TYPE;
558
559
        /** @var ParametersMapperInterface $mapper */
560 16
        $mapper = $container->get(ParametersMapperInterface::class);
561 16
        $mapper->selectRootSchemeByResourceType($jsonResourceType);
562
563 16
        return $mapper;
564
    }
565
566
    /**
567
     * @param array                    $captures
568
     * @param string                   $schemeClass
569
     * @param ModelSchemeInfoInterface $schemeInfo
570
     *
571
     * @return array
572
     */
573 4
    protected static function mapSchemeDataToModelData(
574
        array $captures,
575
        string $schemeClass,
576
        ModelSchemeInfoInterface $schemeInfo
577
    ): array {
578 4
        static::assertClassImplements($schemeClass, SchemaInterface::class);
579
580
        /** @var SchemaInterface $schemeClass */
581 4
        static::assertClassImplements($modelClass = $schemeClass::MODEL, ModelInterface::class);
582
        /** @var ModelInterface $modelClass */
583
584 4
        $index         = null;
585 4
        $fields        = [];
586 4
        $toManyIndexes = [];
587 4
        foreach ($captures as $name => $value) {
588 4
            assert(is_string($name) === true);
589 4
            if ($name === DI::KEYWORD_ID) {
590 4
                $index = $value;
591 4
            } elseif ($schemeClass::hasAttributeMapping($name) === true) {
592 4
                $fieldName          = $schemeClass::getAttributeMapping($name);
593 4
                $fields[$fieldName] = $value;
594 4
            } elseif ($schemeClass::hasRelationshipMapping($name) === true) {
595 2
                $modelRelName = $schemeClass::getRelationshipMapping($name);
596 2
                $relType      = $schemeInfo->getRelationshipType($modelClass, $modelRelName);
0 ignored issues
show
Documentation introduced by
$modelClass is of type object<Limoncello\Contra...ication\ModelInterface>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
597 2
                if ($relType === RelationshipTypes::BELONGS_TO) {
598 2
                    $fkName          = $schemeInfo->getForeignKey($modelClass, $modelRelName);
0 ignored issues
show
Documentation introduced by
$modelClass is of type object<Limoncello\Contra...ication\ModelInterface>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
599 2
                    $fields[$fkName] = $value;
600 2
                } elseif ($relType === RelationshipTypes::BELONGS_TO_MANY) {
601 4
                    $toManyIndexes[$modelRelName] = $value;
602
                }
603
            }
604
        }
605
606 4
        $result = [$index, $fields, $toManyIndexes];
607
608 4
        return $result;
609
    }
610
611
    /**
612
     * @param ContainerInterface $container
613
     * @param string|null        $class
614
     *
615
     * @return CrudInterface
616
     *
617
     * @throws ContainerExceptionInterface
618
     * @throws NotFoundExceptionInterface
619
     */
620 26
    protected static function createApi(ContainerInterface $container, string $class): CrudInterface
621
    {
622 26
        static::assertClassImplements($class, CrudInterface::class);
623
624
        /** @var FactoryInterface $factory */
625 26
        $factory = $container->get(FactoryInterface::class);
626 26
        $api     = $factory->createApi($class);
627
628 26
        return $api;
629
    }
630
631
    /**
632
     * @param UriInterface                     $requestUri
633
     * @param SettingsProviderInterface        $provider
634
     * @param JsonSchemesInterface             $jsonSchemes
635
     * @param EncoderInterface                 $encoder
636
     * @param EncodingParametersInterface|null $parameters
637
     *
638
     * @return ResponsesInterface
639
     */
640 21
    protected static function createResponses(
641
        UriInterface $requestUri,
642
        SettingsProviderInterface $provider,
643
        JsonSchemesInterface $jsonSchemes,
644
        EncoderInterface $encoder,
645
        ?EncodingParametersInterface $parameters
646
    ): ResponsesInterface {
647 21
        $encoder->forOriginalUri($requestUri);
648 21
        $settings  = $provider->get(S::class);
649 21
        $responses = new Responses(
650 21
            new MediaType(MediaTypeInterface::JSON_API_TYPE, MediaTypeInterface::JSON_API_SUB_TYPE),
651 21
            $encoder,
652 21
            $jsonSchemes,
653 21
            $parameters,
654 21
            $settings[S::KEY_URI_PREFIX],
655 21
            $settings[S::KEY_META]
656
        );
657
658 21
        return $responses;
659
    }
660
661
    /**
662
     * @param null|string $value
663
     *
664
     * @return void
665
     */
666 26
    protected static function assertClassValueDefined(?string $value): void
667
    {
668 26
        assert(empty($value) === false, 'Value should be defined in `' . static::class . '`.');
669
    }
670
671
    /**
672
     * @param string $class
673
     * @param string $interface
674
     *
675
     * @return void
676
     */
677 26
    protected static function assertClassImplements(string $class, string $interface): void
678
    {
679 26
        assert(
680 26
            array_key_exists($interface, class_implements($class)) === true,
681 26
            "Class `$class` should implement `" . $interface . '` interface.'
682
        );
683
    }
684
}
685