Completed
Push — develop ( 599906...c694a4 )
by Neomerx
03:50 queued 02:08
created

BaseController::deleteInRelationship()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 15

Duplication

Lines 20
Ratio 100 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
dl 20
loc 20
ccs 8
cts 8
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 15
nc 2
nop 6
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
    /** URI key used in routing table */
66
    const ROUTE_KEY_INDEX = 'idx';
67
68
    /**
69
     * @inheritdoc
70
     */
71 12
    public static function index(
72
        array $routeParams,
73
        ContainerInterface $container,
74
        ServerRequestInterface $request
75
    ): ResponseInterface {
76
        /** @var QueryParametersParserInterface $queryParser */
77 12
        $queryParser    = $container->get(QueryParametersParserInterface::class);
78 12
        $encodingParams = $queryParser->parse($request);
79
80
        list ($filters, $sorts, $includes, $paging) =
81 12
            static::mapQueryParameters($container, $encodingParams, static::SCHEMA_CLASS);
82
83 10
        $modelData = static::createApi($container)->index($filters, $sorts, $includes, $paging);
84 10
        $responses = static::createResponses($container, $request, $encodingParams);
85 10
        $response  = $modelData->getPaginatedData()->getData() === null ?
86 10
            $responses->getCodeResponse(404) : $responses->getContentResponse($modelData);
87
88 10
        return $response;
89
    }
90
91
    /**
92
     * @inheritdoc
93
     */
94 1
    public static function create(
95
        array $routeParams,
96
        ContainerInterface $container,
97
        ServerRequestInterface $request
98
    ): ResponseInterface {
99 1
        $validator = static::createOnCreateValidator($container);
100 1
        $jsonData  = static::readJsonFromRequest($container, $request);
101 1
        $captures  = $validator->assert($jsonData)->getJsonApiCaptures();
102
103
        list ($index, $attributes, $toMany) =
104 1
            static::mapSchemeDataToModelData($container, $captures, static::SCHEMA_CLASS);
105
106 1
        $api   = self::createApi($container);
107 1
        $index = $api->create($index, $attributes, $toMany);
108 1
        $data  = $api->read($index);
109
110 1
        $response = static::createResponses($container, $request)->getCreatedResponse($data);
111
112 1
        return $response;
113
    }
114
115
    /**
116
     * @inheritdoc
117
     */
118 1
    public static function read(
119
        array $routeParams,
120
        ContainerInterface $container,
121
        ServerRequestInterface $request
122
    ): ResponseInterface {
123
        /** @var QueryParametersParserInterface $queryParser */
124 1
        $queryParser    = $container->get(QueryParametersParserInterface::class);
125 1
        $encodingParams = $queryParser->parse($request);
126
127 1
        list ($filters, , $includes) = static::mapQueryParameters($container, $encodingParams, static::SCHEMA_CLASS);
128
129 1
        $index    = $routeParams[static::ROUTE_KEY_INDEX];
130 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...
131 1
            static::createApi($container),
132 1
            static::createResponses($container, $request, $encodingParams),
133 1
            $index,
134 1
            $filters,
135 1
            $includes
136
        );
137
138 1
        return $response;
139
    }
140
141
    /**
142
     * @inheritdoc
143
     */
144 4
    public static function update(
145
        array $routeParams,
146
        ContainerInterface $container,
147
        ServerRequestInterface $request
148
    ): ResponseInterface {
149 4
        $validator = static::createOnUpdateValidator($container);
150 4
        $jsonData  = static::readJsonFromRequest($container, $request);
151 3
        $jsonData  = static::normalizeIndexValueOnUpdate($routeParams, $container, $jsonData);
152 2
        $captures  = $validator->assert($jsonData)->getJsonApiCaptures();
153
154
        list ($index, $attributes, $toMany) =
155 1
            static::mapSchemeDataToModelData($container, $captures, static::SCHEMA_CLASS);
156 1
        $api = self::createApi($container);
157
158 1
        return self::updateImpl($index, $attributes, $toMany, $container, $request, $api);
159
    }
160
161
    /**
162
     * @inheritdoc
163
     */
164 1
    public static function delete(
165
        array $routeParams,
166
        ContainerInterface $container,
167
        ServerRequestInterface $request
168
    ): ResponseInterface {
169 1
        $index = $routeParams[static::ROUTE_KEY_INDEX];
170
171 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...
172
    }
173
174
    /**
175
     * @param string                 $index
176
     * @param string                 $relationshipName
177
     * @param ContainerInterface     $container
178
     * @param ServerRequestInterface $request
179
     *
180
     * @return ResponseInterface
181
     */
182 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...
183
        string $index,
184
        string $relationshipName,
185
        ContainerInterface $container,
186
        ServerRequestInterface $request
187
    ): ResponseInterface {
188
        /** @var PaginatedDataInterface $relData */
189
        /** @var EncodingParametersInterface $encodingParams */
190 2
        list ($relData, $encodingParams) = self::readRelationshipData($index, $relationshipName, $container, $request);
191
192 2
        $responses = static::createResponses($container, $request, $encodingParams);
193 2
        $response  = $relData->getData() === null ?
194 2
            $responses->getCodeResponse(404) : $responses->getContentResponse($relData);
195
196 2
        return $response;
197
    }
198
199
    /**
200
     * @param string                 $index
201
     * @param string                 $relationshipName
202
     * @param ContainerInterface     $container
203
     * @param ServerRequestInterface $request
204
     *
205
     * @return ResponseInterface
206
     */
207 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...
208
        string $index,
209
        string $relationshipName,
210
        ContainerInterface $container,
211
        ServerRequestInterface $request
212
    ): ResponseInterface {
213
        /** @var PaginatedDataInterface $relData */
214
        /** @var EncodingParametersInterface $encodingParams */
215 1
        list ($relData, $encodingParams) = self::readRelationshipData($index, $relationshipName, $container, $request);
216
217 1
        $responses = static::createResponses($container, $request, $encodingParams);
218 1
        $response  = $relData->getData() === null ?
219 1
            $responses->getCodeResponse(404) : $responses->getIdentifiersResponse($relData);
220
221 1
        return $response;
222
    }
223
224
    /**
225
     * @param ContainerInterface $container
226
     * @param string|null        $class
227
     *
228
     * @return CrudInterface
229
     */
230 20
    protected static function createApi(ContainerInterface $container, string $class = null): CrudInterface
231
    {
232
        /** @var FactoryInterface $factory */
233 20
        $factory = $container->get(FactoryInterface::class);
234 20
        $api     = $factory->createApi($class ?? static::API_CLASS);
235
236 20
        return $api;
237
    }
238
239
    /**
240
     * @param ContainerInterface          $container
241
     * @param EncodingParametersInterface $parameters
242
     * @param string                      $schemaClass
243
     *
244
     * @return array
245
     */
246 16
    protected static function mapQueryParameters(
247
        ContainerInterface $container,
248
        EncodingParametersInterface $parameters,
249
        string $schemaClass
250
    ): array {
251
        /** @var FactoryInterface $factory */
252 16
        $factory          = $container->get(FactoryInterface::class);
253 16
        $errors           = $factory->createErrorCollection();
254 16
        $queryTransformer = new QueryTransformer(
255 16
            $container->get(ModelSchemeInfoInterface::class),
256 16
            $container->get(JsonSchemesInterface::class),
257 16
            static::createMessageFormatter($container),
258 16
            $schemaClass
259
        );
260
261 16
        $result = $queryTransformer->mapParameters($errors, $parameters);
262 16
        if ($errors->count() > 0) {
263 2
            throw new JsonApiException($errors);
264
        }
265
266 14
        return $result;
267
    }
268
269
    /**
270
     * @param ContainerInterface     $container
271
     * @param ServerRequestInterface $request
272
     *
273
     * @return array
274
     */
275 7
    protected static function readJsonFromRequest(ContainerInterface $container, ServerRequestInterface $request): array
276
    {
277 7
        $body = (string)$request->getBody();
278 7
        if (empty($body) === true || ($json = json_decode($body, true)) === null) {
279
            /** @var FactoryInterface $factory */
280 1
            $factory = $container->get(FactoryInterface::class);
281 1
            $errors  = $factory->createErrorCollection();
282 1
            $errors->addDataError(
283 1
                static::createMessageFormatter($container)->formatMessage(Messages::MSG_ERR_INVALID_ELEMENT)
284
            );
285
286 1
            throw new JsonApiException($errors);
287
        }
288
289 6
        return $json;
290
    }
291
292
    /**
293
     * @param array              $routeParams
294
     * @param ContainerInterface $container
295
     * @param array              $jsonData
296
     *
297
     * @return array
298
     *
299
     * @SuppressWarnings(PHPMD.ElseExpression)
300
     */
301 3
    protected static function normalizeIndexValueOnUpdate(
302
        array $routeParams,
303
        ContainerInterface $container,
304
        array $jsonData
305
    ): array {
306
        // check that index in data and URL are identical
307 3
        $index         = $routeParams[static::ROUTE_KEY_INDEX];
308 3
        $dataSection   = null;
309
        $hasIndexValue =
310 3
            array_key_exists(DI::KEYWORD_DATA, $jsonData) &&
311 3
            array_key_exists(DI::KEYWORD_ID, ($dataSection = $jsonData[DI::KEYWORD_DATA]));
312 3
        if ($hasIndexValue === true) {
313 2
            assert($dataSection !== null);
314 2
            if ($dataSection[DI::KEYWORD_ID] !== $index) {
315
                /** @var FactoryInterface $factory */
316 1
                $factory = $container->get(FactoryInterface::class);
317 1
                $errors  = $factory->createErrorCollection();
318 1
                $errors->addDataIdError(
319 1
                    static::createMessageFormatter($container)->formatMessage(Messages::MSG_ERR_INVALID_ELEMENT)
320
                );
321
322 2
                throw new JsonApiException($errors);
323
            }
324
        } else {
325
            // put the index to data for our convenience
326 1
            $jsonData[DI::KEYWORD_DATA][DI::KEYWORD_ID] = $index;
327
        }
328
329 2
        return $jsonData;
330
    }
331
332
    /**
333
     * @param int|string             $parentIndex
334
     * @param string                 $relationshipName
335
     * @param int|string             $childIndex
336
     * @param string                 $childApiClass
337
     * @param ContainerInterface     $container
338
     * @param ServerRequestInterface $request
339
     *
340
     * @return ResponseInterface
341
     */
342 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...
343
        $parentIndex,
344
        string $relationshipName,
345
        $childIndex,
346
        string $childApiClass,
347
        ContainerInterface $container,
348
        ServerRequestInterface $request
349
    ): ResponseInterface {
350
        /** @var SchemaInterface $schemaClass */
351 1
        $schemaClass  = static::SCHEMA_CLASS;
352 1
        $modelRelName = $schemaClass::getRelationshipMapping($relationshipName);
353 1
        $hasChild     = self::createApi($container)->hasInRelationship($parentIndex, $modelRelName, $childIndex);
354 1
        if ($hasChild === false) {
355 1
            return static::createResponses($container, $request)->getCodeResponse(404);
356
        }
357
358 1
        $childApi = self::createApi($container, $childApiClass);
359
360 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...
361
    }
362
363
    /** @noinspection PhpTooManyParametersInspection
364
     * @param int|string             $parentIndex
365
     * @param string                 $relationshipName
366
     * @param int|string             $childIndex
367
     * @param array                  $attributes
368
     * @param array                  $toMany
369
     * @param string                 $childApiClass
370
     * @param ContainerInterface     $container
371
     * @param ServerRequestInterface $request
372
     *
373
     * @return ResponseInterface
374
     */
375 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...
376
        $parentIndex,
377
        string $relationshipName,
378
        $childIndex,
379
        array $attributes,
380
        array $toMany,
381
        string $childApiClass,
382
        ContainerInterface $container,
383
        ServerRequestInterface $request
384
    ): ResponseInterface {
385
        /** @var SchemaInterface $schemaClass */
386 2
        $schemaClass  = static::SCHEMA_CLASS;
387 2
        $modelRelName = $schemaClass::getRelationshipMapping($relationshipName);
388 2
        $hasChild     = self::createApi($container)->hasInRelationship($parentIndex, $modelRelName, $childIndex);
389 2
        if ($hasChild === false) {
390 1
            return static::createResponses($container, $request)->getCodeResponse(404);
391
        }
392
393 1
        $childApi = self::createApi($container, $childApiClass);
394
395 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...
396
    }
397
398
    /**
399
     * @param ContainerInterface $container
400
     *
401
     * @return JsonApiValidatorInterface
402
     */
403 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...
404
    {
405 1
        assert(
406 1
            empty(static::ON_CREATE_VALIDATION_RULES_SET_CLASS) === false,
407 1
            'Validation rules set should be defined for class ' . static::class . '.'
408
        );
409
410 1
        return static::createJsonApiValidator($container, static::ON_CREATE_VALIDATION_RULES_SET_CLASS);
411
    }
412
413
    /**
414
     * @param ContainerInterface $container
415
     *
416
     * @return JsonApiValidatorInterface
417
     */
418 4 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...
419
    {
420 4
        assert(
421 4
            empty(static::ON_UPDATE_VALIDATION_RULES_SET_CLASS) === false,
422 4
            'Validation rules set should be defined for class ' . static::class . '.'
423
        );
424
425 4
        return static::createJsonApiValidator($container, static::ON_UPDATE_VALIDATION_RULES_SET_CLASS);
426
    }
427
428
    /**
429
     * @param ContainerInterface $container
430
     * @param string             $rulesSetClass
431
     *
432
     * @return JsonApiValidatorInterface
433
     */
434 7
    protected static function createJsonApiValidator(
435
        ContainerInterface $container,
436
        string $rulesSetClass
437
    ): JsonApiValidatorInterface {
438
        /** @var JsonApiValidatorFactoryInterface $validatorFactory */
439 7
        $validatorFactory = $container->get(JsonApiValidatorFactoryInterface::class);
440 7
        $validator        = $validatorFactory->createValidator($rulesSetClass);
441
442 7
        return $validator;
443
    }
444
445
    /**
446
     * @param ContainerInterface $container
447
     * @param array              $captures
448
     * @param string             $schemeClass
449
     *
450
     * @return array
451
     */
452 4
    protected static function mapSchemeDataToModelData(
453
        ContainerInterface $container,
454
        array $captures,
455
        string $schemeClass
456
    ): array {
457 4
        assert(in_array(SchemaInterface::class, class_implements($schemeClass)));
458
        /** @var SchemaInterface $schemeClass */
459
460 4
        $modelClass = $schemeClass::MODEL;
461 4
        assert(in_array(ModelInterface::class, class_implements($modelClass)));
462
        /** @var ModelInterface $modelClass */
463
464
        /** @var ModelSchemeInfoInterface $schemeInfo */
465 4
        $schemeInfo = $container->get(ModelSchemeInfoInterface::class);
466
467 4
        $index         = null;
468 4
        $fields        = [];
469 4
        $toManyIndexes = [];
470 4
        foreach ($captures as $name => $value) {
471 4
            if ($name === DI::KEYWORD_ID) {
472 4
                $index = $value;
473 4
            } elseif ($schemeClass::hasAttributeMapping($name) === true) {
474 4
                $fieldName          = $schemeClass::getAttributeMapping($name);
475 4
                $fields[$fieldName] = $value;
476 4
            } elseif ($schemeClass::hasRelationshipMapping($name) === true) {
477 2
                $modelRelName = $schemeClass::getRelationshipMapping($name);
478 2
                $relType      = $schemeInfo->getRelationshipType($modelClass, $modelRelName);
479 2
                if ($relType === RelationshipTypes::BELONGS_TO) {
480 2
                    $fkName          = $schemeInfo->getForeignKey($modelClass, $modelRelName);
481 2
                    $fields[$fkName] = $value;
482 2
                } elseif ($relType === RelationshipTypes::BELONGS_TO_MANY) {
483 4
                    $toManyIndexes[$modelRelName] = $value;
484
                }
485
            }
486
        }
487
488 4
        $result = [$index, $fields, $toManyIndexes];
489
490 4
        return $result;
491
    }
492
493
    /**
494
     * @param CrudInterface                  $api
495
     * @param ResponsesInterface             $responses
496
     * @param string|int                     $index
497
     * @param FilterParameterCollection|null $filters
498
     * @param array|null                     $includes
499
     *
500
     * @return mixed
501
     */
502 3
    private static function readImpl(
503
        CrudInterface $api,
504
        ResponsesInterface $responses,
505
        $index,
506
        FilterParameterCollection $filters = null,
507
        array $includes = null
508
    ) {
509 3
        $modelData = $api->read($index, $filters, $includes);
510 3
        $response  = $modelData->getPaginatedData()->getData() === null ?
511 3
            $responses->getCodeResponse(404) : $responses->getContentResponse($modelData);
512
513 3
        return $response;
514
    }
515
516
    /**
517
     * @param string                 $index
518
     * @param string                 $relationshipName
519
     * @param ContainerInterface     $container
520
     * @param ServerRequestInterface $request
521
     *
522
     * @return array [PaginatedDataInterface, EncodingParametersInterface]
523
     */
524 3
    private static function readRelationshipData(
525
        string $index,
526
        string $relationshipName,
527
        ContainerInterface $container,
528
        ServerRequestInterface $request
529
    ): array {
530
        /** @var QueryParametersParserInterface $queryParser */
531 3
        $queryParser    = $container->get(QueryParametersParserInterface::class);
532 3
        $encodingParams = $queryParser->parse($request);
533
534
        /** @var JsonSchemesInterface $jsonSchemes */
535 3
        $jsonSchemes  = $container->get(JsonSchemesInterface::class);
536 3
        $targetSchema = $jsonSchemes->getRelationshipSchema(static::SCHEMA_CLASS, $relationshipName);
537
        list ($filters, $sorts, , $paging) =
538 3
            static::mapQueryParameters($container, $encodingParams, get_class($targetSchema));
539
540
        /** @var SchemaInterface $schemaClass */
541 3
        $schemaClass  = static::SCHEMA_CLASS;
542 3
        $modelRelName = $schemaClass::getRelationshipMapping($relationshipName);
543 3
        $relData      = self::createApi($container)->readRelationship($index, $modelRelName, $filters, $sorts, $paging);
544
545 3
        return [$relData, $encodingParams];
546
    }
547
548
    /**
549
     * @param string|int             $index
550
     * @param array                  $attributes
551
     * @param array                  $toMany
552
     * @param ContainerInterface     $container
553
     * @param ServerRequestInterface $request
554
     * @param CrudInterface          $api
555
     *
556
     * @return ResponseInterface
557
     */
558 2
    private static function updateImpl(
559
        $index,
560
        array $attributes,
561
        array $toMany,
562
        ContainerInterface $container,
563
        ServerRequestInterface $request,
564
        CrudInterface $api
565
    ): ResponseInterface {
566 2
        $api->update($index, $attributes, $toMany);
567
568 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...
569
570 2
        return $response;
571
    }
572
573
    /**
574
     * @param string|int             $index
575
     * @param ContainerInterface     $container
576
     * @param ServerRequestInterface $request
577
     * @param CrudInterface          $api
578
     *
579
     * @return ResponseInterface
580
     */
581 2
    private static function deleteImpl(
582
        $index,
583
        ContainerInterface $container,
584
        ServerRequestInterface $request,
585
        CrudInterface $api
586
    ): ResponseInterface {
587 2
        $api->delete($index);
588 2
        $response = static::createResponses($container, $request)->getCodeResponse(204);
589
590 2
        return $response;
591
    }
592
593
    /**
594
     * @param ContainerInterface $container
595
     * @param string             $namespace
596
     *
597
     * @return FormatterInterface
598
     */
599 18
    protected static function createMessageFormatter(
600
        ContainerInterface $container,
601
        string $namespace = Messages::RESOURCES_NAMESPACE
602
    ): FormatterInterface {
603
        /** @var FormatterFactoryInterface $factory */
604 18
        $factory          = $container->get(FormatterFactoryInterface::class);
605 18
        $messageFormatter = $factory->createFormatter($namespace);
606
607 18
        return $messageFormatter;
608
    }
609
}
610