Completed
Push — develop ( de7f4b...5c2193 )
by Neomerx
09:05
created

defaultReadRelationshipWithClosureHandler()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 27
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 15.2788

Importance

Changes 0
Metric Value
dl 0
loc 27
ccs 4
cts 11
cp 0.3636
rs 8.439
c 0
b 0
f 0
cc 6
eloc 21
nc 6
nop 9
crap 15.2788

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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 defaultIndexHandler(
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
        $encParams = new EncodingParameters(
86
            $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
            $queryParser->hasFields() === true ? $queryParser->getFields() : null
88
        );
89
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
90
        $response  = ($models->getData()) === null ?
91
            $responses->getCodeResponse(404) : $responses->getContentResponse($models);
92
93
        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 defaultReadHandler(
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
        assert(!($model instanceof PaginatedDataInterface));
124
125
        $encParams = new EncodingParameters(
126
            $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
            $queryParser->hasFields() === true ? $queryParser->getFields() : null
128
        );
129
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
130
        $response  = $model === null ?
131
            $responses->getCodeResponse(404) : $responses->getContentResponse($model);
132
133
        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 defaultReadRelationshipWithClosureHandler(
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
        $encParams = new EncodingParameters(
166
            $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
            $queryParser->hasFields() === true ? $queryParser->getFields() : null
168
        );
169
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
170
171
        $noData   = $relData === null || ($relData instanceof PaginatedDataInterface && $relData->getData() === null);
172
        $response = $noData === true ? $responses->getCodeResponse(404) : $responses->getContentResponse($relData);
173
174
        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 defaultReadRelationshipIdentifiersWithClosureHandler(
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
        $encParams = new EncodingParameters(
207
            $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
            $queryParser->hasFields() === true ? $queryParser->getFields() : null
209
        );
210
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
211
212
        $noData   = $relData === null || ($relData instanceof PaginatedDataInterface && $relData->getData() === null);
213
        $response = $noData === true ? $responses->getCodeResponse(404) : $responses->getIdentifiersResponse($relData);
214
215
        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 defaultCreateHandler(
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
        // some of the users want to reuse default `create` but have a custom part for responses
249
        // to meet this requirement it is split into two parts.
250 1
        $index = static::defaultCreate(
251 1
            $requestBody,
252 1
            $schemeClass,
253 1
            $schemeInfo,
254 1
            $validator,
255 1
            $crud,
256 1
            $errorFactory,
257 1
            $formatterFactory
258
        );
259
260 1
        return static::defaultCreateResponse($index, $requestUri, $crud, $provider, $jsonSchemes, $encoder);
261
    }
262
263
    /**
264
     * @param string                               $requestBody
265
     * @param string                               $schemeClass
266
     * @param ModelSchemeInfoInterface             $schemeInfo
267
     * @param JsonApiDataValidatingParserInterface $validator
268
     * @param CrudInterface                        $crud
269
     * @param FactoryInterface                     $errorFactory
270
     * @param FormatterFactoryInterface            $formatterFactory
271
     *
272
     * @return ResponseInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
273
     */
274 1
    protected static function defaultCreate(
275
        string $requestBody,
276
        string $schemeClass,
277
        ModelSchemeInfoInterface $schemeInfo,
278
        JsonApiDataValidatingParserInterface $validator,
279
        CrudInterface $crud,
280
        FactoryInterface $errorFactory,
281
        FormatterFactoryInterface $formatterFactory
282
    ): string {
283 1
        $jsonData = static::readJsonFromRequest($requestBody, $errorFactory, $formatterFactory);
284 1
        $captures = $validator->assert($jsonData)->getJsonApiCaptures();
285
286 1
        list ($index, $attributes, $toMany) = static::mapSchemeDataToModelData($captures, $schemeClass, $schemeInfo);
287
288 1
        $index = $crud->create($index, $attributes, $toMany);
289
290 1
        return $index;
291
    }
292
293
    /**
294
     * @param string                    $index
295
     * @param UriInterface              $requestUri
296
     * @param CrudInterface             $crud
297
     * @param SettingsProviderInterface $provider
298
     * @param JsonSchemesInterface      $jsonSchemes
299
     * @param EncoderInterface          $encoder
300
     *
301
     * @return ResponseInterface
302
     */
303 1
    protected static function defaultCreateResponse(
304
        string $index,
305
        UriInterface $requestUri,
306
        CrudInterface $crud,
307
        SettingsProviderInterface $provider,
308
        JsonSchemesInterface $jsonSchemes,
309
        EncoderInterface $encoder
310
    ): ResponseInterface {
311 1
        $model = $crud->read($index);
312
        assert($model !== null && !($model instanceof PaginatedDataInterface));
313
314
        $encParams = null;
315
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
316
        $response  = $responses->getCreatedResponse($model);
317
318
        return $response;
319
    }
320
321
    /** @noinspection PhpTooManyParametersInspection
322
     * @param string                               $index
323
     * @param UriInterface                         $requestUri
324
     * @param string                               $requestBody
325
     * @param string                               $schemeClass
326
     * @param ModelSchemeInfoInterface             $schemeInfo
327
     * @param JsonApiDataValidatingParserInterface $validator
328
     * @param CrudInterface                        $crud
329
     * @param SettingsProviderInterface            $provider
330
     * @param JsonSchemesInterface                 $jsonSchemes
331
     * @param EncoderInterface                     $encoder
332
     * @param FactoryInterface                     $errorFactory
333
     * @param FormatterFactoryInterface            $formatterFactory
334
     * @param string                               $messagesNamespace
335
     * @param string                               $errorMessage
336
     *
337
     * @return ResponseInterface
338
     *
339
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
340
     */
341 5
    protected static function defaultUpdateHandler(
342
        string $index,
343
        UriInterface $requestUri,
344
        string $requestBody,
345
        string $schemeClass,
346
        ModelSchemeInfoInterface $schemeInfo,
347
        JsonApiDataValidatingParserInterface $validator,
348
        CrudInterface $crud,
349
        SettingsProviderInterface $provider,
350
        JsonSchemesInterface $jsonSchemes,
351
        EncoderInterface $encoder,
352
        FactoryInterface $errorFactory,
353
        FormatterFactoryInterface $formatterFactory,
354
        string $messagesNamespace = S::GENERIC_NAMESPACE,
355
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
356
    ): ResponseInterface {
357
        // some of the users want to reuse default `update` but have a custom part for responses
358
        // to meet this requirement it is split into two parts.
359 5
        $updated = static::defaultUpdate(
360 5
            $index,
361 5
            $requestBody,
362 5
            $schemeClass,
363 5
            $schemeInfo,
364 5
            $validator,
365 5
            $crud,
366 5
            $errorFactory,
367 5
            $formatterFactory,
368 5
            $messagesNamespace,
369 5
            $errorMessage
370
        );
371
372 2
        return static::defaultUpdateResponse($updated, $index, $requestUri, $crud, $provider, $jsonSchemes, $encoder);
373
    }
374
375
    /** @noinspection PhpTooManyParametersInspection
376
     * @param string                               $index
377
     * @param string                               $requestBody
378
     * @param string                               $schemeClass
379
     * @param ModelSchemeInfoInterface             $schemeInfo
380
     * @param JsonApiDataValidatingParserInterface $validator
381
     * @param CrudInterface                        $crud
382
     * @param FactoryInterface                     $errorFactory
383
     * @param FormatterFactoryInterface            $formatterFactory
384
     * @param string                               $messagesNamespace
385
     * @param string                               $errorMessage
386
     *
387
     * @return int
388
     *
389
     * @SuppressWarnings(PHPMD.ElseExpression)
390
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
391
     */
392 5
    protected static function defaultUpdate(
393
        string $index,
394
        string $requestBody,
395
        string $schemeClass,
396
        ModelSchemeInfoInterface $schemeInfo,
397
        JsonApiDataValidatingParserInterface $validator,
398
        CrudInterface $crud,
399
        FactoryInterface $errorFactory,
400
        FormatterFactoryInterface $formatterFactory,
401
        string $messagesNamespace = S::GENERIC_NAMESPACE,
402
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
403
    ): int {
404 5
        $jsonData = static::readJsonFromRequest($requestBody, $errorFactory, $formatterFactory);
405
        // check that index in data and URL are identical
406 4
        $indexValue = $jsonData[DI::KEYWORD_DATA][DI::KEYWORD_ID] ?? null;
407 4
        if (empty($indexValue) === false) {
408 3
            if ($indexValue !== $index) {
409 1
                $errors    = $errorFactory->createErrorCollection();
410 1
                $formatter = $formatterFactory->createFormatter($messagesNamespace);
411 1
                $errors->addDataIdError($formatter->formatMessage($errorMessage));
412
413 3
                throw new JsonApiException($errors);
414
            }
415
        } else {
416
            // put the index to data for our convenience
417 1
            $jsonData[DI::KEYWORD_DATA][DI::KEYWORD_ID] = $index;
418
        }
419
        // validate the data
420 3
        $captures = $validator->assert($jsonData)->getJsonApiCaptures();
421
422 2
        list ($index, $attributes, $toMany) = static::mapSchemeDataToModelData($captures, $schemeClass, $schemeInfo);
423
424 2
        $updated = $crud->update($index, $attributes, $toMany);
425
426 2
        return $updated;
427
    }
428
429
    /**
430
     * @param int                       $updated
431
     * @param string                    $index
432
     * @param UriInterface              $requestUri
433
     * @param CrudInterface             $crud
434
     * @param SettingsProviderInterface $provider
435
     * @param JsonSchemesInterface      $jsonSchemes
436
     * @param EncoderInterface          $encoder
437
     *
438
     * @return ResponseInterface
439
     *
440
     * @SuppressWarnings(PHPMD.ElseExpression)
441
     */
442 2
    protected static function defaultUpdateResponse(
443
        int $updated,
444
        string $index,
445
        UriInterface $requestUri,
446
        CrudInterface $crud,
447
        SettingsProviderInterface $provider,
448
        JsonSchemesInterface $jsonSchemes,
449
        EncoderInterface $encoder
450
    ): ResponseInterface {
451 2
        $encParams = null;
452 2
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
453 2
        if ($updated > 0) {
454 1
            $model = $crud->read($index);
455
            assert($model !== null && !($model instanceof PaginatedDataInterface));
456
            $response = $responses->getContentResponse($model);
457
        } else {
458 1
            $response = $responses->getCodeResponse(404);
459
        }
460
461 1
        return $response;
462
    }
463
464
    /** @noinspection PhpTooManyParametersInspection
465
     * @param string                               $parentIndex
466
     * @param string                               $modelRelName
467
     * @param string                               $childIndex
468
     * @param UriInterface                         $requestUri
469
     * @param string                               $requestBody
470
     * @param string                               $childSchemeClass
471
     * @param ModelSchemeInfoInterface             $schemeInfo
472
     * @param JsonApiDataValidatingParserInterface $childValidator
473
     * @param CrudInterface                        $parentCrud
474
     * @param CrudInterface                        $childCrud
475
     * @param SettingsProviderInterface            $provider
476
     * @param JsonSchemesInterface                 $jsonSchemes
477
     * @param EncoderInterface                     $encoder
478
     * @param FactoryInterface                     $errorFactory
479
     * @param FormatterFactoryInterface            $formatterFactory
480
     * @param string                               $messagesNamespace
481
     * @param string                               $errorMessage
482
     *
483
     * @return ResponseInterface
484
     *
485
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
486
     */
487 2
    protected static function defaultUpdateInRelationshipHandler(
488
        string $parentIndex,
489
        string $modelRelName,
490
        string $childIndex,
491
        UriInterface $requestUri,
492
        string $requestBody,
493
        string $childSchemeClass,
494
        ModelSchemeInfoInterface $schemeInfo,
495
        JsonApiDataValidatingParserInterface $childValidator,
496
        CrudInterface $parentCrud,
497
        CrudInterface $childCrud,
498
        SettingsProviderInterface $provider,
499
        JsonSchemesInterface $jsonSchemes,
500
        EncoderInterface $encoder,
501
        FactoryInterface $errorFactory,
502
        FormatterFactoryInterface $formatterFactory,
503
        string $messagesNamespace = S::GENERIC_NAMESPACE,
504
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
505
    ): ResponseInterface {
506 2
        if ($parentCrud->hasInRelationship($parentIndex, $modelRelName, $childIndex) === true) {
507
            return static::defaultUpdateHandler(
508
                $childIndex,
509
                $requestUri,
510
                $requestBody,
511
                $childSchemeClass,
512
                $schemeInfo,
513
                $childValidator,
514
                $childCrud,
515
                $provider,
516
                $jsonSchemes,
517
                $encoder,
518
                $errorFactory,
519
                $formatterFactory,
520
                $messagesNamespace,
521
                $errorMessage
522
            );
523
        }
524
525 1
        $encParams = null;
526 1
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
527
528 1
        return $responses->getCodeResponse(404);
529
    }
530
531
    /**
532
     * @param string                    $index
533
     * @param UriInterface              $requestUri
534
     * @param CrudInterface             $crud
535
     * @param SettingsProviderInterface $provider
536
     * @param JsonSchemesInterface      $jsonSchemes
537
     * @param EncoderInterface          $encoder
538
     *
539
     * @return ResponseInterface
540
     */
541 1
    protected static function defaultDeleteHandler(
542
        string $index,
543
        UriInterface $requestUri,
544
        CrudInterface $crud,
545
        SettingsProviderInterface $provider,
546
        JsonSchemesInterface $jsonSchemes,
547
        EncoderInterface $encoder
548
    ): ResponseInterface {
549 1
        $crud->remove($index);
550
551 1
        $encParams = null;
552 1
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
553 1
        $response  = $responses->getCodeResponse(204);
554
555 1
        return $response;
556
    }
557
558
    /** @noinspection PhpTooManyParametersInspection
559
     * @param string                    $parentIndex
560
     * @param string                    $modelRelName
561
     * @param string                    $childIndex
562
     * @param UriInterface              $requestUri
563
     * @param CrudInterface             $parentCrud
564
     * @param CrudInterface             $childCrud
565
     * @param SettingsProviderInterface $provider
566
     * @param JsonSchemesInterface      $jsonSchemes
567
     * @param EncoderInterface          $encoder
568
     *
569
     * @return ResponseInterface
570
     */
571 1
    protected static function defaultDeleteInRelationshipHandler(
572
        string $parentIndex,
573
        string $modelRelName,
574
        string $childIndex,
575
        UriInterface $requestUri,
576
        CrudInterface $parentCrud,
577
        CrudInterface $childCrud,
578
        SettingsProviderInterface $provider,
579
        JsonSchemesInterface $jsonSchemes,
580
        EncoderInterface $encoder
581
    ): ResponseInterface {
582 1
        if ($parentCrud->hasInRelationship($parentIndex, $modelRelName, $childIndex) === true) {
583
            return static::defaultDeleteHandler(
584
                $childIndex,
585
                $requestUri,
586
                $childCrud,
587
                $provider,
588
                $jsonSchemes,
589
                $encoder
590
            );
591
        }
592
593
        $encParams = null;
594
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
595
596
        return $responses->getCodeResponse(404);
597
    }
598
599
    /**
600
     * @param ContainerInterface $container
601
     * @param string             $rulesClass
602
     *
603
     * @return JsonApiQueryValidatingParserInterface
604
     * @throws ContainerExceptionInterface
605
     * @throws NotFoundExceptionInterface
606
     */
607 16
    protected static function defaultCreateQueryParser(
608
        ContainerInterface $container,
609
        string $rulesClass = DefaultQueryValidationRules::class
610
    ): JsonApiQueryValidatingParserInterface {
611 16
        static::assertClassImplements($rulesClass, JsonApiQueryRulesInterface::class);
612
613
        /** @var JsonApiParserFactoryInterface $factory */
614 16
        $factory   = $container->get(JsonApiParserFactoryInterface::class);
615 16
        $validator = $factory->createQueryParser($rulesClass);
616
617 16
        return $validator;
618
    }
619
620
    /**
621
     * @param ContainerInterface $container
622
     * @param string             $rulesClass
623
     *
624
     * @return JsonApiDataValidatingParserInterface
625
     *
626
     * @throws ContainerExceptionInterface
627
     * @throws NotFoundExceptionInterface
628
     */
629 8
    protected static function defaultCreateDataParser(
630
        ContainerInterface $container,
631
        string $rulesClass
632
    ): JsonApiDataValidatingParserInterface {
633 8
        static::assertClassImplements($rulesClass, JsonApiDataRulesInterface::class);
634
635
        /** @var JsonApiParserFactoryInterface $factory */
636 8
        $factory   = $container->get(JsonApiParserFactoryInterface::class);
637 8
        $validator = $factory->createDataParser($rulesClass);
638
639 8
        return $validator;
640
    }
641
642
    /**
643
     * @param ContainerInterface $container
644
     * @param string             $schemaClass
645
     *
646
     * @return ParametersMapperInterface
647
     * @throws ContainerExceptionInterface
648
     * @throws NotFoundExceptionInterface
649
     */
650 16
    protected static function defaultCreateParameterMapper(
651
        ContainerInterface $container,
652
        string $schemaClass
653
    ): ParametersMapperInterface {
654 16
        static::assertClassImplements($schemaClass, SchemaInterface::class);
655
656
        /** @var SchemaInterface $schemaClass */
657 16
        $jsonResourceType = $schemaClass::TYPE;
658
659
        /** @var ParametersMapperInterface $mapper */
660 16
        $mapper = $container->get(ParametersMapperInterface::class);
661 16
        $mapper->selectRootSchemeByResourceType($jsonResourceType);
662
663 16
        return $mapper;
664
    }
665
666
    /**
667
     * @param ContainerInterface $container
668
     * @param string|null        $class
669
     *
670
     * @return CrudInterface
671
     *
672
     * @throws ContainerExceptionInterface
673
     * @throws NotFoundExceptionInterface
674
     */
675 26
    protected static function defaultCreateApi(ContainerInterface $container, string $class): CrudInterface
676
    {
677 26
        static::assertClassImplements($class, CrudInterface::class);
678
679
        /** @var FactoryInterface $factory */
680 26
        $factory = $container->get(FactoryInterface::class);
681 26
        $api     = $factory->createApi($class);
682
683 26
        return $api;
684
    }
685
686
    /**
687
     * @param UriInterface                     $requestUri
688
     * @param SettingsProviderInterface        $provider
689
     * @param JsonSchemesInterface             $jsonSchemes
690
     * @param EncoderInterface                 $encoder
691
     * @param EncodingParametersInterface|null $parameters
692
     *
693
     * @return ResponsesInterface
694
     */
695 4
    protected static function defaultCreateResponses(
696
        UriInterface $requestUri,
697
        SettingsProviderInterface $provider,
698
        JsonSchemesInterface $jsonSchemes,
699
        EncoderInterface $encoder,
700
        ?EncodingParametersInterface $parameters
701
    ): ResponsesInterface {
702 4
        $encoder->forOriginalUri($requestUri);
703 4
        $settings  = $provider->get(S::class);
704 4
        $responses = new Responses(
705 4
            new MediaType(MediaTypeInterface::JSON_API_TYPE, MediaTypeInterface::JSON_API_SUB_TYPE),
706 4
            $encoder,
707 4
            $jsonSchemes,
708 4
            $parameters,
709 4
            $settings[S::KEY_URI_PREFIX],
710 4
            $settings[S::KEY_META]
711
        );
712
713 4
        return $responses;
714
    }
715
716
    /**
717
     * @param array                    $captures
718
     * @param string                   $schemeClass
719
     * @param ModelSchemeInfoInterface $schemeInfo
720
     *
721
     * @return array
722
     */
723 3
    private static function mapSchemeDataToModelData(
724
        array $captures,
725
        string $schemeClass,
726
        ModelSchemeInfoInterface $schemeInfo
727
    ): array {
728 3
        static::assertClassImplements($schemeClass, SchemaInterface::class);
729
730
        /** @var SchemaInterface $schemeClass */
731 3
        static::assertClassImplements($modelClass = $schemeClass::MODEL, ModelInterface::class);
732
        /** @var ModelInterface $modelClass */
733
734 3
        $index         = null;
735 3
        $fields        = [];
736 3
        $toManyIndexes = [];
737 3
        foreach ($captures as $name => $value) {
738 3
            assert(is_string($name) === true);
739 3
            if ($name === DI::KEYWORD_ID) {
740 3
                $index = $value;
741 3
            } elseif ($schemeClass::hasAttributeMapping($name) === true) {
742 3
                $fieldName          = $schemeClass::getAttributeMapping($name);
743 3
                $fields[$fieldName] = $value;
744 3
            } elseif ($schemeClass::hasRelationshipMapping($name) === true) {
745 2
                $modelRelName = $schemeClass::getRelationshipMapping($name);
746 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...
747 2
                if ($relType === RelationshipTypes::BELONGS_TO) {
748 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...
749 2
                    $fields[$fkName] = $value;
750 2
                } elseif ($relType === RelationshipTypes::BELONGS_TO_MANY) {
751 3
                    $toManyIndexes[$modelRelName] = $value;
752
                }
753
            }
754
        }
755
756 3
        $result = [$index, $fields, $toManyIndexes];
757
758 3
        return $result;
759
    }
760
761
    /**
762
     * @param string                    $requestBody
763
     * @param FactoryInterface          $errorFactory
764
     * @param FormatterFactoryInterface $formatterFactory
765
     * @param string                    $messagesNamespace
766
     * @param string                    $errorMessage
767
     *
768
     * @return array
769
     */
770 6
    private static function readJsonFromRequest(
771
        string $requestBody,
772
        FactoryInterface $errorFactory,
773
        FormatterFactoryInterface $formatterFactory,
774
        string $messagesNamespace = S::GENERIC_NAMESPACE,
775
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
776
    ): array {
777 6
        if (empty($requestBody) === true || ($json = json_decode($requestBody, true)) === null) {
778 1
            $formatter = $formatterFactory->createFormatter($messagesNamespace);
779 1
            $errors    = $errorFactory->createErrorCollection();
780 1
            $errors->addDataError($formatter->formatMessage($errorMessage));
781
782 1
            throw new JsonApiException($errors);
783
        }
784
785 5
        return $json;
786
    }
787
788
    /**
789
     * @param null|string $value
790
     *
791
     * @return void
792
     */
793 26
    private static function assertClassValueDefined(?string $value): void
794
    {
795 26
        assert(empty($value) === false, 'Value should be defined in `' . static::class . '`.');
796
    }
797
798
    /**
799
     * @param string $class
800
     * @param string $interface
801
     *
802
     * @return void
803
     */
804 26
    private static function assertClassImplements(string $class, string $interface): void
805
    {
806 26
        assert(
807 26
            array_key_exists($interface, class_implements($class)) === true,
808 26
            "Class `$class` should implement `" . $interface . '` interface.'
809
        );
810
    }
811
}
812