API Platform version(s) affected: 2.5.4. Also tried with 2.4.7 same result
Following the instructions for setting up DTOs with DataTransformers using yaml configuration. https://api-platform.com/docs/core/dto
resources:
App\Domain\Model\Booking\Booking:
attributes:
output: App\Application\Api\BookingOutput
The BookingOutput DTO class is picked up - it's displayed in the Schemas in the Swagger UI etc.
However, it appears the DataTransformer is never even called. All it does it return the Doctrine entity of the main resource App\Domain\Model\Booking\Booking instead of the DTO.
The supportsTransformation() method is never called.
The transformer is registered in the container, although the note at the bottom makes me wonder if it's removed because it hasn't been used:
bin/console debug:container BookingOutputDataTransformer
Information for Service "App\Infrastructure\Api\DataTransformer\BookingOutputDataTransformer"
=================================================================================================================
---------------- -----------------------------------------------------------------------------------------
Option Value
---------------- -----------------------------------------------------------------------------------------
Service ID App\Infrastructure\Api\DataTransformer\BookingOutputDataTransformer
Class App\Infrastructure\Api\DataTransformer\BookingOutputDataTransformer
Tags api_platform.data_transformer
Public no
Synthetic no
Lazy no
Shared yes
Abstract no
Autowired yes
Autoconfigured yes
---------------- -----------------------------------------------------------------------------------------
! [NOTE] The "App\Infrastructure\Api\DataTransformer\BookingOutputDataTransformer" service or
! alias has been removed or inlined when the container was compiled.
The DataTransformer class:
final class BookingOutputDataTransformer implements DataTransformerInterface
{
/**
* @param Booking $data
*/
public function transform($data, string $to, array $context = [])
{
$output = new BookingOutput();
$output->id = $data->id()->asString();
$output->start = $data->rentalPeriod()->start()->format(Carbon::ATOM);
$output->end = $data->rentalPeriod()->end()->format(Carbon::ATOM);
return $output;
}
public function supportsTransformation($data, string $to, array $context = []): bool
{
return BookingOutput::class === $to && $data instanceof Booking;
}
}
Any ideas why the DataTransformers are not being picked up?
Thanks
The service seems to have been registered correctly. The note is not a concern.
You might want to place some dump calls in this method to see what's going on:
Thanks for your reply. The transformOutput() method is not being called at all.
Neither is normalize() in the same class.
I've sent you a PM on Symfony Slack. Let's figure this out.
With help from @teohhanhui I've got to the bottom of the issue.
It is caused by having the Symfony PropertyNormalizer enabled as well. As soon as I disable this, the DataTransformers start working as expected and the output is the BookingOutput class instead of the Booking entity directly.
Apparently there is currently no way to use ApiPlatform with the PropertyNormalizer. My use case was that I didn't want to have "get" prefixes on my entity getters, as per DDD recommendations, but it seems this is not possible.
Apparently it'll be supported in Symfony 5.1, at least in the PropertyInfo component.
It's a bit early to say, but my use-case is that the API is only providing read-only data, so instead of messing with my domain model, I might publish all the data as a read model to Elasticsearch and then use ApiPlatform backed by Elasticsearch instead of Doctrine.