Completed
Push — master ( dcfc04...697864 )
by Neomerx
04:30
created

defaultGetResourceUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 6
cts 6
cp 1
rs 9.8666
c 0
b 0
f 0
cc 1
nc 1
nop 3
crap 1
1
<?php namespace Limoncello\Flute\Http\Traits;
2
3
/**
4
 * Copyright 2015-2018 [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 Doctrine\DBAL\Exception\UniqueConstraintViolationException;
21
use Limoncello\Contracts\Application\ModelInterface;
22
use Limoncello\Contracts\Data\ModelSchemaInfoInterface;
23
use Limoncello\Contracts\Data\RelationshipTypes;
24
use Limoncello\Contracts\L10n\FormatterFactoryInterface;
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\JsonApiDataParserInterface;
36
use Limoncello\Flute\Contracts\Validation\JsonApiDataRulesInterface;
37
use Limoncello\Flute\Contracts\Validation\JsonApiParserFactoryInterface;
38
use Limoncello\Flute\Contracts\Validation\JsonApiQueryParserInterface;
39
use Limoncello\Flute\Contracts\Validation\JsonApiQueryRulesInterface;
40
use Limoncello\Flute\Http\JsonApiResponse;
41
use Limoncello\Flute\Http\Responses;
42
use Limoncello\Flute\Package\FluteSettings as S;
43
use Limoncello\Flute\Resources\Messages\En\Generic;
44
use Limoncello\Flute\Validation\JsonApi\Rules\DefaultQueryValidationRules;
45
use Neomerx\JsonApi\Contracts\Http\Headers\MediaTypeInterface;
46
use Neomerx\JsonApi\Contracts\Http\ResponsesInterface;
47
use Neomerx\JsonApi\Contracts\Schema\DocumentInterface as DI;
48
use Neomerx\JsonApi\Exceptions\JsonApiException;
49
use Neomerx\JsonApi\Http\Headers\MediaType;
50
use Psr\Container\ContainerExceptionInterface;
51
use Psr\Container\ContainerInterface;
52
use Psr\Container\NotFoundExceptionInterface;
53
use Psr\Http\Message\ResponseInterface;
54
use Psr\Http\Message\UriInterface;
55
56
/**
57
 * @package Limoncello\Flute
58
 */
59
trait DefaultControllerMethodsTrait
60
{
61
    /** @noinspection PhpTooManyParametersInspection
62
     * @param array                       $queryParams
63
     * @param UriInterface                $requestUri
64
     * @param JsonApiQueryParserInterface $queryParser
65
     * @param ParametersMapperInterface   $mapper
66
     * @param CrudInterface               $crud
67
     * @param EncoderInterface            $encoder
68
     *
69
     * @return ResponseInterface
70
     */
71 12
    protected static function defaultIndexHandler(
72
        array $queryParams,
73
        UriInterface $requestUri,
74
        JsonApiQueryParserInterface $queryParser,
75
        ParametersMapperInterface $mapper,
76
        CrudInterface $crud,
77
        EncoderInterface $encoder
78
    ): ResponseInterface {
79 12
        $queryParser->parse(null, $queryParams);
80
81 11
        $models = $mapper->applyQueryParameters($queryParser, $crud)->index();
82
83 10
        self::defaultApplyIncludesAndFieldSetsToEncoder($queryParser, $encoder);
84 10
        $responses = static::defaultCreateResponses($requestUri, $encoder);
85 10
        $response  = ($models->getData()) === null ?
86 10
            $responses->getCodeResponse(404) : $responses->getContentResponse($models);
87
88 10
        return $response;
89
    }
90
91
    /** @noinspection PhpTooManyParametersInspection
92
     * @param string                      $index
93
     * @param array                       $queryParams
94
     * @param UriInterface                $requestUri
95
     * @param JsonApiQueryParserInterface $queryParser
96
     * @param ParametersMapperInterface   $mapper
97
     * @param CrudInterface               $crud
98
     * @param EncoderInterface            $encoder
99
     *
100
     * @return ResponseInterface
101
     */
102 1
    protected static function defaultReadHandler(
103
        string $index,
104
        array $queryParams,
105
        UriInterface $requestUri,
106
        JsonApiQueryParserInterface $queryParser,
107
        ParametersMapperInterface $mapper,
108
        CrudInterface $crud,
109
        EncoderInterface $encoder
110
    ): ResponseInterface {
111 1
        $queryParser->parse($index, $queryParams);
112 1
        $validatedIndex = $queryParser->getIdentity();
113
114 1
        $model = $mapper->applyQueryParameters($queryParser, $crud)->read($validatedIndex);
115 1
        assert(!($model instanceof PaginatedDataInterface));
116
117 1
        self::defaultApplyIncludesAndFieldSetsToEncoder($queryParser, $encoder);
118 1
        $responses = static::defaultCreateResponses($requestUri, $encoder);
119 1
        $response  = $model === null ?
120 1
            $responses->getCodeResponse(404) : $responses->getContentResponse($model);
121
122 1
        return $response;
123
    }
124
125
    /** @noinspection PhpTooManyParametersInspection
126
     * @param string                      $index
127
     * @param Closure                     $apiHandler
128
     * @param array                       $queryParams
129
     * @param UriInterface                $requestUri
130
     * @param JsonApiQueryParserInterface $queryParser
131
     * @param ParametersMapperInterface   $mapper
132
     * @param CrudInterface               $crud
133
     * @param EncoderInterface            $encoder
134
     *
135
     * @return ResponseInterface
136
     *
137
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
138
     */
139 2
    protected static function defaultReadRelationshipWithClosureHandler(
140
        string $index,
141
        Closure $apiHandler,
142
        array $queryParams,
143
        UriInterface $requestUri,
144
        JsonApiQueryParserInterface $queryParser,
145
        ParametersMapperInterface $mapper,
146
        CrudInterface $crud,
147
        EncoderInterface $encoder
148
    ): ResponseInterface {
149 2
        $queryParser->parse($index, $queryParams);
150 2
        $mapper->applyQueryParameters($queryParser, $crud);
151
152 2
        $relData = call_user_func($apiHandler);
153
154 2
        self::defaultApplyIncludesAndFieldSetsToEncoder($queryParser, $encoder);
155 2
        $responses = static::defaultCreateResponses($requestUri, $encoder);
156
157 2
        $noData   = $relData === null || ($relData instanceof PaginatedDataInterface && $relData->getData() === null);
158 2
        $response = $noData === true ? $responses->getCodeResponse(404) : $responses->getContentResponse($relData);
159
160 2
        return $response;
161
    }
162
163
    /** @noinspection PhpTooManyParametersInspection
164
     * @param string                      $index
165
     * @param Closure                     $apiHandler
166
     * @param array                       $queryParams
167
     * @param UriInterface                $requestUri
168
     * @param JsonApiQueryParserInterface $queryParser
169
     * @param ParametersMapperInterface   $mapper
170
     * @param CrudInterface               $crud
171
     * @param EncoderInterface            $encoder
172
     *
173
     * @return ResponseInterface
174
     *
175
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
176
     */
177 1
    protected static function defaultReadRelationshipIdentifiersWithClosureHandler(
178
        string $index,
179
        Closure $apiHandler,
180
        array $queryParams,
181
        UriInterface $requestUri,
182
        JsonApiQueryParserInterface $queryParser,
183
        ParametersMapperInterface $mapper,
184
        CrudInterface $crud,
185
        EncoderInterface $encoder
186
    ): ResponseInterface {
187 1
        $queryParser->parse($index, $queryParams);
188 1
        $mapper->applyQueryParameters($queryParser, $crud);
189
190 1
        $relData = call_user_func($apiHandler);
191
192 1
        self::defaultApplyIncludesAndFieldSetsToEncoder($queryParser, $encoder);
193 1
        $responses = static::defaultCreateResponses($requestUri, $encoder);
194
195 1
        $noData   = $relData === null || ($relData instanceof PaginatedDataInterface && $relData->getData() === null);
196 1
        $response = $noData === true ? $responses->getCodeResponse(404) : $responses->getIdentifiersResponse($relData);
197
198 1
        return $response;
199
    }
200
201
    /** @noinspection PhpTooManyParametersInspection
202
     * @param UriInterface               $requestUri
203
     * @param string                     $requestBody
204
     * @param string                     $schemaClass
205
     * @param ModelSchemaInfoInterface   $schemaInfo
206
     * @param JsonApiDataParserInterface $parser
207
     * @param CrudInterface              $crud
208
     * @param JsonSchemasInterface       $jsonSchemas
209
     * @param EncoderInterface           $encoder
210
     * @param FactoryInterface           $errorFactory
211
     * @param FormatterFactoryInterface  $formatterFactory
212
     * @param string                     $messagesNamespace
213
     * @param string                     $errorMessage
214
     *
215
     * @return ResponseInterface
216
     *
217
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
218
     */
219 2
    protected static function defaultCreateHandler(
220
        UriInterface $requestUri,
221
        string $requestBody,
222
        string $schemaClass,
223
        ModelSchemaInfoInterface $schemaInfo,
224
        JsonApiDataParserInterface $parser,
225
        CrudInterface $crud,
226
        JsonSchemasInterface $jsonSchemas,
227
        EncoderInterface $encoder,
228
        FactoryInterface $errorFactory,
229
        FormatterFactoryInterface $formatterFactory,
230
        string $messagesNamespace = S::GENERIC_NAMESPACE,
231
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
232
    ): ResponseInterface {
233
        // some of the users want to reuse default `create` but have a custom part for responses
234
        // to meet this requirement it is split into two parts.
235 2
        $index = static::defaultCreate(
236 2
            $requestBody,
237 2
            $schemaClass,
238 2
            $schemaInfo,
239 2
            $parser,
240 2
            $crud,
241 2
            $errorFactory,
242 2
            $formatterFactory,
243 2
            $messagesNamespace,
244 2
            $errorMessage
245
        );
246
247 1
        return static::defaultCreateResponse($index, $requestUri, $crud, $jsonSchemas, $encoder);
248
    }
249
250
    /** @noinspection PhpTooManyParametersInspection
251
     * @param string                     $requestBody
252
     * @param string                     $schemaClass
253
     * @param ModelSchemaInfoInterface   $schemaInfo
254
     * @param JsonApiDataParserInterface $parser
255
     * @param CrudInterface              $crud
256
     * @param FactoryInterface           $errorFactory
257
     * @param FormatterFactoryInterface  $formatterFactory
258
     * @param string                     $messagesNamespace
259
     * @param string                     $errorMessage
260
     *
261
     * @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...
262
     */
263 2
    protected static function defaultCreate(
264
        string $requestBody,
265
        string $schemaClass,
266
        ModelSchemaInfoInterface $schemaInfo,
267
        JsonApiDataParserInterface $parser,
268
        CrudInterface $crud,
269
        FactoryInterface $errorFactory,
270
        FormatterFactoryInterface $formatterFactory,
271
        string $messagesNamespace = S::GENERIC_NAMESPACE,
272
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
273
    ): string {
274 2
        $jsonData = static::readJsonFromRequest(
275 2
            $requestBody,
276 2
            $errorFactory,
277 2
            $formatterFactory,
278 2
            $messagesNamespace,
279 2
            $errorMessage
280
        );
281
282 2
        $captures = $parser->assert($jsonData)->getCaptures();
283
284 2
        list ($index, $attributes, $toMany) = static::mapSchemaDataToModelData($captures, $schemaClass, $schemaInfo);
285
286
        try {
287 2
            $index = $crud->create($index, $attributes, $toMany);
288 1
        } /** @noinspection PhpRedundantCatchClauseInspection */ catch (UniqueConstraintViolationException $exception) {
289 1
            $errors    = $errorFactory->createErrorCollection();
290 1
            $formatter = $formatterFactory->createFormatter($messagesNamespace);
291 1
            $title     = $formatter->formatMessage($errorMessage);
292 1
            $details   = null;
293 1
            $errorCode = JsonApiResponse::HTTP_CONFLICT;
294 1
            $errors->addDataError($title, $details, $errorCode);
295
296 1
            throw new JsonApiException($errors);
0 ignored issues
show
Documentation introduced by
$errors is of type object<Neomerx\JsonApi\Schema\ErrorCollection>, but the function expects a object<Neomerx\JsonApi\C...pi\Exceptions\iterable>.

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...
297
        }
298
299 1
        return $index;
300
    }
301
302
    /**
303
     * @param string               $index
304
     * @param UriInterface         $requestUri
305
     * @param CrudInterface        $crud
306
     * @param JsonSchemasInterface $jsonSchemas
307
     * @param EncoderInterface     $encoder
308
     *
309
     * @return ResponseInterface
310
     */
311 1
    protected static function defaultCreateResponse(
312
        string $index,
313
        UriInterface $requestUri,
314
        CrudInterface $crud,
315
        JsonSchemasInterface $jsonSchemas,
316
        EncoderInterface $encoder
317
    ): ResponseInterface {
318 1
        $model = $crud->read($index);
319 1
        assert($model !== null && !($model instanceof PaginatedDataInterface));
320
321 1
        $responses = static::defaultCreateResponses($requestUri, $encoder);
322 1
        $fullUrl   = static::defaultGetResourceUrl($model, $requestUri, $jsonSchemas);
323 1
        $response  = $responses->getCreatedResponse($model, $fullUrl);
324
325 1
        return $response;
326
    }
327
328
    /** @noinspection PhpTooManyParametersInspection
329
     * @param string                     $index
330
     * @param UriInterface               $requestUri
331
     * @param string                     $requestBody
332
     * @param string                     $schemaClass
333
     * @param ModelSchemaInfoInterface   $schemaInfo
334
     * @param JsonApiDataParserInterface $parser
335
     * @param CrudInterface              $crud
336
     * @param EncoderInterface           $encoder
337
     * @param FactoryInterface           $errorFactory
338
     * @param FormatterFactoryInterface  $formatterFactory
339
     * @param string                     $messagesNamespace
340
     * @param string                     $errorMessage
341
     *
342
     * @return ResponseInterface
343
     *
344
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
345
     */
346 6
    protected static function defaultUpdateHandler(
347
        string $index,
348
        UriInterface $requestUri,
349
        string $requestBody,
350
        string $schemaClass,
351
        ModelSchemaInfoInterface $schemaInfo,
352
        JsonApiDataParserInterface $parser,
353
        CrudInterface $crud,
354
        EncoderInterface $encoder,
355
        FactoryInterface $errorFactory,
356
        FormatterFactoryInterface $formatterFactory,
357
        string $messagesNamespace = S::GENERIC_NAMESPACE,
358
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
359
    ): ResponseInterface {
360
        // some of the users want to reuse default `update` but have a custom part for responses
361
        // to meet this requirement it is split into two parts.
362 6
        $updated = static::defaultUpdate(
363 6
            $index,
364 6
            $requestBody,
365 6
            $schemaClass,
366 6
            $schemaInfo,
367 6
            $parser,
368 6
            $crud,
369 6
            $errorFactory,
370 6
            $formatterFactory,
371 6
            $messagesNamespace,
372 6
            $errorMessage
373
        );
374
375 2
        return static::defaultUpdateResponse($updated, $index, $requestUri, $crud, $encoder);
376
    }
377
378
    /** @noinspection PhpTooManyParametersInspection
379
     * @param string                     $index
380
     * @param string                     $requestBody
381
     * @param string                     $schemaClass
382
     * @param ModelSchemaInfoInterface   $schemaInfo
383
     * @param JsonApiDataParserInterface $parser
384
     * @param CrudInterface              $crud
385
     * @param FactoryInterface           $errorFactory
386
     * @param FormatterFactoryInterface  $formatterFactory
387
     * @param string                     $messagesNamespace
388
     * @param string                     $errorMessage
389
     *
390
     * @return int
391
     *
392
     * @SuppressWarnings(PHPMD.ElseExpression)
393
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
394
     */
395 6
    protected static function defaultUpdate(
396
        string $index,
397
        string $requestBody,
398
        string $schemaClass,
399
        ModelSchemaInfoInterface $schemaInfo,
400
        JsonApiDataParserInterface $parser,
401
        CrudInterface $crud,
402
        FactoryInterface $errorFactory,
403
        FormatterFactoryInterface $formatterFactory,
404
        string $messagesNamespace = S::GENERIC_NAMESPACE,
405
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
406
    ): int {
407 6
        $jsonData = static::readJsonFromRequest(
408 6
            $requestBody,
409 6
            $errorFactory,
410 6
            $formatterFactory,
411 6
            $messagesNamespace,
412 6
            $errorMessage
413
        );
414
415
        // check that index in data and URL are identical
416 5
        $indexValue = $jsonData[DI::KEYWORD_DATA][DI::KEYWORD_ID] ?? null;
417 5
        if (empty($indexValue) === false) {
418 4
            if ($indexValue !== $index) {
419 1
                $errors    = $errorFactory->createErrorCollection();
420 1
                $formatter = $formatterFactory->createFormatter($messagesNamespace);
421 1
                $errors->addDataIdError($formatter->formatMessage($errorMessage));
422
423 4
                throw new JsonApiException($errors);
0 ignored issues
show
Documentation introduced by
$errors is of type object<Neomerx\JsonApi\Schema\ErrorCollection>, but the function expects a object<Neomerx\JsonApi\C...pi\Exceptions\iterable>.

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...
424
            }
425
        } else {
426
            // put the index to data for our convenience
427 1
            $jsonData[DI::KEYWORD_DATA][DI::KEYWORD_ID] = $index;
428
        }
429
        // validate the data
430 4
        $captures = $parser->assert($jsonData)->getCaptures();
431
432 3
        list ($index, $attributes, $toMany) = static::mapSchemaDataToModelData($captures, $schemaClass, $schemaInfo);
433
434
        try {
435 3
            $updated = $crud->update($index, $attributes, $toMany);
436 1
        } /** @noinspection PhpRedundantCatchClauseInspection */ catch (UniqueConstraintViolationException $exception) {
437 1
            $errors    = $errorFactory->createErrorCollection();
438 1
            $formatter = $formatterFactory->createFormatter($messagesNamespace);
439 1
            $title     = $formatter->formatMessage($errorMessage);
440 1
            $details   = null;
441 1
            $errorCode = JsonApiResponse::HTTP_CONFLICT;
442 1
            $errors->addDataError($title, $details, $errorCode);
443
444 1
            throw new JsonApiException($errors);
0 ignored issues
show
Documentation introduced by
$errors is of type object<Neomerx\JsonApi\Schema\ErrorCollection>, but the function expects a object<Neomerx\JsonApi\C...pi\Exceptions\iterable>.

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...
445
        }
446
447 2
        return $updated;
448
    }
449
450
    /**
451
     * @param int              $updated
452
     * @param string           $index
453
     * @param UriInterface     $requestUri
454
     * @param CrudInterface    $crud
455
     * @param EncoderInterface $encoder
456
     *
457
     * @return ResponseInterface
458
     *
459
     * @SuppressWarnings(PHPMD.ElseExpression)
460
     */
461 3
    protected static function defaultUpdateResponse(
462
        int $updated,
463
        string $index,
464
        UriInterface $requestUri,
465
        CrudInterface $crud,
466
        EncoderInterface $encoder
467
    ): ResponseInterface {
468 3
        $responses = static::defaultCreateResponses($requestUri, $encoder);
469 3
        if ($updated > 0 && ($model = $crud->read($index)) !== null) {
470 2
            assert(!($model instanceof PaginatedDataInterface));
471 2
            $response = $responses->getContentResponse($model);
472
        } else {
473 1
            $response = $responses->getCodeResponse(404);
474
        }
475
476 3
        return $response;
477
    }
478
479
    /**
480
     * @param string                      $index
481
     * @param UriInterface                $requestUri
482
     * @param JsonApiQueryParserInterface $queryParser
483
     * @param CrudInterface               $crud
484
     * @param EncoderInterface            $encoder
485
     *
486
     * @return ResponseInterface
487
     */
488 1
    protected static function defaultDeleteHandler(
489
        string $index,
490
        UriInterface $requestUri,
491
        JsonApiQueryParserInterface $queryParser,
492
        CrudInterface $crud,
493
        EncoderInterface $encoder
494
    ): ResponseInterface {
495 1
        $validatedIndex = $queryParser->parse($index)->getIdentity();
496 1
        $crud->remove($validatedIndex);
497
498 1
        $responses = static::defaultCreateResponses($requestUri, $encoder);
499 1
        $response  = $responses->getCodeResponse(204);
500
501 1
        return $response;
502
    }
503
504
    /** @noinspection PhpTooManyParametersInspection
505
     * @param string                      $index
506
     * @param string                      $jsonRelName
507
     * @param string                      $modelRelName
508
     * @param UriInterface                $requestUri
509
     * @param string                      $requestBody
510
     * @param string                      $schemaClass
511
     * @param ModelSchemaInfoInterface    $schemaInfo
512
     * @param JsonApiQueryParserInterface $queryParser
513
     * @param JsonApiDataParserInterface  $dataValidator
514
     * @param CrudInterface               $parentCrud
515
     * @param EncoderInterface            $encoder
516
     * @param FactoryInterface            $errorFactory
517
     * @param FormatterFactoryInterface   $formatterFactory
518
     *
519
     * @return ResponseInterface
520
     *
521
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
522
     */
523 1
    protected static function defaultAddInRelationshipHandler(
524
        string $index,
525
        string $jsonRelName,
526
        string $modelRelName,
527
        UriInterface $requestUri,
528
        string $requestBody,
529
        string $schemaClass,
530
        ModelSchemaInfoInterface $schemaInfo,
531
        JsonApiQueryParserInterface $queryParser,
532
        JsonApiDataParserInterface $dataValidator,
533
        CrudInterface $parentCrud,
534
        EncoderInterface $encoder,
535
        FactoryInterface $errorFactory,
536
        FormatterFactoryInterface $formatterFactory
537
    ): ResponseInterface {
538
        /** @var SchemaInterface $schemaClass */
539 1
        assert(array_key_exists(SchemaInterface::class, class_implements($schemaClass)) === true);
540 1
        $modelClass = $schemaClass::MODEL;
541 1
        assert($schemaInfo->hasRelationship($modelClass, $modelRelName));
542 1
        assert($schemaInfo->getRelationshipType($modelClass, $modelRelName) === RelationshipTypes::BELONGS_TO_MANY);
543
544 1
        $jsonData = static::readJsonFromRequest($requestBody, $errorFactory, $formatterFactory);
545 1
        $captures = $dataValidator->assertRelationship($index, $jsonRelName, $jsonData)->getCaptures();
546 1
        $relIds   = $captures[$jsonRelName];
547
548 1
        $validatedIndex = $queryParser->parse($index)->getIdentity();
549 1
        $parentCrud->createInBelongsToManyRelationship($validatedIndex, $modelRelName, $relIds);
550
551 1
        $responses = static::defaultCreateResponses($requestUri, $encoder);
552 1
        $response  = $responses->getCodeResponse(204);
553
554 1
        return $response;
555
    }
556
557
    /** @noinspection PhpTooManyParametersInspection
558
     * @param string                      $index
559
     * @param string                      $jsonRelName
560
     * @param string                      $modelRelName
561
     * @param UriInterface                $requestUri
562
     * @param string                      $requestBody
563
     * @param string                      $schemaClass
564
     * @param ModelSchemaInfoInterface    $schemaInfo
565
     * @param JsonApiQueryParserInterface $queryParser
566
     * @param JsonApiDataParserInterface  $dataValidator
567
     * @param CrudInterface               $parentCrud
568
     * @param EncoderInterface            $encoder
569
     * @param FactoryInterface            $errorFactory
570
     * @param FormatterFactoryInterface   $formatterFactory
571
     *
572
     * @return ResponseInterface
573
     *
574
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
575
     */
576 1
    protected static function defaultDeleteInRelationshipHandler(
577
        string $index,
578
        string $jsonRelName,
579
        string $modelRelName,
580
        UriInterface $requestUri,
581
        string $requestBody,
582
        string $schemaClass,
583
        ModelSchemaInfoInterface $schemaInfo,
584
        JsonApiQueryParserInterface $queryParser,
585
        JsonApiDataParserInterface $dataValidator,
586
        CrudInterface $parentCrud,
587
        EncoderInterface $encoder,
588
        FactoryInterface $errorFactory,
589
        FormatterFactoryInterface $formatterFactory
590
    ): ResponseInterface {
591
        /** @var SchemaInterface $schemaClass */
592 1
        assert(array_key_exists(SchemaInterface::class, class_implements($schemaClass)) === true);
593 1
        $modelClass = $schemaClass::MODEL;
594 1
        assert($schemaInfo->hasRelationship($modelClass, $modelRelName));
595 1
        assert($schemaInfo->getRelationshipType($modelClass, $modelRelName) === RelationshipTypes::BELONGS_TO_MANY);
596
597 1
        $jsonData = static::readJsonFromRequest($requestBody, $errorFactory, $formatterFactory);
598 1
        $captures = $dataValidator->assertRelationship($index, $jsonRelName, $jsonData)->getCaptures();
599 1
        $relIds   = $captures[$jsonRelName];
600
601 1
        $validatedIndex = $queryParser->parse($index)->getIdentity();
602 1
        $parentCrud->removeInBelongsToManyRelationship($validatedIndex, $modelRelName, $relIds);
603
604 1
        $responses = static::defaultCreateResponses($requestUri, $encoder);
605 1
        $response  = $responses->getCodeResponse(204);
606
607 1
        return $response;
608
    }
609
610
    /** @noinspection PhpTooManyParametersInspection
611
     * @param string                      $index
612
     * @param string                      $jsonRelName
613
     * @param string                      $modelRelName
614
     * @param UriInterface                $requestUri
615
     * @param string                      $requestBody
616
     * @param string                      $schemaClass
617
     * @param ModelSchemaInfoInterface    $schemaInfo
618
     * @param JsonApiQueryParserInterface $queryParser
619
     * @param JsonApiDataParserInterface  $dataValidator
620
     * @param CrudInterface               $crud
621
     * @param EncoderInterface            $encoder
622
     * @param FactoryInterface            $errorFactory
623
     * @param FormatterFactoryInterface   $formatterFactory
624
     *
625
     * @return ResponseInterface
626
     *
627
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
628
     */
629 1
    protected static function defaultReplaceInRelationship(
630
        string $index,
631
        string $jsonRelName,
632
        string $modelRelName,
633
        UriInterface $requestUri,
634
        string $requestBody,
635
        string $schemaClass,
636
        ModelSchemaInfoInterface $schemaInfo,
637
        JsonApiQueryParserInterface $queryParser,
638
        JsonApiDataParserInterface $dataValidator,
639
        CrudInterface $crud,
640
        EncoderInterface $encoder,
641
        FactoryInterface $errorFactory,
642
        FormatterFactoryInterface $formatterFactory
643
    ): ResponseInterface {
644
        /** @var SchemaInterface $schemaClass */
645 1
        assert(array_key_exists(SchemaInterface::class, class_implements($schemaClass)) === true);
646 1
        $modelClass = $schemaClass::MODEL;
647 1
        assert($schemaInfo->hasRelationship($modelClass, $modelRelName));
648 1
        assert(
649 1
            ($type =$schemaInfo->getRelationshipType($modelClass, $modelRelName)) === RelationshipTypes::BELONGS_TO ||
650 1
            $type === RelationshipTypes::BELONGS_TO_MANY
651
        );
652
653 1
        $jsonData = static::readJsonFromRequest($requestBody, $errorFactory, $formatterFactory);
654 1
        $captures = $dataValidator->assertRelationship($index, $jsonRelName, $jsonData)->getCaptures();
655
656
        // If we are here then we have something in 'data' section.
657
658 1
        $validatedIndex = $queryParser->parse($index)->getIdentity();
659 1
        list (, $attributes, $toMany) = static::mapSchemaDataToModelData($captures, $schemaClass, $schemaInfo);
0 ignored issues
show
Documentation introduced by
$schemaClass is of type object<Limoncello\Flute\...Schema\SchemaInterface>, 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...
660
661 1
        $updated = $crud->update($validatedIndex, $attributes, $toMany);
662
663 1
        return static::defaultUpdateResponse($updated, $index, $requestUri, $crud, $encoder);
664
    }
665
666
    /**
667
     * @param ContainerInterface $container
668
     * @param string             $rulesClass
669
     *
670
     * @return JsonApiQueryParserInterface
671
     *
672
     * @throws ContainerExceptionInterface
673
     * @throws NotFoundExceptionInterface
674
     */
675 20
    protected static function defaultCreateQueryParser(
676
        ContainerInterface $container,
677
        string $rulesClass = DefaultQueryValidationRules::class
678
    ): JsonApiQueryParserInterface {
679 20
        static::assertClassImplements($rulesClass, JsonApiQueryRulesInterface::class);
680
681
        /** @var JsonApiParserFactoryInterface $factory */
682 20
        $factory = $container->get(JsonApiParserFactoryInterface::class);
683 20
        $parser  = $factory->createQueryParser($rulesClass);
684
685 20
        return $parser;
686
    }
687
688
    /**
689
     * @param ContainerInterface $container
690
     * @param string             $rulesClass
691
     *
692
     * @return JsonApiDataParserInterface
693
     *
694
     * @throws ContainerExceptionInterface
695
     * @throws NotFoundExceptionInterface
696
     */
697 11
    protected static function defaultCreateDataParser(
698
        ContainerInterface $container,
699
        string $rulesClass
700
    ): JsonApiDataParserInterface {
701 11
        static::assertClassImplements($rulesClass, JsonApiDataRulesInterface::class);
702
703
        /** @var JsonApiParserFactoryInterface $factory */
704 11
        $factory = $container->get(JsonApiParserFactoryInterface::class);
705 11
        $parser  = $factory->createDataParser($rulesClass);
706
707 11
        return $parser;
708
    }
709
710
    /**
711
     * @param ContainerInterface $container
712
     * @param string             $rulesClass
713
     *
714
     * @return FormValidatorInterface
715
     *
716
     * @throws ContainerExceptionInterface
717
     * @throws NotFoundExceptionInterface
718
     */
719 1
    protected static function defaultCreateFormValidator(
720
        ContainerInterface $container,
721
        string $rulesClass
722
    ): FormValidatorInterface {
723 1
        static::assertClassImplements($rulesClass, FormRulesInterface::class);
724
725
        /** @var FormValidatorFactoryInterface $factory */
726 1
        $factory   = $container->get(FormValidatorFactoryInterface::class);
727 1
        $validator = $factory->createValidator($rulesClass);
728
729 1
        return $validator;
730
    }
731
732
    /**
733
     * @param ContainerInterface $container
734
     * @param string             $schemaClass
735
     *
736
     * @return ParametersMapperInterface
737
     *
738
     * @throws ContainerExceptionInterface
739
     * @throws NotFoundExceptionInterface
740
     */
741 16
    protected static function defaultCreateParameterMapper(
742
        ContainerInterface $container,
743
        string $schemaClass
744
    ): ParametersMapperInterface {
745 16
        static::assertClassImplements($schemaClass, SchemaInterface::class);
746
747
        /** @var SchemaInterface $schemaClass */
748 16
        $jsonResourceType = $schemaClass::TYPE;
749
750
        /** @var ParametersMapperInterface $mapper */
751 16
        $mapper = $container->get(ParametersMapperInterface::class);
752 16
        $mapper->selectRootSchemaByResourceType($jsonResourceType);
753
754 16
        return $mapper;
755
    }
756
757
    /**
758
     * @param JsonApiQueryParserInterface $queryParser
759
     * @param EncoderInterface            $encoder
760
     *
761
     * @return void
762
     */
763 14
    protected static function defaultApplyIncludesAndFieldSetsToEncoder(
764
        JsonApiQueryParserInterface $queryParser,
765
        EncoderInterface $encoder
766
    ): void {
767 14
        if ($queryParser->hasIncludes() === true) {
768 3
            $paths = array_keys($queryParser->getIncludes());
769 3
            $encoder->withIncludedPaths($paths);
0 ignored issues
show
Documentation introduced by
$paths is of type array, but the function expects a object<Neomerx\JsonApi\C...racts\Encoder\iterable>.

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...
770
        }
771 14
        if ($queryParser->hasFields() === true) {
772 1
            $encoder->withFieldSets($queryParser->getFields());
773
        }
774
    }
775
776
    /**
777
     * @param ContainerInterface $container
778
     * @param string|null        $class
779
     *
780
     * @return CrudInterface
781
     *
782
     * @throws ContainerExceptionInterface
783
     * @throws NotFoundExceptionInterface
784
     */
785 28
    protected static function defaultCreateApi(ContainerInterface $container, string $class): CrudInterface
786
    {
787 28
        static::assertClassImplements($class, CrudInterface::class);
788
789
        /** @var FactoryInterface $factory */
790 28
        $factory = $container->get(FactoryInterface::class);
791 28
        $api     = $factory->createApi($class);
792
793 28
        return $api;
794
    }
795
796
    /**
797
     * @param UriInterface     $requestUri
798
     * @param EncoderInterface $encoder
799
     *
800
     * @return ResponsesInterface
801
     */
802 21
    protected static function defaultCreateResponses(
803
        UriInterface $requestUri,
804
        EncoderInterface $encoder
805
    ): ResponsesInterface {
806 21
        $encoder->forOriginalUri($requestUri);
807 21
        $responses = new Responses(
808 21
            new MediaType(MediaTypeInterface::JSON_API_TYPE, MediaTypeInterface::JSON_API_SUB_TYPE),
809 21
            $encoder
810
        );
811
812 21
        return $responses;
813
    }
814
815
    /**
816
     * Developers can override the method in order to add/remove some data for `create`/`update` inputs.
817
     *
818
     * @param string                    $requestBody
819
     * @param FactoryInterface          $errorFactory
820
     * @param FormatterFactoryInterface $formatterFactory
821
     * @param string                    $messagesNamespace
822
     * @param string                    $errorMessage
823
     *
824
     * @return array
825
     */
826 11
    protected static function readJsonFromRequest(
827
        string $requestBody,
828
        FactoryInterface $errorFactory,
829
        FormatterFactoryInterface $formatterFactory,
830
        string $messagesNamespace = S::GENERIC_NAMESPACE,
831
        string $errorMessage = Generic::MSG_ERR_INVALID_ELEMENT
832
    ): array {
833 11
        if (empty($requestBody) === true || ($json = json_decode($requestBody, true)) === null) {
834 1
            $formatter = $formatterFactory->createFormatter($messagesNamespace);
835 1
            $errors    = $errorFactory->createErrorCollection();
836 1
            $errors->addDataError($formatter->formatMessage($errorMessage));
837
838 1
            throw new JsonApiException($errors);
0 ignored issues
show
Documentation introduced by
$errors is of type object<Neomerx\JsonApi\Schema\ErrorCollection>, but the function expects a object<Neomerx\JsonApi\C...pi\Exceptions\iterable>.

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...
839
        }
840
841 10
        return $json;
842
    }
843
844
    /**
845
     * Developers can override the method in order to use custom data mapping from a Schema to Model.
846
     *
847
     * @param iterable                 $captures
848
     * @param string                   $schemaClass
849
     * @param ModelSchemaInfoInterface $schemaInfo
850
     *
851
     * @return array
852
     */
853 6
    protected static function mapSchemaDataToModelData(
854
        iterable $captures,
855
        string $schemaClass,
856
        ModelSchemaInfoInterface $schemaInfo
857
    ): array {
858 6
        static::assertClassImplements($schemaClass, SchemaInterface::class);
859
860
        /** @var SchemaInterface $schemaClass */
861 6
        static::assertClassImplements($modelClass = $schemaClass::MODEL, ModelInterface::class);
862
        /** @var ModelInterface $modelClass */
863
864 6
        $index         = null;
865 6
        $fields        = [];
866 6
        $toManyIndexes = [];
867 6
        foreach ($captures as $name => $value) {
868 6
            assert(is_string($name) === true);
869 6
            if ($name === DI::KEYWORD_ID) {
870 4
                $index = $value;
871 6
            } elseif ($schemaClass::hasAttributeMapping($name) === true) {
872 5
                $fieldName          = $schemaClass::getAttributeMapping($name);
873 5
                $fields[$fieldName] = $value;
874 6
            } elseif ($schemaClass::hasRelationshipMapping($name) === true) {
875 3
                $modelRelName = $schemaClass::getRelationshipMapping($name);
876 3
                $relType      = $schemaInfo->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...
877 3
                if ($relType === RelationshipTypes::BELONGS_TO) {
878 3
                    $fkName          = $schemaInfo->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...
879 3
                    $fields[$fkName] = $value;
880 2
                } elseif ($relType === RelationshipTypes::BELONGS_TO_MANY) {
881 6
                    $toManyIndexes[$modelRelName] = $value;
882
                }
883
            }
884
        }
885
886 6
        $result = [$index, $fields, $toManyIndexes];
887
888 6
        return $result;
889
    }
890
891
    /**
892
     * @param mixed                $model
893
     * @param UriInterface         $requestUri
894
     * @param JsonSchemasInterface $jsonSchemas
895
     *
896
     * @return string
897
     */
898 1
    protected static function defaultGetResourceUrl(
899
        $model,
900
        UriInterface $requestUri,
901
        JsonSchemasInterface $jsonSchemas
902
    ): string {
903 1
        $schema    = $jsonSchemas->getSchema($model);
904 1
        $selfLink  = $schema->getSelfLink($model);
905 1
        $urlPrefix = (string)$requestUri->withPath('')->withQuery('')->withFragment('');
906 1
        $fullUrl   = $selfLink->getStringRepresentation($urlPrefix);
907
908 1
        return $fullUrl;
909
    }
910
911
    /**
912
     * @param null|string $value
913
     *
914
     * @return void
915
     */
916 28
    private static function assertClassValueDefined(?string $value): void
917
    {
918 28
        assert(empty($value) === false, 'Value should be defined in `' . static::class . '`.');
919
    }
920
921
    /**
922
     * @param string $class
923
     * @param string $interface
924
     *
925
     * @return void
926
     */
927 29
    private static function assertClassImplements(string $class, string $interface): void
928
    {
929 29
        assert(
930 29
            array_key_exists($interface, class_implements($class)) === true,
931 29
            "Class `$class` should implement `" . $interface . '` interface.'
932
        );
933
    }
934
}
935