Skip to content

Commit 650e8b7

Browse files
authored
Merge pull request #2 from FastyBird/feature/constructor-params
Added parameters from entity constructor
2 parents 86f1f3c + 19c264b commit 650e8b7

File tree

12 files changed

+90
-51
lines changed

12 files changed

+90
-51
lines changed

composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@
5050
"nette/di" : "^3.1",
5151
"nette/utils" : "^3.2||^4.0",
5252
"phpdocumentor/reflection-docblock" : "^5.3",
53-
"psr/http-factory" : "^1.0",
54-
"psr/http-message" : "^1.0",
53+
"psr/http-factory" : "^1.1",
54+
"psr/http-message" : "^1.1",
5555
"psr/http-server-middleware" : "^1.0",
5656
"psr/log" : "^1.1|^3.0",
57-
"ramsey/uuid" : "^4.2"
57+
"ramsey/uuid" : "^4.7"
5858
},
5959

6060
"require-dev" : {

src/Builder/Builder.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
use Neomerx\JsonApi\Contracts;
2222
use Neomerx\JsonApi\Schema;
2323
use Nette\DI;
24-
use Nette\Utils;
2524
use Psr\Http\Message\ResponseInterface;
2625
use Psr\Http\Message\ServerRequestInterface;
2726
use Psr\Http\Message\UriInterface;
@@ -33,6 +32,7 @@
3332
use function http_build_query;
3433
use function is_array;
3534
use function round;
35+
use function str_contains;
3636
use function str_replace;
3737
use function str_starts_with;
3838
use function strval;
@@ -62,7 +62,7 @@ class Builder
6262
private const LINK_PREV = Contracts\Schema\DocumentInterface::KEYWORD_PREV;
6363

6464
/**
65-
* @param string|Array<string> $metaAuthor
65+
* @param string|array<string> $metaAuthor
6666
*/
6767
public function __construct(
6868
private readonly DI\Container $container,
@@ -73,7 +73,7 @@ public function __construct(
7373
}
7474

7575
/**
76-
* @param object|Array<object>|null $entity
76+
* @param object|array<object>|null $entity
7777
* @param callable(string): bool $linkValidator
7878
*
7979
* @throws InvalidArgumentException
@@ -153,7 +153,7 @@ public function build(
153153

154154
$encoder->withLinks($links);
155155

156-
if (Utils\Strings::contains($request->getUri()->getPath(), '/relationships/')) {
156+
if (str_contains($request->getUri()->getPath(), '/relationships/')) {
157157
$encodedData = $encoder->encodeDataAsArray($entity);
158158

159159
// Try to get "self" link from encoded entity as array
@@ -244,7 +244,7 @@ private function uriToString(UriInterface $uri): string
244244
}
245245

246246
/**
247-
* @return Array<mixed>
247+
* @return array<mixed>
248248
*/
249249
private function getBaseMeta(): array
250250
{

src/Exceptions/JsonApiError.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
use Exception as PHPException;
1919
use Neomerx\JsonApi as NeomerxJsonApi;
20-
use Stringable;
20+
use function strval;
2121

2222
/**
2323
* Process single error
@@ -31,14 +31,14 @@ class JsonApiError extends PHPException implements Exception, JsonApi
3131
{
3232

3333
/**
34-
* @param Array<mixed>|null $source
34+
* @param array<mixed>|null $source
3535
*/
3636
public function __construct(
3737
int $code,
38-
string|Stringable $title,
39-
private readonly string|Stringable|null $detail = null,
38+
string $title,
39+
private readonly string|null $detail = null,
4040
private readonly array|null $source = null,
41-
private readonly string|Stringable|null $type = null,
41+
private readonly string|null $type = null,
4242
)
4343
{
4444
parent::__construct($title, $code);
@@ -47,13 +47,13 @@ public function __construct(
4747
public function getError(): NeomerxJsonApi\Schema\Error
4848
{
4949
return new NeomerxJsonApi\Schema\Error(
50-
$this->getType(),
50+
strval($this->getType()),
5151
null,
5252
null,
5353
(string) $this->code,
5454
(string) $this->code,
5555
$this->message,
56-
$this->getDetail(),
56+
strval($this->getDetail()),
5757
$this->getSource(),
5858
);
5959
}
@@ -69,7 +69,7 @@ public function getDetail(): string|null
6969
}
7070

7171
/**
72-
* @return Array<mixed>|null
72+
* @return array<mixed>|null
7373
*/
7474
public function getSource(): array|null
7575
{

src/Exceptions/JsonApiMultipleError.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
use Exception as PHPException;
1919
use Fig\Http\Message\StatusCodeInterface;
2020
use Neomerx\JsonApi as NeomerxJsonApi;
21-
use Stringable;
2221

2322
/**
2423
* Process multiple error
@@ -31,7 +30,7 @@
3130
class JsonApiMultipleError extends PHPException implements JsonApi
3231
{
3332

34-
/** @var Array<NeomerxJsonApi\Schema\Error> */
33+
/** @var array<NeomerxJsonApi\Schema\Error> */
3534
private array $errors = [];
3635

3736
public function __construct()
@@ -43,14 +42,14 @@ public function __construct()
4342
}
4443

4544
/**
46-
* @param Array<string>|null $source
45+
* @param array<string>|null $source
4746
*/
4847
public function addError(
4948
int $code,
50-
string|Stringable $title,
51-
string|Stringable|null $detail = null,
49+
string $title,
50+
string|null $detail = null,
5251
array|null $source = null,
53-
string|Stringable|null $type = null,
52+
string|null $type = null,
5453
): void
5554
{
5655
$this->errors[] = new NeomerxJsonApi\Schema\Error(
@@ -71,7 +70,7 @@ public function hasErrors(): bool
7170
}
7271

7372
/**
74-
* @return Array<NeomerxJsonApi\Schema\Error>
73+
* @return array<NeomerxJsonApi\Schema\Error>
7574
*/
7675
public function getErrors(): array
7776
{

src/Helpers/CrudReader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public function __construct(Common\Cache\Cache|null $cache = null)
4444
}
4545

4646
/**
47-
* @return Array<bool>
47+
* @return array<bool>
4848
*/
4949
public function read(ReflectionProperty $rp): array
5050
{

src/Hydrators/Container.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,20 @@
2525
/**
2626
* API hydrators container
2727
*
28+
* @template T of object
29+
*
2830
* @package FastyBird:JsonApi!
2931
* @subpackage Hydrators
3032
*/
3133
class Container
3234
{
3335

34-
/** @var SplObjectStorage<Hydrator, null> */
36+
/** @var SplObjectStorage<Hydrator<T>, null> */
3537
private SplObjectStorage $hydrators;
3638

3739
private Log\LoggerInterface $logger;
3840

41+
/** @var JsonApi\SchemaContainer<T>|null */
3942
private JsonApi\SchemaContainer|null $jsonApiSchemaContainer = null;
4043

4144
public function __construct(
@@ -49,6 +52,8 @@ public function __construct(
4952
}
5053

5154
/**
55+
* @return Hydrator<T>|null
56+
*
5257
* @throws DI\MissingServiceException
5358
* @throws Exceptions\InvalidState
5459
*/
@@ -79,6 +84,9 @@ public function findHydrator(JsonAPIDocument\IDocument $document): Hydrator|null
7984
return null;
8085
}
8186

87+
/**
88+
* @param Hydrator<T> $hydrator
89+
*/
8290
public function add(Hydrator $hydrator): void
8391
{
8492
if (!$this->hydrators->contains($hydrator)) {
@@ -87,6 +95,8 @@ public function add(Hydrator $hydrator): void
8795
}
8896

8997
/**
98+
* @return JsonApi\SchemaContainer<T>
99+
*
90100
* @throws DI\MissingServiceException
91101
*/
92102
private function getSchemaContainer(): JsonApi\SchemaContainer

src/Hydrators/Fields/ArrayField.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public function __construct(
4242
/**
4343
* @param JsonAPIDocument\Objects\IStandardObject<string, mixed> $attributes
4444
*
45-
* @return Array<mixed>|null
45+
* @return array<mixed>|null
4646
*/
4747
public function getValue(JsonAPIDocument\Objects\IStandardObject $attributes): array|null
4848
{

src/Hydrators/Fields/SingleEntityField.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ final class SingleEntityField extends EntityField
3434
/**
3535
* @param JsonAPIDocument\Objects\IStandardObject<string, mixed> $attributes
3636
*
37-
* @return Array<mixed>|null
37+
* @return array<mixed>|null
3838
*
3939
* @throws Exceptions\InvalidState
4040
*/

src/Hydrators/Hydrator.php

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@
3434
use ReflectionClass;
3535
use ReflectionException;
3636
use ReflectionNamedType;
37+
use ReflectionParameter;
3738
use ReflectionProperty;
3839
use Throwable;
40+
use function array_filter;
3941
use function array_key_exists;
4042
use function array_map;
4143
use function array_merge;
@@ -57,6 +59,7 @@
5759
use function str_contains;
5860
use function str_replace;
5961
use function strtolower;
62+
use function strval;
6063
use function trim;
6164
use function ucfirst;
6265
use function ucwords;
@@ -174,8 +177,8 @@ public function hydrate(
174177
if (!$document->hasResource()) {
175178
throw new Exceptions\JsonApiError(
176179
StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY,
177-
$this->translator->translate('//jsonApi.hydrator.resourceInvalid.heading'),
178-
$this->translator->translate('//jsonApi.hydrator.resourceInvalid.message'),
180+
strval($this->translator->translate('//jsonApi.hydrator.resourceInvalid.heading')),
181+
strval($this->translator->translate('//jsonApi.hydrator.resourceInvalid.message')),
179182
[
180183
'pointer' => '/data',
181184
],
@@ -220,8 +223,8 @@ public function hydrate(
220223
if ($identifier === null || !Uuid\Uuid::isValid($identifier)) {
221224
throw new Exceptions\JsonApiError(
222225
StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY,
223-
$this->translator->translate('//jsonApi.hydrator.identifierInvalid.heading'),
224-
$this->translator->translate('//jsonApi.hydrator.identifierInvalid.message'),
226+
strval($this->translator->translate('//jsonApi.hydrator.identifierInvalid.heading')),
227+
strval($this->translator->translate('//jsonApi.hydrator.identifierInvalid.message')),
225228
[
226229
'pointer' => '/data/id',
227230
],
@@ -277,6 +280,22 @@ protected function mapEntity(string $entityClassName): array
277280
$reflectionProperties[] = $rp->getName();
278281
}
279282

283+
$constructorRequiredParameters = array_map(
284+
static fn (ReflectionParameter $parameter): string => $parameter->getName(),
285+
array_filter(
286+
$rc->getConstructor()?->getParameters() ?? [],
287+
static fn (ReflectionParameter $parameter): bool => !$parameter->isOptional(),
288+
),
289+
);
290+
291+
$constructorOptionalParameters = array_map(
292+
static fn (ReflectionParameter $parameter): string => $parameter->getName(),
293+
array_filter(
294+
$rc->getConstructor()?->getParameters() ?? [],
295+
static fn (ReflectionParameter $parameter): bool => $parameter->isOptional(),
296+
),
297+
);
298+
280299
$entityFields = array_unique(array_merge(
281300
$reflectionProperties,
282301
$classMetadata->getFieldNames(),
@@ -294,12 +313,22 @@ protected function mapEntity(string $entityClassName): array
294313
continue;
295314
}
296315

297-
if ($this->crudReader !== null) {
298-
[$isRequired, $isWritable] = $this->crudReader->read($rp) + [false, false];
299-
316+
if (
317+
in_array($fieldName, $constructorRequiredParameters, true)
318+
|| in_array($fieldName, $constructorOptionalParameters, true)
319+
) {
320+
[$isRequired, $isWritable] = [
321+
in_array($fieldName, $constructorRequiredParameters, true),
322+
in_array($fieldName, $constructorOptionalParameters, true),
323+
];
300324
} else {
301-
$isRequired = false;
302-
$isWritable = true;
325+
if ($this->crudReader !== null) {
326+
[$isRequired, $isWritable] = $this->crudReader->read($rp) + [false, false];
327+
328+
} else {
329+
$isRequired = false;
330+
$isWritable = true;
331+
}
303332
}
304333

305334
// Check if field is updatable
@@ -785,8 +814,8 @@ protected function hydrateAttributes(
785814
if ($value === null && $field->isRequired() && $isNew) {
786815
$this->errors->addError(
787816
StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY,
788-
$this->translator->translate('//jsonApi.hydrator.missingRequiredAttribute.heading'),
789-
$this->translator->translate('//jsonApi.hydrator.missingRequiredAttribute.message'),
817+
strval($this->translator->translate('//jsonApi.hydrator.missingRequiredAttribute.heading')),
818+
strval($this->translator->translate('//jsonApi.hydrator.missingRequiredAttribute.message')),
790819
[
791820
'pointer' => '/data/attributes/' . $field->getMappedName(),
792821
],
@@ -1038,8 +1067,8 @@ protected function hydrateRelationships(
10381067
} elseif ($field->isRequired() && $entity === null) {
10391068
$this->errors->addError(
10401069
StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY,
1041-
$this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.heading'),
1042-
$this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.message'),
1070+
strval($this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.heading')),
1071+
strval($this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.message')),
10431072
[
10441073
'pointer' => '/data/relationships/' . $field->getMappedName() . '/data/id',
10451074
],
@@ -1129,8 +1158,8 @@ protected function hydrateHasOne(
11291158
} elseif ($entity === null && $field->isRequired()) {
11301159
$this->errors->addError(
11311160
StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY,
1132-
$this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.heading'),
1133-
$this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.message'),
1161+
strval($this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.heading')),
1162+
strval($this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.message')),
11341163
[
11351164
'pointer' => '/data/relationships/' . $field->getMappedName() . '/data/id',
11361165
],
@@ -1139,8 +1168,8 @@ protected function hydrateHasOne(
11391168
} elseif ($entity === null && $field->isRequired()) {
11401169
$this->errors->addError(
11411170
StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY,
1142-
$this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.heading'),
1143-
$this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.message'),
1171+
strval($this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.heading')),
1172+
strval($this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.message')),
11441173
[
11451174
'pointer' => '/data/relationships/' . $field->getMappedName() . '/data/id',
11461175
],
@@ -1215,8 +1244,8 @@ protected function hydrateHasMany(
12151244
if ($entity === null && $field->isRequired() && count($relations) === 0) {
12161245
$this->errors->addError(
12171246
StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY,
1218-
$this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.heading'),
1219-
$this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.message'),
1247+
strval($this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.heading')),
1248+
strval($this->translator->translate('//jsonApi.hydrator.missingRequiredRelation.message')),
12201249
[
12211250
'pointer' => '/data/relationships/' . $field->getMappedName() . '/data',
12221251
],

src/JsonApi/Encoder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class Encoder extends NeomerxEncoder\Encoder
3131
/**
3232
* @param object|iterable<mixed>|null $data
3333
*
34-
* @return Array<mixed>
34+
* @return array<mixed>
3535
*/
3636
public function encodeDataAsArray(object|iterable|null $data): array
3737
{

0 commit comments

Comments
 (0)