@@ -128,6 +128,9 @@ public function buildSchema(string $className, string $format = 'jsonapi', strin
128128
129129 $ schema = $ this ->schemaFactory ->buildSchema ($ className , 'json ' , $ type , $ operation , $ schema , $ jsonApiSerializerContext , $ forceCollection );
130130 $ definitionName = $ this ->definitionNameFactory ->create ($ className , $ format , $ inputOrOutputClass , $ operation , $ jsonApiSerializerContext + ['schema_type ' => $ type ]);
131+ if (Schema::TYPE_INPUT === $ type ) {
132+ $ definitionName .= '.input ' ;
133+ }
131134 $ prefix = $ this ->getSchemaUriPrefix ($ schema ->getVersion ());
132135 $ definitions = $ schema ->getDefinitions ();
133136 $ collectionKey = $ schema ->getItemsDefinitionKey ();
@@ -161,7 +164,7 @@ public function buildSchema(string $className, string $format = 'jsonapi', strin
161164 }
162165
163166 if (!$ collectionKey ) {
164- $ definitions [$ definitionName ]['properties ' ] = $ this ->buildDefinitionPropertiesSchema ($ key , $ className , $ format , $ type , $ operation , $ schema , []);
167+ $ definitions [$ definitionName ]['properties ' ] = $ this ->buildDefinitionPropertiesSchema ($ key , $ definitionName , $ inputOrOutputClass , $ format , $ type , $ operation , $ schema , []);
165168 $ schema ['$ref ' ] = $ prefix .$ definitionName ;
166169
167170 return $ schema ;
@@ -198,6 +201,7 @@ public function buildSchema(string $className, string $format = 'jsonapi', strin
198201 ],
199202 'data ' => [
200203 'type ' => 'array ' ,
204+ 'items ' => ['type ' => 'object ' ],
201205 ],
202206 ],
203207 'required ' => ['data ' ],
@@ -258,7 +262,7 @@ public function buildSchema(string $className, string $format = 'jsonapi', strin
258262 unset($ schema ['items ' ]);
259263 unset($ schema ['type ' ]);
260264
261- $ properties = $ this ->buildDefinitionPropertiesSchema ($ key , $ className , $ format , $ type , $ operation , $ schema , []);
265+ $ properties = $ this ->buildDefinitionPropertiesSchema ($ key , $ definitionName , $ inputOrOutputClass , $ format , $ type , $ operation , $ schema , []);
262266
263267 $ properties ['data ' ] = [
264268 'type ' => 'array ' ,
@@ -281,7 +285,7 @@ public function setSchemaFactory(SchemaFactoryInterface $schemaFactory): void
281285 }
282286 }
283287
284- private function buildDefinitionPropertiesSchema (string $ key , string $ className , string $ format , string $ type , ?Operation $ operation , Schema $ schema , ?array $ serializerContext ): array
288+ private function buildDefinitionPropertiesSchema (string $ key , string $ documentDefinitionName , string $ propertyClass , string $ format , string $ type , ?Operation $ operation , Schema $ schema , ?array $ serializerContext ): array
285289 {
286290 // Capture the resource's operation up front; the relationship loop below reassigns $operation.
287291 $ resourceOperation = $ operation ;
@@ -292,14 +296,10 @@ private function buildDefinitionPropertiesSchema(string $key, string $className,
292296 $ relationships = [];
293297 $ relatedDefinitions = [];
294298 foreach ($ properties as $ propertyName => $ property ) {
295- if ($ relation = $ this ->getRelationship ($ className , $ propertyName , $ serializerContext )) {
299+ if ($ relation = $ this ->getRelationship ($ propertyClass , $ propertyName , $ serializerContext )) {
296300 [$ isOne , $ relatedClasses ] = $ relation ;
297301 $ refs = [];
298- foreach ($ relatedClasses as $ relatedClassName => $ hasOperations ) {
299- if (false === $ hasOperations ) {
300- continue ;
301- }
302-
302+ foreach (Schema::TYPE_OUTPUT === $ type ? $ relatedClasses : [] as $ relatedClassName ) {
303303 $ operation = $ this ->findOperation ($ relatedClassName , $ type , null , $ serializerContext );
304304 $ inputOrOutputClass = $ this ->findOutputClass ($ relatedClassName , $ type , $ operation , $ serializerContext );
305305 $ serializerContext ??= $ this ->getSerializerContext ($ operation , $ type );
@@ -324,7 +324,7 @@ private function buildDefinitionPropertiesSchema(string $key, string $className,
324324 }
325325 // keep one entry per related definition: a polymorphic relation targets several resource classes, all of which may appear in "included"
326326 foreach (array_keys ($ refs ) as $ ref ) {
327- $ relatedDefinitions [$ ref ] = ['$ref ' => $ ref ];
327+ $ relatedDefinitions [$ ref. ' .resource ' ] = ['$ref ' => $ ref. ' .resource ' ];
328328 }
329329 // A relationship literally named "relationships"/"included" is prefixed at runtime too.
330330 $ relationshipName = ReservedAttributeNameConverter::getReservedAttributes ($ this ->strictMemberNames )[$ propertyName ] ?? $ propertyName ;
@@ -358,6 +358,9 @@ private function buildDefinitionPropertiesSchema(string $key, string $className,
358358 'type ' => 'object ' ,
359359 'properties ' => $ relationships ,
360360 ];
361+ }
362+
363+ if (Schema::TYPE_OUTPUT === $ type && \count ($ relationships ) > 0 ) {
361364 $ included = [
362365 'included ' => [
363366 'description ' => 'Related resources requested via the "include" query parameter. ' ,
@@ -377,12 +380,15 @@ private function buildDefinitionPropertiesSchema(string $key, string $className,
377380 // Only relax the requirement on the input schema; responses still always carry an `id`.
378381 $ required = Schema::TYPE_INPUT === $ type && $ resourceOperation instanceof HttpOperation && 'POST ' === $ resourceOperation ->getMethod () ? ['type ' ] : ['type ' , 'id ' ];
379382
383+ $ resourceDefinitionName = $ documentDefinitionName .'.resource ' ;
384+ $ definitions [$ resourceDefinitionName ] = [
385+ 'type ' => 'object ' ,
386+ 'properties ' => $ replacement ,
387+ 'required ' => $ required ,
388+ ];
389+
380390 return [
381- 'data ' => [
382- 'type ' => 'object ' ,
383- 'properties ' => $ replacement ,
384- 'required ' => $ required ,
385- ],
391+ 'data ' => ['$ref ' => $ this ->getSchemaUriPrefix ($ schema ->getVersion ()).$ resourceDefinitionName ],
386392 ] + $ included ;
387393 }
388394
@@ -400,9 +406,7 @@ private function getRelationship(string $resourceClass, string $property, ?array
400406 $ relatedClasses = [];
401407 foreach ($ relationships as [$ className , $ isCollection ]) {
402408 $ isOne = $ isOne || !$ isCollection ;
403- // @see https://github.com/api-platform/core/issues/5501
404- // @see https://github.com/api-platform/core/pull/5722
405- $ relatedClasses [$ className ] = $ this ->resourceMetadataFactory ->create ($ className )->getOperation ()->canRead ();
409+ $ relatedClasses [$ className ] = $ className ;
406410 }
407411
408412 return [$ isOne , $ relatedClasses ];
0 commit comments