34
34
use ReflectionClass ;
35
35
use ReflectionException ;
36
36
use ReflectionNamedType ;
37
+ use ReflectionParameter ;
37
38
use ReflectionProperty ;
38
39
use Throwable ;
40
+ use function array_filter ;
39
41
use function array_key_exists ;
40
42
use function array_map ;
41
43
use function array_merge ;
57
59
use function str_contains ;
58
60
use function str_replace ;
59
61
use function strtolower ;
62
+ use function strval ;
60
63
use function trim ;
61
64
use function ucfirst ;
62
65
use function ucwords ;
@@ -174,8 +177,8 @@ public function hydrate(
174
177
if (!$ document ->hasResource ()) {
175
178
throw new Exceptions \JsonApiError (
176
179
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 ' ) ),
179
182
[
180
183
'pointer ' => '/data ' ,
181
184
],
@@ -220,8 +223,8 @@ public function hydrate(
220
223
if ($ identifier === null || !Uuid \Uuid::isValid ($ identifier )) {
221
224
throw new Exceptions \JsonApiError (
222
225
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 ' ) ),
225
228
[
226
229
'pointer ' => '/data/id ' ,
227
230
],
@@ -277,6 +280,22 @@ protected function mapEntity(string $entityClassName): array
277
280
$ reflectionProperties [] = $ rp ->getName ();
278
281
}
279
282
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
+
280
299
$ entityFields = array_unique (array_merge (
281
300
$ reflectionProperties ,
282
301
$ classMetadata ->getFieldNames (),
@@ -294,12 +313,22 @@ protected function mapEntity(string $entityClassName): array
294
313
continue ;
295
314
}
296
315
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
+ ];
300
324
} 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
+ }
303
332
}
304
333
305
334
// Check if field is updatable
@@ -785,8 +814,8 @@ protected function hydrateAttributes(
785
814
if ($ value === null && $ field ->isRequired () && $ isNew ) {
786
815
$ this ->errors ->addError (
787
816
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 ' ) ),
790
819
[
791
820
'pointer ' => '/data/attributes/ ' . $ field ->getMappedName (),
792
821
],
@@ -1038,8 +1067,8 @@ protected function hydrateRelationships(
1038
1067
} elseif ($ field ->isRequired () && $ entity === null ) {
1039
1068
$ this ->errors ->addError (
1040
1069
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 ' ) ),
1043
1072
[
1044
1073
'pointer ' => '/data/relationships/ ' . $ field ->getMappedName () . '/data/id ' ,
1045
1074
],
@@ -1129,8 +1158,8 @@ protected function hydrateHasOne(
1129
1158
} elseif ($ entity === null && $ field ->isRequired ()) {
1130
1159
$ this ->errors ->addError (
1131
1160
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 ' ) ),
1134
1163
[
1135
1164
'pointer ' => '/data/relationships/ ' . $ field ->getMappedName () . '/data/id ' ,
1136
1165
],
@@ -1139,8 +1168,8 @@ protected function hydrateHasOne(
1139
1168
} elseif ($ entity === null && $ field ->isRequired ()) {
1140
1169
$ this ->errors ->addError (
1141
1170
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 ' ) ),
1144
1173
[
1145
1174
'pointer ' => '/data/relationships/ ' . $ field ->getMappedName () . '/data/id ' ,
1146
1175
],
@@ -1215,8 +1244,8 @@ protected function hydrateHasMany(
1215
1244
if ($ entity === null && $ field ->isRequired () && count ($ relations ) === 0 ) {
1216
1245
$ this ->errors ->addError (
1217
1246
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 ' ) ),
1220
1249
[
1221
1250
'pointer ' => '/data/relationships/ ' . $ field ->getMappedName () . '/data ' ,
1222
1251
],
0 commit comments