Completed
Push — develop ( 5c2193...01cb9f )
by Neomerx
02:08
created

defaultCreateEncodingParameters()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 0
cts 4
cp 0
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 1
nop 1
crap 12
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 = self::defaultCreateEncodingParameters($queryParser);
86
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
87
        $response  = ($models->getData()) === null ?
88
            $responses->getCodeResponse(404) : $responses->getContentResponse($models);
89
90
        return $response;
91
    }
92
93
    /** @noinspection PhpTooManyParametersInspection
94
     * @param string                                $index
95
     * @param array                                 $queryParams
96
     * @param UriInterface                          $requestUri
97
     * @param JsonApiQueryValidatingParserInterface $queryParser
98
     * @param ParametersMapperInterface             $mapper
99
     * @param CrudInterface                         $crud
100
     * @param SettingsProviderInterface             $provider
101
     * @param JsonSchemesInterface                  $jsonSchemes
102
     * @param EncoderInterface                      $encoder
103
     *
104
     * @return ResponseInterface
105
     */
106 1
    protected static function defaultReadHandler(
107
        string $index,
108
        array $queryParams,
109
        UriInterface $requestUri,
110
        JsonApiQueryValidatingParserInterface $queryParser,
111
        ParametersMapperInterface $mapper,
112
        CrudInterface $crud,
113
        SettingsProviderInterface $provider,
114
        JsonSchemesInterface $jsonSchemes,
115
        EncoderInterface $encoder
116
    ): ResponseInterface {
117 1
        $queryParser->parse($queryParams);
118
119 1
        $model = $mapper->applyQueryParameters($queryParser, $crud)->read($index);
120
        assert(!($model instanceof PaginatedDataInterface));
121
122
        $encParams = self::defaultCreateEncodingParameters($queryParser);
123
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
124
        $response  = $model === null ?
125
            $responses->getCodeResponse(404) : $responses->getContentResponse($model);
126
127
        return $response;
128
    }
129
130
    /** @noinspection PhpTooManyParametersInspection
131
     * @param Closure                               $apiHandler
132
     * @param array                                 $queryParams
133
     * @param UriInterface                          $requestUri
134
     * @param JsonApiQueryValidatingParserInterface $queryParser
135
     * @param ParametersMapperInterface             $mapper
136
     * @param CrudInterface                         $crud
137
     * @param SettingsProviderInterface             $provider
138
     * @param JsonSchemesInterface                  $jsonSchemes
139
     * @param EncoderInterface                      $encoder
140
     *
141
     * @return ResponseInterface
142
     */
143 2
    protected static function defaultReadRelationshipWithClosureHandler(
144
        Closure $apiHandler,
145
        array $queryParams,
146
        UriInterface $requestUri,
147
        JsonApiQueryValidatingParserInterface $queryParser,
148
        ParametersMapperInterface $mapper,
149
        CrudInterface $crud,
150
        SettingsProviderInterface $provider,
151
        JsonSchemesInterface $jsonSchemes,
152
        EncoderInterface $encoder
153
    ): ResponseInterface {
154 2
        $queryParser->parse($queryParams);
155 2
        $mapper->applyQueryParameters($queryParser, $crud);
156
157 2
        $relData = call_user_func($apiHandler);
158
159
        $encParams = self::defaultCreateEncodingParameters($queryParser);
160
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
161
162
        $noData   = $relData === null || ($relData instanceof PaginatedDataInterface && $relData->getData() === null);
163
        $response = $noData === true ? $responses->getCodeResponse(404) : $responses->getContentResponse($relData);
164
165
        return $response;
166
    }
167
168
    /** @noinspection PhpTooManyParametersInspection
169
     * @param Closure                               $apiHandler
170
     * @param array                                 $queryParams
171
     * @param UriInterface                          $requestUri
172
     * @param JsonApiQueryValidatingParserInterface $queryParser
173
     * @param ParametersMapperInterface             $mapper
174
     * @param CrudInterface                         $crud
175
     * @param SettingsProviderInterface             $provider
176
     * @param JsonSchemesInterface                  $jsonSchemes
177
     * @param EncoderInterface                      $encoder
178
     *
179
     * @return ResponseInterface
180
     */
181 1
    protected static function defaultReadRelationshipIdentifiersWithClosureHandler(
182
        Closure $apiHandler,
183
        array $queryParams,
184
        UriInterface $requestUri,
185
        JsonApiQueryValidatingParserInterface $queryParser,
186
        ParametersMapperInterface $mapper,
187
        CrudInterface $crud,
188
        SettingsProviderInterface $provider,
189
        JsonSchemesInterface $jsonSchemes,
190
        EncoderInterface $encoder
191
    ): ResponseInterface {
192 1
        $queryParser->parse($queryParams);
193 1
        $mapper->applyQueryParameters($queryParser, $crud);
194
195 1
        $relData = call_user_func($apiHandler);
196
197
        $encParams = self::defaultCreateEncodingParameters($queryParser);
198
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
199
200
        $noData   = $relData === null || ($relData instanceof PaginatedDataInterface && $relData->getData() === null);
201
        $response = $noData === true ? $responses->getCodeResponse(404) : $responses->getIdentifiersResponse($relData);
202
203
        return $response;
204
    }
205
206
    /** @noinspection PhpTooManyParametersInspection
207
     * @param UriInterface                         $requestUri
208
     * @param string                               $requestBody
209
     * @param string                               $schemeClass
210
     * @param ModelSchemeInfoInterface             $schemeInfo
211
     * @param JsonApiDataValidatingParserInterface $validator
212
     * @param CrudInterface                        $crud
213
     * @param SettingsProviderInterface            $provider
214
     * @param JsonSchemesInterface                 $jsonSchemes
215
     * @param EncoderInterface                     $encoder
216
     * @param FactoryInterface                     $errorFactory
217
     * @param FormatterFactoryInterface            $formatterFactory
218
     *
219
     * @return ResponseInterface
220
     *
221
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
222
     */
223 1
    protected static function defaultCreateHandler(
224
        UriInterface $requestUri,
225
        string $requestBody,
226
        string $schemeClass,
227
        ModelSchemeInfoInterface $schemeInfo,
228
        JsonApiDataValidatingParserInterface $validator,
229
        CrudInterface $crud,
230
        SettingsProviderInterface $provider,
231
        JsonSchemesInterface $jsonSchemes,
232
        EncoderInterface $encoder,
233
        FactoryInterface $errorFactory,
234
        FormatterFactoryInterface $formatterFactory
235
    ): ResponseInterface {
236
        // some of the users want to reuse default `create` but have a custom part for responses
237
        // to meet this requirement it is split into two parts.
238 1
        $index = static::defaultCreate(
239 1
            $requestBody,
240 1
            $schemeClass,
241 1
            $schemeInfo,
242 1
            $validator,
243 1
            $crud,
244 1
            $errorFactory,
245 1
            $formatterFactory
246
        );
247
248 1
        return static::defaultCreateResponse($index, $requestUri, $crud, $provider, $jsonSchemes, $encoder);
249
    }
250
251
    /**
252
     * @param string                               $requestBody
253
     * @param string                               $schemeClass
254
     * @param ModelSchemeInfoInterface             $schemeInfo
255
     * @param JsonApiDataValidatingParserInterface $validator
256
     * @param CrudInterface                        $crud
257
     * @param FactoryInterface                     $errorFactory
258
     * @param FormatterFactoryInterface            $formatterFactory
259
     *
260
     * @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...
261
     */
262 1
    protected static function defaultCreate(
263
        string $requestBody,
264
        string $schemeClass,
265
        ModelSchemeInfoInterface $schemeInfo,
266
        JsonApiDataValidatingParserInterface $validator,
267
        CrudInterface $crud,
268
        FactoryInterface $errorFactory,
269
        FormatterFactoryInterface $formatterFactory
270
    ): string {
271 1
        $jsonData = static::readJsonFromRequest($requestBody, $errorFactory, $formatterFactory);
272 1
        $captures = $validator->assert($jsonData)->getJsonApiCaptures();
273
274 1
        list ($index, $attributes, $toMany) = static::mapSchemeDataToModelData($captures, $schemeClass, $schemeInfo);
275
276 1
        $index = $crud->create($index, $attributes, $toMany);
277
278 1
        return $index;
279
    }
280
281
    /**
282
     * @param string                    $index
283
     * @param UriInterface              $requestUri
284
     * @param CrudInterface             $crud
285
     * @param SettingsProviderInterface $provider
286
     * @param JsonSchemesInterface      $jsonSchemes
287
     * @param EncoderInterface          $encoder
288
     *
289
     * @return ResponseInterface
290
     */
291 1
    protected static function defaultCreateResponse(
292
        string $index,
293
        UriInterface $requestUri,
294
        CrudInterface $crud,
295
        SettingsProviderInterface $provider,
296
        JsonSchemesInterface $jsonSchemes,
297
        EncoderInterface $encoder
298
    ): ResponseInterface {
299 1
        $model = $crud->read($index);
300
        assert($model !== null && !($model instanceof PaginatedDataInterface));
301
302
        $encParams = null;
303
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
304
        $response  = $responses->getCreatedResponse($model);
305
306
        return $response;
307
    }
308
309
    /** @noinspection PhpTooManyParametersInspection
310
     * @param string                               $index
311
     * @param UriInterface                         $requestUri
312
     * @param string                               $requestBody
313
     * @param string                               $schemeClass
314
     * @param ModelSchemeInfoInterface             $schemeInfo
315
     * @param JsonApiDataValidatingParserInterface $validator
316
     * @param CrudInterface                        $crud
317
     * @param SettingsProviderInterface            $provider
318
     * @param JsonSchemesInterface                 $jsonSchemes
319
     * @param EncoderInterface                     $encoder
320
     * @param FactoryInterface                     $errorFactory
321
     * @param FormatterFactoryInterface            $formatterFactory
322
     * @param string                               $messagesNamespace
323
     * @param string                               $errorMessage
324
     *
325
     * @return ResponseInterface
326
     *
327
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
328
     */
329 5
    protected static function defaultUpdateHandler(
330
        string $index,
331
        UriInterface $requestUri,
332
        string $requestBody,
333
        string $schemeClass,
334
        ModelSchemeInfoInterface $schemeInfo,
335
        JsonApiDataValidatingParserInterface $validator,
336
        CrudInterface $crud,
337
        SettingsProviderInterface $provider,
338
        JsonSchemesInterface $jsonSchemes,
339
        EncoderInterface $encoder,
340
        FactoryInterface $errorFactory,
341
        FormatterFactoryInterface $formatterFactory,
342
        string $messagesNamespace = S::GENERIC_NAMESPACE,
343
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
344
    ): ResponseInterface {
345
        // some of the users want to reuse default `update` but have a custom part for responses
346
        // to meet this requirement it is split into two parts.
347 5
        $updated = static::defaultUpdate(
348 5
            $index,
349 5
            $requestBody,
350 5
            $schemeClass,
351 5
            $schemeInfo,
352 5
            $validator,
353 5
            $crud,
354 5
            $errorFactory,
355 5
            $formatterFactory,
356 5
            $messagesNamespace,
357 5
            $errorMessage
358
        );
359
360 2
        return static::defaultUpdateResponse($updated, $index, $requestUri, $crud, $provider, $jsonSchemes, $encoder);
361
    }
362
363
    /** @noinspection PhpTooManyParametersInspection
364
     * @param string                               $index
365
     * @param string                               $requestBody
366
     * @param string                               $schemeClass
367
     * @param ModelSchemeInfoInterface             $schemeInfo
368
     * @param JsonApiDataValidatingParserInterface $validator
369
     * @param CrudInterface                        $crud
370
     * @param FactoryInterface                     $errorFactory
371
     * @param FormatterFactoryInterface            $formatterFactory
372
     * @param string                               $messagesNamespace
373
     * @param string                               $errorMessage
374
     *
375
     * @return int
376
     *
377
     * @SuppressWarnings(PHPMD.ElseExpression)
378
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
379
     */
380 5
    protected static function defaultUpdate(
381
        string $index,
382
        string $requestBody,
383
        string $schemeClass,
384
        ModelSchemeInfoInterface $schemeInfo,
385
        JsonApiDataValidatingParserInterface $validator,
386
        CrudInterface $crud,
387
        FactoryInterface $errorFactory,
388
        FormatterFactoryInterface $formatterFactory,
389
        string $messagesNamespace = S::GENERIC_NAMESPACE,
390
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
391
    ): int {
392 5
        $jsonData = static::readJsonFromRequest($requestBody, $errorFactory, $formatterFactory);
393
        // check that index in data and URL are identical
394 4
        $indexValue = $jsonData[DI::KEYWORD_DATA][DI::KEYWORD_ID] ?? null;
395 4
        if (empty($indexValue) === false) {
396 3
            if ($indexValue !== $index) {
397 1
                $errors    = $errorFactory->createErrorCollection();
398 1
                $formatter = $formatterFactory->createFormatter($messagesNamespace);
399 1
                $errors->addDataIdError($formatter->formatMessage($errorMessage));
400
401 3
                throw new JsonApiException($errors);
402
            }
403
        } else {
404
            // put the index to data for our convenience
405 1
            $jsonData[DI::KEYWORD_DATA][DI::KEYWORD_ID] = $index;
406
        }
407
        // validate the data
408 3
        $captures = $validator->assert($jsonData)->getJsonApiCaptures();
409
410 2
        list ($index, $attributes, $toMany) = static::mapSchemeDataToModelData($captures, $schemeClass, $schemeInfo);
411
412 2
        $updated = $crud->update($index, $attributes, $toMany);
413
414 2
        return $updated;
415
    }
416
417
    /**
418
     * @param int                       $updated
419
     * @param string                    $index
420
     * @param UriInterface              $requestUri
421
     * @param CrudInterface             $crud
422
     * @param SettingsProviderInterface $provider
423
     * @param JsonSchemesInterface      $jsonSchemes
424
     * @param EncoderInterface          $encoder
425
     *
426
     * @return ResponseInterface
427
     *
428
     * @SuppressWarnings(PHPMD.ElseExpression)
429
     */
430 2
    protected static function defaultUpdateResponse(
431
        int $updated,
432
        string $index,
433
        UriInterface $requestUri,
434
        CrudInterface $crud,
435
        SettingsProviderInterface $provider,
436
        JsonSchemesInterface $jsonSchemes,
437
        EncoderInterface $encoder
438
    ): ResponseInterface {
439 2
        $encParams = null;
440 2
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
441 2
        if ($updated > 0) {
442 1
            $model = $crud->read($index);
443
            assert($model !== null && !($model instanceof PaginatedDataInterface));
444
            $response = $responses->getContentResponse($model);
445
        } else {
446 1
            $response = $responses->getCodeResponse(404);
447
        }
448
449 1
        return $response;
450
    }
451
452
    /** @noinspection PhpTooManyParametersInspection
453
     * @param string                               $parentIndex
454
     * @param string                               $modelRelName
455
     * @param string                               $childIndex
456
     * @param UriInterface                         $requestUri
457
     * @param string                               $requestBody
458
     * @param string                               $childSchemeClass
459
     * @param ModelSchemeInfoInterface             $schemeInfo
460
     * @param JsonApiDataValidatingParserInterface $childValidator
461
     * @param CrudInterface                        $parentCrud
462
     * @param CrudInterface                        $childCrud
463
     * @param SettingsProviderInterface            $provider
464
     * @param JsonSchemesInterface                 $jsonSchemes
465
     * @param EncoderInterface                     $encoder
466
     * @param FactoryInterface                     $errorFactory
467
     * @param FormatterFactoryInterface            $formatterFactory
468
     * @param string                               $messagesNamespace
469
     * @param string                               $errorMessage
470
     *
471
     * @return ResponseInterface
472
     *
473
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
474
     */
475 2
    protected static function defaultUpdateInRelationshipHandler(
476
        string $parentIndex,
477
        string $modelRelName,
478
        string $childIndex,
479
        UriInterface $requestUri,
480
        string $requestBody,
481
        string $childSchemeClass,
482
        ModelSchemeInfoInterface $schemeInfo,
483
        JsonApiDataValidatingParserInterface $childValidator,
484
        CrudInterface $parentCrud,
485
        CrudInterface $childCrud,
486
        SettingsProviderInterface $provider,
487
        JsonSchemesInterface $jsonSchemes,
488
        EncoderInterface $encoder,
489
        FactoryInterface $errorFactory,
490
        FormatterFactoryInterface $formatterFactory,
491
        string $messagesNamespace = S::GENERIC_NAMESPACE,
492
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
493
    ): ResponseInterface {
494 2
        if ($parentCrud->hasInRelationship($parentIndex, $modelRelName, $childIndex) === true) {
495
            return static::defaultUpdateHandler(
496
                $childIndex,
497
                $requestUri,
498
                $requestBody,
499
                $childSchemeClass,
500
                $schemeInfo,
501
                $childValidator,
502
                $childCrud,
503
                $provider,
504
                $jsonSchemes,
505
                $encoder,
506
                $errorFactory,
507
                $formatterFactory,
508
                $messagesNamespace,
509
                $errorMessage
510
            );
511
        }
512
513 1
        $encParams = null;
514 1
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
515
516 1
        return $responses->getCodeResponse(404);
517
    }
518
519
    /**
520
     * @param string                    $index
521
     * @param UriInterface              $requestUri
522
     * @param CrudInterface             $crud
523
     * @param SettingsProviderInterface $provider
524
     * @param JsonSchemesInterface      $jsonSchemes
525
     * @param EncoderInterface          $encoder
526
     *
527
     * @return ResponseInterface
528
     */
529 1
    protected static function defaultDeleteHandler(
530
        string $index,
531
        UriInterface $requestUri,
532
        CrudInterface $crud,
533
        SettingsProviderInterface $provider,
534
        JsonSchemesInterface $jsonSchemes,
535
        EncoderInterface $encoder
536
    ): ResponseInterface {
537 1
        $crud->remove($index);
538
539 1
        $encParams = null;
540 1
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
541 1
        $response  = $responses->getCodeResponse(204);
542
543 1
        return $response;
544
    }
545
546
    /** @noinspection PhpTooManyParametersInspection
547
     * @param string                    $parentIndex
548
     * @param string                    $modelRelName
549
     * @param string                    $childIndex
550
     * @param UriInterface              $requestUri
551
     * @param CrudInterface             $parentCrud
552
     * @param CrudInterface             $childCrud
553
     * @param SettingsProviderInterface $provider
554
     * @param JsonSchemesInterface      $jsonSchemes
555
     * @param EncoderInterface          $encoder
556
     *
557
     * @return ResponseInterface
558
     */
559 1
    protected static function defaultDeleteInRelationshipHandler(
560
        string $parentIndex,
561
        string $modelRelName,
562
        string $childIndex,
563
        UriInterface $requestUri,
564
        CrudInterface $parentCrud,
565
        CrudInterface $childCrud,
566
        SettingsProviderInterface $provider,
567
        JsonSchemesInterface $jsonSchemes,
568
        EncoderInterface $encoder
569
    ): ResponseInterface {
570 1
        if ($parentCrud->hasInRelationship($parentIndex, $modelRelName, $childIndex) === true) {
571
            return static::defaultDeleteHandler(
572
                $childIndex,
573
                $requestUri,
574
                $childCrud,
575
                $provider,
576
                $jsonSchemes,
577
                $encoder
578
            );
579
        }
580
581
        $encParams = null;
582
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemes, $encoder, $encParams);
583
584
        return $responses->getCodeResponse(404);
585
    }
586
587
    /**
588
     * @param ContainerInterface $container
589
     * @param string             $rulesClass
590
     *
591
     * @return JsonApiQueryValidatingParserInterface
592
     * @throws ContainerExceptionInterface
593
     * @throws NotFoundExceptionInterface
594
     */
595 16
    protected static function defaultCreateQueryParser(
596
        ContainerInterface $container,
597
        string $rulesClass = DefaultQueryValidationRules::class
598
    ): JsonApiQueryValidatingParserInterface {
599 16
        static::assertClassImplements($rulesClass, JsonApiQueryRulesInterface::class);
600
601
        /** @var JsonApiParserFactoryInterface $factory */
602 16
        $factory   = $container->get(JsonApiParserFactoryInterface::class);
603 16
        $validator = $factory->createQueryParser($rulesClass);
604
605 16
        return $validator;
606
    }
607
608
    /**
609
     * @param ContainerInterface $container
610
     * @param string             $rulesClass
611
     *
612
     * @return JsonApiDataValidatingParserInterface
613
     *
614
     * @throws ContainerExceptionInterface
615
     * @throws NotFoundExceptionInterface
616
     */
617 8
    protected static function defaultCreateDataParser(
618
        ContainerInterface $container,
619
        string $rulesClass
620
    ): JsonApiDataValidatingParserInterface {
621 8
        static::assertClassImplements($rulesClass, JsonApiDataRulesInterface::class);
622
623
        /** @var JsonApiParserFactoryInterface $factory */
624 8
        $factory   = $container->get(JsonApiParserFactoryInterface::class);
625 8
        $validator = $factory->createDataParser($rulesClass);
626
627 8
        return $validator;
628
    }
629
630
    /**
631
     * @param ContainerInterface $container
632
     * @param string             $schemaClass
633
     *
634
     * @return ParametersMapperInterface
635
     * @throws ContainerExceptionInterface
636
     * @throws NotFoundExceptionInterface
637
     */
638 16
    protected static function defaultCreateParameterMapper(
639
        ContainerInterface $container,
640
        string $schemaClass
641
    ): ParametersMapperInterface {
642 16
        static::assertClassImplements($schemaClass, SchemaInterface::class);
643
644
        /** @var SchemaInterface $schemaClass */
645 16
        $jsonResourceType = $schemaClass::TYPE;
646
647
        /** @var ParametersMapperInterface $mapper */
648 16
        $mapper = $container->get(ParametersMapperInterface::class);
649 16
        $mapper->selectRootSchemeByResourceType($jsonResourceType);
650
651 16
        return $mapper;
652
    }
653
654
    /**
655
     * @param JsonApiQueryValidatingParserInterface $queryParser
656
     *
657
     * @return EncodingParametersInterface
658
     */
659
    protected static function defaultCreateEncodingParameters(
660
        JsonApiQueryValidatingParserInterface $queryParser
661
    ): EncodingParametersInterface {
662
        return new EncodingParameters(
663
            $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...
664
            $queryParser->hasFields() === true ? $queryParser->getFields() : null
665
        );
666
    }
667
668
    /**
669
     * @param ContainerInterface $container
670
     * @param string|null        $class
671
     *
672
     * @return CrudInterface
673
     *
674
     * @throws ContainerExceptionInterface
675
     * @throws NotFoundExceptionInterface
676
     */
677 26
    protected static function defaultCreateApi(ContainerInterface $container, string $class): CrudInterface
678
    {
679 26
        static::assertClassImplements($class, CrudInterface::class);
680
681
        /** @var FactoryInterface $factory */
682 26
        $factory = $container->get(FactoryInterface::class);
683 26
        $api     = $factory->createApi($class);
684
685 26
        return $api;
686
    }
687
688
    /**
689
     * @param UriInterface                     $requestUri
690
     * @param SettingsProviderInterface        $provider
691
     * @param JsonSchemesInterface             $jsonSchemes
692
     * @param EncoderInterface                 $encoder
693
     * @param EncodingParametersInterface|null $parameters
694
     *
695
     * @return ResponsesInterface
696
     */
697 4
    protected static function defaultCreateResponses(
698
        UriInterface $requestUri,
699
        SettingsProviderInterface $provider,
700
        JsonSchemesInterface $jsonSchemes,
701
        EncoderInterface $encoder,
702
        ?EncodingParametersInterface $parameters
703
    ): ResponsesInterface {
704 4
        $encoder->forOriginalUri($requestUri);
705 4
        $settings  = $provider->get(S::class);
706 4
        $responses = new Responses(
707 4
            new MediaType(MediaTypeInterface::JSON_API_TYPE, MediaTypeInterface::JSON_API_SUB_TYPE),
708 4
            $encoder,
709 4
            $jsonSchemes,
710 4
            $parameters,
711 4
            $settings[S::KEY_URI_PREFIX],
712 4
            $settings[S::KEY_META]
713
        );
714
715 4
        return $responses;
716
    }
717
718
    /**
719
     * Developers can override the method in order to add/remove some data for `create`/`update` inputs.
720
     *
721
     * @param string                    $requestBody
722
     * @param FactoryInterface          $errorFactory
723
     * @param FormatterFactoryInterface $formatterFactory
724
     * @param string                    $messagesNamespace
725
     * @param string                    $errorMessage
726
     *
727
     * @return array
728
     */
729 6
    protected static function readJsonFromRequest(
730
        string $requestBody,
731
        FactoryInterface $errorFactory,
732
        FormatterFactoryInterface $formatterFactory,
733
        string $messagesNamespace = S::GENERIC_NAMESPACE,
734
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
735
    ): array {
736 6
        if (empty($requestBody) === true || ($json = json_decode($requestBody, true)) === null) {
737 1
            $formatter = $formatterFactory->createFormatter($messagesNamespace);
738 1
            $errors    = $errorFactory->createErrorCollection();
739 1
            $errors->addDataError($formatter->formatMessage($errorMessage));
740
741 1
            throw new JsonApiException($errors);
742
        }
743
744 5
        return $json;
745
    }
746
747
    /**
748
     * Developers can override the method in order to use custom data mapping from a Schema to Model.
749
     *
750
     * @param array                    $captures
751
     * @param string                   $schemeClass
752
     * @param ModelSchemeInfoInterface $schemeInfo
753
     *
754
     * @return array
755
     */
756 3
    protected static function mapSchemeDataToModelData(
757
        array $captures,
758
        string $schemeClass,
759
        ModelSchemeInfoInterface $schemeInfo
760
    ): array {
761 3
        static::assertClassImplements($schemeClass, SchemaInterface::class);
762
763
        /** @var SchemaInterface $schemeClass */
764 3
        static::assertClassImplements($modelClass = $schemeClass::MODEL, ModelInterface::class);
765
        /** @var ModelInterface $modelClass */
766
767 3
        $index         = null;
768 3
        $fields        = [];
769 3
        $toManyIndexes = [];
770 3
        foreach ($captures as $name => $value) {
771 3
            assert(is_string($name) === true);
772 3
            if ($name === DI::KEYWORD_ID) {
773 3
                $index = $value;
774 3
            } elseif ($schemeClass::hasAttributeMapping($name) === true) {
775 3
                $fieldName          = $schemeClass::getAttributeMapping($name);
776 3
                $fields[$fieldName] = $value;
777 3
            } elseif ($schemeClass::hasRelationshipMapping($name) === true) {
778 2
                $modelRelName = $schemeClass::getRelationshipMapping($name);
779 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...
780 2
                if ($relType === RelationshipTypes::BELONGS_TO) {
781 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...
782 2
                    $fields[$fkName] = $value;
783 2
                } elseif ($relType === RelationshipTypes::BELONGS_TO_MANY) {
784 3
                    $toManyIndexes[$modelRelName] = $value;
785
                }
786
            }
787
        }
788
789 3
        $result = [$index, $fields, $toManyIndexes];
790
791 3
        return $result;
792
    }
793
794
    /**
795
     * @param null|string $value
796
     *
797
     * @return void
798
     */
799 26
    private static function assertClassValueDefined(?string $value): void
800
    {
801 26
        assert(empty($value) === false, 'Value should be defined in `' . static::class . '`.');
802
    }
803
804
    /**
805
     * @param string $class
806
     * @param string $interface
807
     *
808
     * @return void
809
     */
810 26
    private static function assertClassImplements(string $class, string $interface): void
811
    {
812 26
        assert(
813 26
            array_key_exists($interface, class_implements($class)) === true,
814 26
            "Class `$class` should implement `" . $interface . '` interface.'
815
        );
816
    }
817
}
818