Completed
Push — develop ( 46135c...90e0de )
by Neomerx
03:10
created

mapSchemeDataToModelData()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 37
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 6.7272
c 0
b 0
f 0
ccs 23
cts 23
cp 1
cc 7
eloc 27
nc 7
nop 3
crap 7
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\ModelSchemaInfoInterface;
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\JsonSchemasInterface;
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 JsonSchemasInterface                  $jsonSchemas
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
        JsonSchemasInterface $jsonSchemas,
79
        EncoderInterface $encoder
80
    ): ResponseInterface {
81 12
        $queryParser->parse($queryParams);
82
83 11
        $models = $mapper->applyQueryParameters($queryParser, $crud)->index();
84
85 10
        $encParams = self::defaultCreateEncodingParameters($queryParser);
86 10
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemas, $encoder, $encParams);
87 10
        $response  = ($models->getData()) === null ?
88 10
            $responses->getCodeResponse(404) : $responses->getContentResponse($models);
89
90 10
        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 JsonSchemasInterface                  $jsonSchemas
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
        JsonSchemasInterface $jsonSchemas,
115
        EncoderInterface $encoder
116
    ): ResponseInterface {
117 1
        $queryParser->parse($queryParams);
118
119 1
        $model = $mapper->applyQueryParameters($queryParser, $crud)->read($index);
120 1
        assert(!($model instanceof PaginatedDataInterface));
121
122 1
        $encParams = self::defaultCreateEncodingParameters($queryParser);
123 1
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemas, $encoder, $encParams);
124 1
        $response  = $model === null ?
125 1
            $responses->getCodeResponse(404) : $responses->getContentResponse($model);
126
127 1
        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 JsonSchemasInterface                  $jsonSchemas
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
        JsonSchemasInterface $jsonSchemas,
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 2
        $encParams = self::defaultCreateEncodingParameters($queryParser);
160 2
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemas, $encoder, $encParams);
161
162 2
        $noData   = $relData === null || ($relData instanceof PaginatedDataInterface && $relData->getData() === null);
163 2
        $response = $noData === true ? $responses->getCodeResponse(404) : $responses->getContentResponse($relData);
164
165 2
        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 JsonSchemasInterface                  $jsonSchemas
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
        JsonSchemasInterface $jsonSchemas,
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 1
        $encParams = self::defaultCreateEncodingParameters($queryParser);
198 1
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemas, $encoder, $encParams);
199
200 1
        $noData   = $relData === null || ($relData instanceof PaginatedDataInterface && $relData->getData() === null);
201 1
        $response = $noData === true ? $responses->getCodeResponse(404) : $responses->getIdentifiersResponse($relData);
202
203 1
        return $response;
204
    }
205
206
    /** @noinspection PhpTooManyParametersInspection
207
     * @param UriInterface                         $requestUri
208
     * @param string                               $requestBody
209
     * @param string                               $schemaClass
210
     * @param ModelSchemaInfoInterface             $schemaInfo
211
     * @param JsonApiDataValidatingParserInterface $validator
212
     * @param CrudInterface                        $crud
213
     * @param SettingsProviderInterface            $provider
214
     * @param JsonSchemasInterface                 $jsonSchemas
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 $schemaClass,
227
        ModelSchemaInfoInterface $schemaInfo,
228
        JsonApiDataValidatingParserInterface $validator,
229
        CrudInterface $crud,
230
        SettingsProviderInterface $provider,
231
        JsonSchemasInterface $jsonSchemas,
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
            $schemaClass,
241 1
            $schemaInfo,
242 1
            $validator,
243 1
            $crud,
244 1
            $errorFactory,
245 1
            $formatterFactory
246
        );
247
248 1
        return static::defaultCreateResponse($index, $requestUri, $crud, $provider, $jsonSchemas, $encoder);
249
    }
250
251
    /**
252
     * @param string                               $requestBody
253
     * @param string                               $schemaClass
254
     * @param ModelSchemaInfoInterface             $schemaInfo
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 $schemaClass,
265
        ModelSchemaInfoInterface $schemaInfo,
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::mapSchemaDataToModelData($captures, $schemaClass, $schemaInfo);
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 JsonSchemasInterface      $jsonSchemas
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
        JsonSchemasInterface $jsonSchemas,
297
        EncoderInterface $encoder
298
    ): ResponseInterface {
299 1
        $model = $crud->read($index);
300 1
        assert($model !== null && !($model instanceof PaginatedDataInterface));
301
302 1
        $encParams = null;
303 1
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemas, $encoder, $encParams);
304 1
        $response  = $responses->getCreatedResponse($model);
305
306 1
        return $response;
307
    }
308
309
    /** @noinspection PhpTooManyParametersInspection
310
     * @param string                               $index
311
     * @param UriInterface                         $requestUri
312
     * @param string                               $requestBody
313
     * @param string                               $schemaClass
314
     * @param ModelSchemaInfoInterface             $schemaInfo
315
     * @param JsonApiDataValidatingParserInterface $validator
316
     * @param CrudInterface                        $crud
317
     * @param SettingsProviderInterface            $provider
318
     * @param JsonSchemasInterface                 $jsonSchemas
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 6
    protected static function defaultUpdateHandler(
330
        string $index,
331
        UriInterface $requestUri,
332
        string $requestBody,
333
        string $schemaClass,
334
        ModelSchemaInfoInterface $schemaInfo,
335
        JsonApiDataValidatingParserInterface $validator,
336
        CrudInterface $crud,
337
        SettingsProviderInterface $provider,
338
        JsonSchemasInterface $jsonSchemas,
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 6
        $updated = static::defaultUpdate(
348 6
            $index,
349 6
            $requestBody,
350 6
            $schemaClass,
351 6
            $schemaInfo,
352 6
            $validator,
353 6
            $crud,
354 6
            $errorFactory,
355 6
            $formatterFactory,
356 6
            $messagesNamespace,
357 6
            $errorMessage
358
        );
359
360 3
        return static::defaultUpdateResponse($updated, $index, $requestUri, $crud, $provider, $jsonSchemas, $encoder);
361
    }
362
363
    /** @noinspection PhpTooManyParametersInspection
364
     * @param string                               $index
365
     * @param string                               $requestBody
366
     * @param string                               $schemaClass
367
     * @param ModelSchemaInfoInterface             $schemaInfo
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 6
    protected static function defaultUpdate(
381
        string $index,
382
        string $requestBody,
383
        string $schemaClass,
384
        ModelSchemaInfoInterface $schemaInfo,
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 6
        $jsonData = static::readJsonFromRequest($requestBody, $errorFactory, $formatterFactory);
393
        // check that index in data and URL are identical
394 5
        $indexValue = $jsonData[DI::KEYWORD_DATA][DI::KEYWORD_ID] ?? null;
395 5
        if (empty($indexValue) === false) {
396 4
            if ($indexValue !== $index) {
397 1
                $errors    = $errorFactory->createErrorCollection();
398 1
                $formatter = $formatterFactory->createFormatter($messagesNamespace);
399 1
                $errors->addDataIdError($formatter->formatMessage($errorMessage));
400
401 4
                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 4
        $captures = $validator->assert($jsonData)->getJsonApiCaptures();
409
410 3
        list ($index, $attributes, $toMany) = static::mapSchemaDataToModelData($captures, $schemaClass, $schemaInfo);
411
412 3
        $updated = $crud->update($index, $attributes, $toMany);
413
414 3
        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 JsonSchemasInterface      $jsonSchemas
424
     * @param EncoderInterface          $encoder
425
     *
426
     * @return ResponseInterface
427
     *
428
     * @SuppressWarnings(PHPMD.ElseExpression)
429
     */
430 3
    protected static function defaultUpdateResponse(
431
        int $updated,
432
        string $index,
433
        UriInterface $requestUri,
434
        CrudInterface $crud,
435
        SettingsProviderInterface $provider,
436
        JsonSchemasInterface $jsonSchemas,
437
        EncoderInterface $encoder
438
    ): ResponseInterface {
439 3
        $encParams = null;
440 3
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemas, $encoder, $encParams);
441 3
        if ($updated > 0) {
442 2
            $model = $crud->read($index);
443 2
            assert($model !== null && !($model instanceof PaginatedDataInterface));
444 2
            $response = $responses->getContentResponse($model);
445
        } else {
446 1
            $response = $responses->getCodeResponse(404);
447
        }
448
449 3
        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                               $childSchemaClass
459
     * @param ModelSchemaInfoInterface             $schemaInfo
460
     * @param JsonApiDataValidatingParserInterface $childValidator
461
     * @param CrudInterface                        $parentCrud
462
     * @param CrudInterface                        $childCrud
463
     * @param SettingsProviderInterface            $provider
464
     * @param JsonSchemasInterface                 $jsonSchemas
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 $childSchemaClass,
482
        ModelSchemaInfoInterface $schemaInfo,
483
        JsonApiDataValidatingParserInterface $childValidator,
484
        CrudInterface $parentCrud,
485
        CrudInterface $childCrud,
486
        SettingsProviderInterface $provider,
487
        JsonSchemasInterface $jsonSchemas,
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 1
            return static::defaultUpdateHandler(
496 1
                $childIndex,
497 1
                $requestUri,
498 1
                $requestBody,
499 1
                $childSchemaClass,
500 1
                $schemaInfo,
501 1
                $childValidator,
502 1
                $childCrud,
503 1
                $provider,
504 1
                $jsonSchemas,
505 1
                $encoder,
506 1
                $errorFactory,
507 1
                $formatterFactory,
508 1
                $messagesNamespace,
509 1
                $errorMessage
510
            );
511
        }
512
513 1
        $encParams = null;
514 1
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemas, $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 JsonSchemasInterface      $jsonSchemas
525
     * @param EncoderInterface          $encoder
526
     *
527
     * @return ResponseInterface
528
     */
529 2
    protected static function defaultDeleteHandler(
530
        string $index,
531
        UriInterface $requestUri,
532
        CrudInterface $crud,
533
        SettingsProviderInterface $provider,
534
        JsonSchemasInterface $jsonSchemas,
535
        EncoderInterface $encoder
536
    ): ResponseInterface {
537 2
        $crud->remove($index);
538
539 2
        $encParams = null;
540 2
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemas, $encoder, $encParams);
541 2
        $response  = $responses->getCodeResponse(204);
542
543 2
        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 JsonSchemasInterface      $jsonSchemas
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
        JsonSchemasInterface $jsonSchemas,
568
        EncoderInterface $encoder
569
    ): ResponseInterface {
570 1
        if ($parentCrud->hasInRelationship($parentIndex, $modelRelName, $childIndex) === true) {
571 1
            return static::defaultDeleteHandler(
572 1
                $childIndex,
573 1
                $requestUri,
574 1
                $childCrud,
575 1
                $provider,
576 1
                $jsonSchemas,
577 1
                $encoder
578
            );
579
        }
580
581 1
        $encParams = null;
582 1
        $responses = static::defaultCreateResponses($requestUri, $provider, $jsonSchemas, $encoder, $encParams);
583
584 1
        return $responses->getCodeResponse(404);
585
    }
586
587
    /**
588
     * @param ContainerInterface $container
589
     * @param string             $rulesClass
590
     *
591
     * @return JsonApiQueryValidatingParserInterface
592
     *
593
     * @throws ContainerExceptionInterface
594
     * @throws NotFoundExceptionInterface
595 16
     */
596
    protected static function defaultCreateQueryParser(
597
        ContainerInterface $container,
598
        string $rulesClass = DefaultQueryValidationRules::class
599 16
    ): JsonApiQueryValidatingParserInterface {
600
        static::assertClassImplements($rulesClass, JsonApiQueryRulesInterface::class);
601
602 16
        /** @var JsonApiParserFactoryInterface $factory */
603 16
        $factory   = $container->get(JsonApiParserFactoryInterface::class);
604
        $validator = $factory->createQueryParser($rulesClass);
605 16
606
        return $validator;
607
    }
608
609
    /**
610
     * @param ContainerInterface $container
611
     * @param string             $rulesClass
612
     *
613
     * @return JsonApiDataValidatingParserInterface
614
     *
615
     * @throws ContainerExceptionInterface
616
     * @throws NotFoundExceptionInterface
617 8
     */
618
    protected static function defaultCreateDataParser(
619
        ContainerInterface $container,
620
        string $rulesClass
621 8
    ): JsonApiDataValidatingParserInterface {
622
        static::assertClassImplements($rulesClass, JsonApiDataRulesInterface::class);
623
624 8
        /** @var JsonApiParserFactoryInterface $factory */
625 8
        $factory   = $container->get(JsonApiParserFactoryInterface::class);
626
        $validator = $factory->createDataParser($rulesClass);
627 8
628
        return $validator;
629
    }
630
631
    /**
632
     * @param ContainerInterface $container
633
     * @param string             $schemaClass
634
     *
635
     * @return ParametersMapperInterface
636
     *
637
     * @throws ContainerExceptionInterface
638 16
     * @throws NotFoundExceptionInterface
639
     */
640
    protected static function defaultCreateParameterMapper(
641
        ContainerInterface $container,
642 16
        string $schemaClass
643
    ): ParametersMapperInterface {
644
        static::assertClassImplements($schemaClass, SchemaInterface::class);
645 16
646
        /** @var SchemaInterface $schemaClass */
647
        $jsonResourceType = $schemaClass::TYPE;
648 16
649 16
        /** @var ParametersMapperInterface $mapper */
650
        $mapper = $container->get(ParametersMapperInterface::class);
651 16
        $mapper->selectRootSchemaByResourceType($jsonResourceType);
652
653
        return $mapper;
654
    }
655
656
    /**
657
     * @param JsonApiQueryValidatingParserInterface $queryParser
658
     *
659 14
     * @return EncodingParametersInterface
660
     */
661
    protected static function defaultCreateEncodingParameters(
662 14
        JsonApiQueryValidatingParserInterface $queryParser
663 14
    ): EncodingParametersInterface {
664 14
        return new EncodingParameters(
665
            $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...
666
            $queryParser->hasFields() === true ? $queryParser->getFields() : null
667
        );
668
    }
669
670
    /**
671
     * @param ContainerInterface $container
672
     * @param string|null        $class
673
     *
674
     * @return CrudInterface
675
     *
676
     * @throws ContainerExceptionInterface
677 26
     * @throws NotFoundExceptionInterface
678
     */
679 26
    protected static function defaultCreateApi(ContainerInterface $container, string $class): CrudInterface
680
    {
681
        static::assertClassImplements($class, CrudInterface::class);
682 26
683 26
        /** @var FactoryInterface $factory */
684
        $factory = $container->get(FactoryInterface::class);
685 26
        $api     = $factory->createApi($class);
686
687
        return $api;
688
    }
689
690
    /**
691
     * @param UriInterface                     $requestUri
692
     * @param SettingsProviderInterface        $provider
693
     * @param JsonSchemasInterface             $jsonSchemas
694
     * @param EncoderInterface                 $encoder
695
     * @param EncodingParametersInterface|null $parameters
696
     *
697 21
     * @return ResponsesInterface
698
     */
699
    protected static function defaultCreateResponses(
700
        UriInterface $requestUri,
701
        SettingsProviderInterface $provider,
702
        JsonSchemasInterface $jsonSchemas,
703
        EncoderInterface $encoder,
704 21
        ?EncodingParametersInterface $parameters
705 21
    ): ResponsesInterface {
706 21
        $encoder->forOriginalUri($requestUri);
707 21
        $settings  = $provider->get(S::class);
708 21
        $responses = new Responses(
709 21
            new MediaType(MediaTypeInterface::JSON_API_TYPE, MediaTypeInterface::JSON_API_SUB_TYPE),
710 21
            $encoder,
711 21
            $jsonSchemas,
712 21
            $parameters,
713
            $settings[S::KEY_URI_PREFIX],
714
            $settings[S::KEY_META]
715 21
        );
716
717
        return $responses;
718
    }
719
720
    /**
721
     * Developers can override the method in order to add/remove some data for `create`/`update` inputs.
722
     *
723
     * @param string                    $requestBody
724
     * @param FactoryInterface          $errorFactory
725
     * @param FormatterFactoryInterface $formatterFactory
726
     * @param string                    $messagesNamespace
727
     * @param string                    $errorMessage
728
     *
729 7
     * @return array
730
     */
731
    protected static function readJsonFromRequest(
732
        string $requestBody,
733
        FactoryInterface $errorFactory,
734
        FormatterFactoryInterface $formatterFactory,
735
        string $messagesNamespace = S::GENERIC_NAMESPACE,
736 7
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
737 1
    ): array {
738 1
        if (empty($requestBody) === true || ($json = json_decode($requestBody, true)) === null) {
739 1
            $formatter = $formatterFactory->createFormatter($messagesNamespace);
740
            $errors    = $errorFactory->createErrorCollection();
741 1
            $errors->addDataError($formatter->formatMessage($errorMessage));
742
743
            throw new JsonApiException($errors);
744 6
        }
745
746
        return $json;
747
    }
748
749
    /**
750
     * Developers can override the method in order to use custom data mapping from a Schema to Model.
751
     *
752
     * @param array                    $captures
753
     * @param string                   $schemaClass
754
     * @param ModelSchemaInfoInterface $schemaInfo
755
     *
756 4
     * @return array
757
     */
758
    protected static function mapSchemaDataToModelData(
759
        array $captures,
760
        string $schemaClass,
761 4
        ModelSchemaInfoInterface $schemaInfo
762
    ): array {
763
        static::assertClassImplements($schemaClass, SchemaInterface::class);
764 4
765
        /** @var SchemaInterface $schemaClass */
766
        static::assertClassImplements($modelClass = $schemaClass::MODEL, ModelInterface::class);
767 4
        /** @var ModelInterface $modelClass */
768 4
769 4
        $index         = null;
770 4
        $fields        = [];
771 4
        $toManyIndexes = [];
772 4
        foreach ($captures as $name => $value) {
773 4
            assert(is_string($name) === true);
774 4
            if ($name === DI::KEYWORD_ID) {
775 4
                $index = $value;
776 4
            } elseif ($schemaClass::hasAttributeMapping($name) === true) {
777 4
                $fieldName          = $schemaClass::getAttributeMapping($name);
778 2
                $fields[$fieldName] = $value;
779 2
            } elseif ($schemaClass::hasRelationshipMapping($name) === true) {
780 2
                $modelRelName = $schemaClass::getRelationshipMapping($name);
781 2
                $relType      = $schemaInfo->getRelationshipType($modelClass, $modelRelName);
782 2
                if ($relType === RelationshipTypes::BELONGS_TO) {
783 2
                    $fkName          = $schemaInfo->getForeignKey($modelClass, $modelRelName);
784 4
                    $fields[$fkName] = $value;
785
                } elseif ($relType === RelationshipTypes::BELONGS_TO_MANY) {
786
                    $toManyIndexes[$modelRelName] = $value;
787
                }
788
            }
789 4
        }
790
791 4
        $result = [$index, $fields, $toManyIndexes];
792
793
        return $result;
794
    }
795
796
    /**
797
     * @param null|string $value
798
     *
799 26
     * @return void
800
     */
801 26
    private static function assertClassValueDefined(?string $value): void
802
    {
803
        assert(empty($value) === false, 'Value should be defined in `' . static::class . '`.');
804
    }
805
806
    /**
807
     * @param string $class
808
     * @param string $interface
809
     *
810 26
     * @return void
811
     */
812 26
    private static function assertClassImplements(string $class, string $interface): void
813 26
    {
814 26
        assert(
815
            array_key_exists($interface, class_implements($class)) === true,
816
            "Class `$class` should implement `" . $interface . '` interface.'
817
        );
818
    }
819
}
820