Completed
Push — master ( 0ca994...bcdd07 )
by Neomerx
05:23
created

BaseController::readJsonFromRequest()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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