Completed
Push — develop ( 6d3477...b4cdc6 )
by Neomerx
05:19
created

BaseController::mapSchemeToModelParameters()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 12
cts 12
cp 1
rs 9.2
c 0
b 0
f 0
cc 2
eloc 16
nc 2
nop 3
crap 2
1
<?php namespace Limoncello\Flute\Http;
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 Limoncello\Contracts\Application\ModelInterface;
20
use Limoncello\Contracts\Data\ModelSchemeInfoInterface;
21
use Limoncello\Contracts\Data\RelationshipTypes;
22
use Limoncello\Contracts\L10n\FormatterFactoryInterface;
23
use Limoncello\Contracts\L10n\FormatterInterface;
24
use Limoncello\Flute\Contracts\Api\CrudInterface;
25
use Limoncello\Flute\Contracts\FactoryInterface;
26
use Limoncello\Flute\Contracts\Http\ControllerInterface;
27
use Limoncello\Flute\Contracts\Models\PaginatedDataInterface;
28
use Limoncello\Flute\Contracts\Schema\JsonSchemesInterface;
29
use Limoncello\Flute\Contracts\Schema\SchemaInterface;
30
use Limoncello\Flute\Contracts\Validation\JsonApiValidatorFactoryInterface;
31
use Limoncello\Flute\Contracts\Validation\JsonApiValidatorInterface;
32
use Limoncello\Flute\Http\Query\FilterParameterCollection;
33
use Limoncello\Flute\Http\Traits\CreateResponsesTrait;
34
use Limoncello\Flute\L10n\Messages;
35
use Neomerx\JsonApi\Contracts\Document\DocumentInterface as DI;
36
use Neomerx\JsonApi\Contracts\Encoder\Parameters\EncodingParametersInterface;
37
use Neomerx\JsonApi\Contracts\Http\Query\QueryParametersParserInterface;
38
use Neomerx\JsonApi\Contracts\Http\ResponsesInterface;
39
use Neomerx\JsonApi\Exceptions\JsonApiException;
40
use Psr\Container\ContainerInterface;
41
use Psr\Http\Message\ResponseInterface;
42
use Psr\Http\Message\ServerRequestInterface;
43
44
/**
45
 * @package Limoncello\Flute
46
 *
47
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
48
 */
49
abstract class BaseController implements ControllerInterface
50
{
51
    use CreateResponsesTrait;
52
53
    /** API class name */
54
    const API_CLASS = null;
55
56
    /** JSON API Schema class name */
57
    const SCHEMA_CLASS = null;
58
59
    /** JSON API validation rules set class */
60
    const ON_CREATE_VALIDATION_RULES_SET_CLASS = null;
61
62
    /** JSON API validation rules set class */
63
    const ON_UPDATE_VALIDATION_RULES_SET_CLASS = null;
64
65
    /**
66
     * @inheritdoc
67
     */
68 12
    public static function index(
69
        array $routeParams,
70
        ContainerInterface $container,
71
        ServerRequestInterface $request
72
    ): ResponseInterface {
73 12
        $schemeParams = self::parseQueryParameters($container, $request);
74
75
        list ($filters, $sorts, $includes, $paging) =
76 12
            static::mapSchemeToModelParameters($container, $schemeParams, static::SCHEMA_CLASS);
77 10
        $modelData = static::createApi($container)->index($filters, $sorts, $includes, $paging);
78
79 10
        $responses = static::createResponses($container, $request, $schemeParams);
80 10
        $response  = $modelData->getData() === null ?
81 10
            $responses->getCodeResponse(404) : $responses->getContentResponse($modelData);
82
83 10
        return $response;
84
    }
85
86
    /**
87
     * @inheritdoc
88
     */
89 1
    public static function create(
90
        array $routeParams,
91
        ContainerInterface $container,
92
        ServerRequestInterface $request
93
    ): ResponseInterface {
94 1
        $jsonData  = static::readJsonFromRequest($container, $request);
95 1
        $validator = static::createOnCreateValidator($container);
96 1
        $captures  = $validator->assert($jsonData)->getJsonApiCaptures();
97
98
        list ($index, $attributes, $toMany) =
99 1
            static::mapSchemeDataToModelData($container, $captures, static::SCHEMA_CLASS);
100
101 1
        $api   = self::createApi($container);
102 1
        $index = $api->create($index, $attributes, $toMany);
103 1
        $data  = $api->read($index);
104
105 1
        $response = static::createResponses($container, $request)->getCreatedResponse($data);
106
107 1
        return $response;
108
    }
109
110
    /**
111
     * @inheritdoc
112
     */
113 1
    public static function read(
114
        array $routeParams,
115
        ContainerInterface $container,
116
        ServerRequestInterface $request
117
    ): ResponseInterface {
118 1
        $schemeParams = self::parseQueryParameters($container, $request);
119
120
        list ($filters, , $includes) =
121 1
            static::mapSchemeToModelParameters($container, $schemeParams, static::SCHEMA_CLASS);
122
123 1
        $index    = $routeParams[static::ROUTE_KEY_INDEX];
124 1
        $response = static::readImpl(
0 ignored issues
show
Bug introduced by
Since readImpl() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of readImpl() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
125 1
            static::createApi($container),
126 1
            static::createResponses($container, $request, $schemeParams),
127 1
            $index,
128 1
            $filters,
129 1
            $includes
130
        );
131
132 1
        return $response;
133
    }
134
135
    /**
136
     * @inheritdoc
137
     */
138 4
    public static function update(
139
        array $routeParams,
140
        ContainerInterface $container,
141
        ServerRequestInterface $request
142
    ): ResponseInterface {
143 4
        $jsonData  = static::normalizeIndexValueOnUpdate(
144 4
            $routeParams,
145 4
            $container,
146 4
            static::readJsonFromRequest($container, $request)
147
        );
148 2
        $validator = static::createOnUpdateValidator($container);
149 2
        $captures  = $validator->assert($jsonData)->getJsonApiCaptures();
150
151
        list ($index, $attributes, $toMany) =
152 1
            static::mapSchemeDataToModelData($container, $captures, static::SCHEMA_CLASS);
153 1
        $api = self::createApi($container);
154
155 1
        return self::updateImpl($index, $attributes, $toMany, $container, $request, $api);
156
    }
157
158
    /**
159
     * @inheritdoc
160
     */
161 1
    public static function delete(
162
        array $routeParams,
163
        ContainerInterface $container,
164
        ServerRequestInterface $request
165
    ): ResponseInterface {
166 1
        $index = $routeParams[static::ROUTE_KEY_INDEX];
167
168 1
        return static::deleteImpl($index, $container, $request, self::createApi($container));
0 ignored issues
show
Bug introduced by
Since deleteImpl() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of deleteImpl() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
169
    }
170
171
    /**
172
     * @param string                 $index
173
     * @param string                 $relationshipName
174
     * @param ContainerInterface     $container
175
     * @param ServerRequestInterface $request
176
     *
177
     * @return ResponseInterface
178
     */
179 2 View Code Duplication
    protected static function readRelationship(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
        string $index,
181
        string $relationshipName,
182
        ContainerInterface $container,
183
        ServerRequestInterface $request
184
    ): ResponseInterface {
185 2
        $schemeParams = self::parseQueryParameters($container, $request);
186 2
        $relData      = self::readRelationshipData($index, $relationshipName, $container, $schemeParams);
187 2
        $responses    = static::createResponses($container, $request, $schemeParams);
188 2
        $response     = $relData->getData() === null ?
189 2
            $responses->getCodeResponse(404) : $responses->getContentResponse($relData);
190
191 2
        return $response;
192
    }
193
194
    /**
195
     * @param string                 $index
196
     * @param string                 $relationshipName
197
     * @param ContainerInterface     $container
198
     * @param ServerRequestInterface $request
199
     *
200
     * @return ResponseInterface
201
     */
202 1 View Code Duplication
    protected static function readRelationshipIdentifiers(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
203
        string $index,
204
        string $relationshipName,
205
        ContainerInterface $container,
206
        ServerRequestInterface $request
207
    ): ResponseInterface {
208 1
        $schemeParams = self::parseQueryParameters($container, $request);
209 1
        $relData      = self::readRelationshipData($index, $relationshipName, $container, $schemeParams);
210 1
        $responses    = static::createResponses($container, $request, $schemeParams);
211 1
        $response     = $relData->getData() === null ?
212 1
            $responses->getCodeResponse(404) : $responses->getIdentifiersResponse($relData);
213
214 1
        return $response;
215
    }
216
217
    /**
218
     * @param ContainerInterface $container
219
     * @param string|null        $class
220
     *
221
     * @return CrudInterface
222
     */
223 20
    protected static function createApi(ContainerInterface $container, string $class = null): CrudInterface
224
    {
225
        /** @var FactoryInterface $factory */
226 20
        $factory = $container->get(FactoryInterface::class);
227 20
        $api     = $factory->createApi($class ?? static::API_CLASS);
228
229 20
        return $api;
230
    }
231
232
    /**
233
     * @param ContainerInterface          $container
234
     * @param EncodingParametersInterface $parameters
235
     * @param string                      $schemaClass
236
     *
237
     * @return array
238
     */
239 16
    protected static function mapSchemeToModelParameters(
240
        ContainerInterface $container,
241
        EncodingParametersInterface $parameters,
242
        string $schemaClass
243
    ): array {
244
        /** @var FactoryInterface $factory */
245 16
        $factory          = $container->get(FactoryInterface::class);
246 16
        $errors           = $factory->createErrorCollection();
247 16
        $queryTransformer = new QueryTransformer(
248 16
            $container->get(ModelSchemeInfoInterface::class),
249 16
            $container->get(JsonSchemesInterface::class),
250 16
            static::createMessageFormatter($container),
251 16
            $schemaClass
252
        );
253
254 16
        $result = $queryTransformer->mapParameters($errors, $parameters);
255 16
        if ($errors->count() > 0) {
256 2
            throw new JsonApiException($errors);
257
        }
258
259 14
        return $result;
260
    }
261
262
    /**
263
     * @param ContainerInterface     $container
264
     * @param ServerRequestInterface $request
265
     *
266
     * @return array
267
     */
268 7
    protected static function readJsonFromRequest(ContainerInterface $container, ServerRequestInterface $request): array
269
    {
270 7
        $body = (string)$request->getBody();
271 7
        if (empty($body) === true || ($json = json_decode($body, true)) === null) {
272
            /** @var FactoryInterface $factory */
273 1
            $factory = $container->get(FactoryInterface::class);
274 1
            $errors  = $factory->createErrorCollection();
275 1
            $errors->addDataError(
276 1
                static::createMessageFormatter($container)->formatMessage(Messages::MSG_ERR_INVALID_ELEMENT)
277
            );
278
279 1
            throw new JsonApiException($errors);
280
        }
281
282 6
        return $json;
283
    }
284
285
    /**
286
     * @param array              $routeParams
287
     * @param ContainerInterface $container
288
     * @param array              $jsonData
289
     *
290
     * @return array
291
     *
292
     * @SuppressWarnings(PHPMD.ElseExpression)
293
     */
294 3
    protected static function normalizeIndexValueOnUpdate(
295
        array $routeParams,
296
        ContainerInterface $container,
297
        array $jsonData
298
    ): array {
299
        // check that index in data and URL are identical
300 3
        $index         = $routeParams[static::ROUTE_KEY_INDEX];
301 3
        $dataSection   = null;
302
        $hasIndexValue =
303 3
            array_key_exists(DI::KEYWORD_DATA, $jsonData) &&
304 3
            array_key_exists(DI::KEYWORD_ID, ($dataSection = $jsonData[DI::KEYWORD_DATA]));
305 3
        if ($hasIndexValue === true) {
306 2
            assert($dataSection !== null);
307 2
            if ($dataSection[DI::KEYWORD_ID] !== $index) {
308
                /** @var FactoryInterface $factory */
309 1
                $factory = $container->get(FactoryInterface::class);
310 1
                $errors  = $factory->createErrorCollection();
311 1
                $errors->addDataIdError(
312 1
                    static::createMessageFormatter($container)->formatMessage(Messages::MSG_ERR_INVALID_ELEMENT)
313
                );
314
315 2
                throw new JsonApiException($errors);
316
            }
317
        } else {
318
            // put the index to data for our convenience
319 1
            $jsonData[DI::KEYWORD_DATA][DI::KEYWORD_ID] = $index;
320
        }
321
322 2
        return $jsonData;
323
    }
324
325
    /**
326
     * @param int|string             $parentIndex
327
     * @param string                 $relationshipName
328
     * @param int|string             $childIndex
329
     * @param string                 $childApiClass
330
     * @param ContainerInterface     $container
331
     * @param ServerRequestInterface $request
332
     *
333
     * @return ResponseInterface
334
     */
335 1 View Code Duplication
    protected static function deleteInRelationship(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
336
        $parentIndex,
337
        string $relationshipName,
338
        $childIndex,
339
        string $childApiClass,
340
        ContainerInterface $container,
341
        ServerRequestInterface $request
342
    ): ResponseInterface {
343
        /** @var SchemaInterface $schemaClass */
344 1
        $schemaClass  = static::SCHEMA_CLASS;
345 1
        $modelRelName = $schemaClass::getRelationshipMapping($relationshipName);
346 1
        $hasChild     = self::createApi($container)->hasInRelationship($parentIndex, $modelRelName, $childIndex);
347 1
        if ($hasChild === false) {
348 1
            return static::createResponses($container, $request)->getCodeResponse(404);
349
        }
350
351 1
        $childApi = self::createApi($container, $childApiClass);
352
353 1
        return static::deleteImpl($childIndex, $container, $request, $childApi);
0 ignored issues
show
Bug introduced by
Since deleteImpl() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of deleteImpl() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
354
    }
355
356
    /** @noinspection PhpTooManyParametersInspection
357
     * @param int|string             $parentIndex
358
     * @param string                 $relationshipName
359
     * @param int|string             $childIndex
360
     * @param array                  $attributes
361
     * @param array                  $toMany
362
     * @param string                 $childApiClass
363
     * @param ContainerInterface     $container
364
     * @param ServerRequestInterface $request
365
     *
366
     * @return ResponseInterface
367
     */
368 2 View Code Duplication
    protected static function updateInRelationship(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
369
        $parentIndex,
370
        string $relationshipName,
371
        $childIndex,
372
        array $attributes,
373
        array $toMany,
374
        string $childApiClass,
375
        ContainerInterface $container,
376
        ServerRequestInterface $request
377
    ): ResponseInterface {
378
        /** @var SchemaInterface $schemaClass */
379 2
        $schemaClass  = static::SCHEMA_CLASS;
380 2
        $modelRelName = $schemaClass::getRelationshipMapping($relationshipName);
381 2
        $hasChild     = self::createApi($container)->hasInRelationship($parentIndex, $modelRelName, $childIndex);
382 2
        if ($hasChild === false) {
383 1
            return static::createResponses($container, $request)->getCodeResponse(404);
384
        }
385
386 1
        $childApi = self::createApi($container, $childApiClass);
387
388 1
        return static::updateImpl($childIndex, $attributes, $toMany, $container, $request, $childApi);
0 ignored issues
show
Bug introduced by
Since updateImpl() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of updateImpl() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
389
    }
390
391
    /**
392
     * @param ContainerInterface $container
393
     *
394
     * @return JsonApiValidatorInterface
395
     */
396 1 View Code Duplication
    protected static function createOnCreateValidator(ContainerInterface $container): JsonApiValidatorInterface
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
397
    {
398 1
        assert(
399 1
            empty(static::ON_CREATE_VALIDATION_RULES_SET_CLASS) === false,
400 1
            'Validation rules set should be defined for class ' . static::class . '.'
401
        );
402
403 1
        return static::createJsonApiValidator($container, static::ON_CREATE_VALIDATION_RULES_SET_CLASS);
404
    }
405
406
    /**
407
     * @param ContainerInterface $container
408
     *
409
     * @return JsonApiValidatorInterface
410
     */
411 2 View Code Duplication
    protected static function createOnUpdateValidator(ContainerInterface $container): JsonApiValidatorInterface
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
412
    {
413 2
        assert(
414 2
            empty(static::ON_UPDATE_VALIDATION_RULES_SET_CLASS) === false,
415 2
            'Validation rules set should be defined for class ' . static::class . '.'
416
        );
417
418 2
        return static::createJsonApiValidator($container, static::ON_UPDATE_VALIDATION_RULES_SET_CLASS);
419
    }
420
421
    /**
422
     * @param ContainerInterface $container
423
     * @param string             $rulesSetClass
424
     *
425
     * @return JsonApiValidatorInterface
426
     */
427 5
    protected static function createJsonApiValidator(
428
        ContainerInterface $container,
429
        string $rulesSetClass
430
    ): JsonApiValidatorInterface {
431
        /** @var JsonApiValidatorFactoryInterface $validatorFactory */
432 5
        $validatorFactory = $container->get(JsonApiValidatorFactoryInterface::class);
433 5
        $validator        = $validatorFactory->createValidator($rulesSetClass);
434
435 5
        return $validator;
436
    }
437
438
    /**
439
     * @param ContainerInterface $container
440
     * @param array              $captures
441
     * @param string             $schemeClass
442
     *
443
     * @return array
444
     */
445 4
    protected static function mapSchemeDataToModelData(
446
        ContainerInterface $container,
447
        array $captures,
448
        string $schemeClass
449
    ): array {
450 4
        assert(in_array(SchemaInterface::class, class_implements($schemeClass)));
451
        /** @var SchemaInterface $schemeClass */
452
453 4
        $modelClass = $schemeClass::MODEL;
454 4
        assert(in_array(ModelInterface::class, class_implements($modelClass)));
455
        /** @var ModelInterface $modelClass */
456
457
        /** @var ModelSchemeInfoInterface $schemeInfo */
458 4
        $schemeInfo = $container->get(ModelSchemeInfoInterface::class);
459
460 4
        $index         = null;
461 4
        $fields        = [];
462 4
        $toManyIndexes = [];
463 4
        foreach ($captures as $name => $value) {
464 4
            if ($name === DI::KEYWORD_ID) {
465 4
                $index = $value;
466 4
            } elseif ($schemeClass::hasAttributeMapping($name) === true) {
467 4
                $fieldName          = $schemeClass::getAttributeMapping($name);
468 4
                $fields[$fieldName] = $value;
469 4
            } elseif ($schemeClass::hasRelationshipMapping($name) === true) {
470 2
                $modelRelName = $schemeClass::getRelationshipMapping($name);
471 2
                $relType      = $schemeInfo->getRelationshipType($modelClass, $modelRelName);
472 2
                if ($relType === RelationshipTypes::BELONGS_TO) {
473 2
                    $fkName          = $schemeInfo->getForeignKey($modelClass, $modelRelName);
474 2
                    $fields[$fkName] = $value;
475 2
                } elseif ($relType === RelationshipTypes::BELONGS_TO_MANY) {
476 4
                    $toManyIndexes[$modelRelName] = $value;
477
                }
478
            }
479
        }
480
481 4
        $result = [$index, $fields, $toManyIndexes];
482
483 4
        return $result;
484
    }
485
486
    /**
487
     * @param CrudInterface                  $api
488
     * @param ResponsesInterface             $responses
489
     * @param string|int                     $index
490
     * @param FilterParameterCollection|null $filters
491
     * @param array|null                     $includes
492
     *
493
     * @return mixed
494
     */
495 3
    private static function readImpl(
496
        CrudInterface $api,
497
        ResponsesInterface $responses,
498
        $index,
499
        FilterParameterCollection $filters = null,
500
        array $includes = null
501
    ) {
502 3
        $modelData = $api->read($index, $filters, $includes);
503 3
        $response  = $modelData->getData() === null ?
504 3
            $responses->getCodeResponse(404) : $responses->getContentResponse($modelData);
505
506 3
        return $response;
507
    }
508
509
    /**
510
     * @param string                      $index
511
     * @param string                      $relationshipName
512
     * @param ContainerInterface          $container
513
     * @param EncodingParametersInterface $encodingParams
514
     *
515
     * @return PaginatedDataInterface
516
     */
517 3
    private static function readRelationshipData(
518
        string $index,
519
        string $relationshipName,
520
        ContainerInterface $container,
521
        EncodingParametersInterface $encodingParams
522
    ): PaginatedDataInterface {
523
        /** @var JsonSchemesInterface $jsonSchemes */
524 3
        $jsonSchemes  = $container->get(JsonSchemesInterface::class);
525 3
        $targetSchema = $jsonSchemes->getRelationshipSchema(static::SCHEMA_CLASS, $relationshipName);
526
        list ($filters, $sorts, , $paging) =
527 3
            static::mapSchemeToModelParameters($container, $encodingParams, get_class($targetSchema));
528
529
        /** @var SchemaInterface $schemaClass */
530 3
        $schemaClass  = static::SCHEMA_CLASS;
531 3
        $modelRelName = $schemaClass::getRelationshipMapping($relationshipName);
532 3
        $relData      = self::createApi($container)->readRelationship($index, $modelRelName, $filters, $sorts, $paging);
533
534 3
        return $relData;
535
    }
536
537
    /**
538
     * @param ContainerInterface     $container
539
     * @param ServerRequestInterface $request
540
     *
541
     * @return EncodingParametersInterface
542
     */
543 16
    private static function parseQueryParameters(
544
        ContainerInterface $container,
545
        ServerRequestInterface $request
546
    ): EncodingParametersInterface {
547
        /** @var QueryParametersParserInterface $queryParser */
548 16
        $queryParser    = $container->get(QueryParametersParserInterface::class);
549 16
        $encodingParams = $queryParser->parse($request);
550
551 16
        return $encodingParams;
552
    }
553
554
    /**
555
     * @param string|int             $index
556
     * @param array                  $attributes
557
     * @param array                  $toMany
558
     * @param ContainerInterface     $container
559
     * @param ServerRequestInterface $request
560
     * @param CrudInterface          $api
561
     *
562
     * @return ResponseInterface
563
     */
564 2
    private static function updateImpl(
565
        $index,
566
        array $attributes,
567
        array $toMany,
568
        ContainerInterface $container,
569
        ServerRequestInterface $request,
570
        CrudInterface $api
571
    ): ResponseInterface {
572 2
        $api->update($index, $attributes, $toMany);
573
574 2
        $response = static::readImpl($api, static::createResponses($container, $request), $index);
0 ignored issues
show
Bug introduced by
Since readImpl() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of readImpl() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
575
576 2
        return $response;
577
    }
578
579
    /**
580
     * @param string|int             $index
581
     * @param ContainerInterface     $container
582
     * @param ServerRequestInterface $request
583
     * @param CrudInterface          $api
584
     *
585
     * @return ResponseInterface
586
     */
587 2
    private static function deleteImpl(
588
        $index,
589
        ContainerInterface $container,
590
        ServerRequestInterface $request,
591
        CrudInterface $api
592
    ): ResponseInterface {
593 2
        $api->delete($index);
594 2
        $response = static::createResponses($container, $request)->getCodeResponse(204);
595
596 2
        return $response;
597
    }
598
599
    /**
600
     * @param ContainerInterface $container
601
     * @param string             $namespace
602
     *
603
     * @return FormatterInterface
604
     */
605 18
    protected static function createMessageFormatter(
606
        ContainerInterface $container,
607
        string $namespace = Messages::RESOURCES_NAMESPACE
608
    ): FormatterInterface {
609
        /** @var FormatterFactoryInterface $factory */
610 18
        $factory          = $container->get(FormatterFactoryInterface::class);
611 18
        $messageFormatter = $factory->createFormatter($namespace);
612
613 18
        return $messageFormatter;
614
    }
615
}
616