1414namespace ApiPlatform \Laravel \State ;
1515
1616use ApiPlatform \Metadata \Error ;
17+ use ApiPlatform \Metadata \Exception \RuntimeException ;
1718use ApiPlatform \Metadata \Operation ;
1819use ApiPlatform \State \ProviderInterface ;
1920use Illuminate \Contracts \Foundation \Application ;
21+ use Illuminate \Database \Eloquent \Model ;
2022use Illuminate \Foundation \Http \FormRequest ;
2123use Illuminate \Support \Facades \Validator ;
2224use Illuminate \Validation \ValidationException ;
25+ use Symfony \Component \Serializer \Normalizer \NormalizerInterface ;
2326
2427/**
2528 * @implements ProviderInterface<object>
@@ -34,12 +37,13 @@ final class ValidateProvider implements ProviderInterface
3437 public function __construct (
3538 private readonly ProviderInterface $ inner ,
3639 private readonly Application $ app ,
40+ // TODO: trigger deprecation in API Platform 4.2 when this is not defined
41+ private readonly ?NormalizerInterface $ normalizer = null ,
3742 ) {
3843 }
3944
4045 public function provide (Operation $ operation , array $ uriVariables = [], array $ context = []): object |array |null
4146 {
42- $ request = $ context ['request ' ];
4347 $ body = $ this ->inner ->provide ($ operation , $ uriVariables , $ context );
4448
4549 if ($ operation instanceof Error) {
@@ -74,12 +78,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
7478 return $ body ;
7579 }
7680
77- // In Symfony, validation is done on the Resource object (here $body) using Deserialization before Validation
78- // Here, we did not deserialize yet, we validate on the raw body before.
79- $ validationBody = $ request ->request ->all ();
80- if ('jsonapi ' === $ request ->getRequestFormat ()) {
81- $ validationBody = $ validationBody ['data ' ]['attributes ' ];
82- }
81+ $ validationBody = $ this ->getBodyForValidation ($ body );
8382
8483 $ validator = Validator::make ($ validationBody , $ rules );
8584 if ($ validator ->fails ()) {
@@ -88,4 +87,35 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
8887
8988 return $ body ;
9089 }
90+
91+ /**
92+ * @return array<string, mixed>
93+ */
94+ private function getBodyForValidation (mixed $ body ): array
95+ {
96+ if (!$ body ) {
97+ return [];
98+ }
99+
100+ if ($ body instanceof Model) {
101+ return $ body ->toArray ();
102+ }
103+
104+ if ($ this ->normalizer ) {
105+ if (!\is_array ($ v = $ this ->normalizer ->normalize ($ body ))) {
106+ throw new RuntimeException ('An array is expected. ' );
107+ }
108+
109+ return $ v ;
110+ }
111+
112+ // hopefully this path never gets used, its there for BC-layer only
113+ // TODO: deprecation in API Platform 4.2
114+ // TODO: remove in 5.0
115+ if ($ s = json_encode ($ body )) {
116+ return json_decode ($ s , true );
117+ }
118+
119+ throw new RuntimeException ('Could not transform the denormalized body in an array for validation ' );
120+ }
91121}
0 commit comments