[2.7.0] ApiResource output data-transformers are not called in a relationship context anymore
API Platform version(s) affected: 2.7.0
Description
I've registered an ApiResource only for read item operation:
App\GeneratedEntity\NSGalleryBlock:
iri: GalleryBlock
shortName: GalleryBlock
collectionOperations: { }
attributes:
output: App\Api\Dto\GalleryBlockOutput
itemOperations:
get:
method: GET
normalization_context:
groups:
- nodes_sources
- urls
- tag_base
- translation_base
- document_display
Then I've got another resource which will store relationships to differents kind of resources:
App\Model\WebResponse:
collectionOperations: {}
itemOperations:
getByPath:
method: 'GET'
path: '/web_response_by_path'
read: false
controller: RZ\Roadiz\CoreBundle\Api\Controller\GetWebResponseByPathController
pagination_enabled: false
normalization_context:
pagination_enabled: false
groups:
- get
- web_response
- nodes_sources
- urls
- tag_base
- translation_base
- document_display
Direct resource call
If I call item operation for NSGalleryBlock resource directly, for example:
GET /api/gallery_blocks/2811
then GalleryBlockOutputDataTransformer is automatically called to hydrate GalleryBlockOutput DTO.

media property is populated by GalleryBlockOutputDataTransformer
Indirect resource call
If I call item operation for WebResponse resource, for example
GET /api/web_response_by_path?path=/path-to-my-web-response
and this WebResponse holds a relationship to /api/gallery_blocks/2811 then GalleryBlockOutputDataTransformer is not called anymore! Only WebResponseDataTransformer is called because it is the main resource class for this operation.

media property cannot be populated by GalleryBlockOutputDataTransformer, it remains empty
Possible Solution
This worked on 2.6.x because InputOutputMetadataTrait was getting output class from current normalizing object metadata, not the current operation context.
https://github.com/api-platform/core/blob/2.6/src/Serializer/InputOutputMetadataTrait.php#L48
I don't think that this was ever supported and it looks like you should use a normalizer instead of a data transformer. I'd strongly advise updating to 3.0 where this'd be way easier to handle.
These examples purpose is to create custom DTOs from a model or Doctrine entities.
As I understood from Api-platform documentation, Normalizers are contextual to a format (JSON, XML, JSON-LD). Then I find it cumbersome to use Normalizers to create DTOs which should be format-agnostic, it is just creating temporary data, not presentation (...then normalizers serialize my DTOs).
Moreover, Normalizers are too low-level for injecting non-scalar properties to objects, especially properties that store objects or Resources as well. My custom normalizer may depend on serializer service to serialize relationships and this could lead to cyclic dependency (I tried this way before using DTOs).
In the previous example, NSGalleryBlock resource was decorated to inject media property at runtime. But this media property holds an array<Document> resource which must be serialized as well and also use a DocumentOutput DTO. Up to api-platform/core 2.6.x, DataTransformer worked very well at creating DTOs in cascade (each time Serializer meets a new Resource that is configured to be output with a DTO) which sounds logical and was a bit magic too :smile:.
But for the moment I will freeze my dependencies to api-platform/core:~2.6.8. Until I figure out how to migrate my whole system to 3.0
Use a Provider / Processor. You shouldn't need a DataTransformer and yes Normaliers may be more appropriate to change your output at will. You can make a normalizer non-format specific.