Completed
Push — develop ( 5c8fb2...8f8d73 )
by Neomerx
07:05 queued 04:59
created

defaultCreateQueryParser()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

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