DTO not considered when ObjectMapper is defined
API Platform version(s) affected: 4.2.x
Description
It looks like the output (and maybe input -not tested yet) class is not considered when Object Mapper is used.
Let say I have this resource with DTO for both operations. The DTOs have a #[Map] attribute.
namespace App\Api\Resource;
use ApiPlatform\Doctrine\Orm\State\Options;
use ApiPlatform\Metadata\ApiResource;
use App\Entity\Book as BookEntity;
use Symfony\Component\ObjectMapper\Attribute\Map;
#[ApiResource(
stateOptions: new Options(entityClass: BookEntity::class),
operations: [
new Get(
output: BookItem::class
),
new GetCollection(
output: BookCollection::class
),
]
)]
#[Map(source: BookEntity::class)]
final class Book
{
public int $id;
public string $name;
}
The data returned by the API endpoints are not the DTOs, but the Book resource.
How to reproduce
Use the example above.
Possible Solution
From my understanding, the ObjectMappedProvider and the ObjectMapperProcessor use the $operation->getClass() method to perform the mapping.
getClass returns the class that holds the operation and not the DTO to be used.
A new method getMappedClass should exist and be used by the Provider and Processor.
This method should return the output/input DTO class if it has a #[Map] attribute or the resource class. In the example, getClass will return Book::class (current behavior) and getMappedClass should return BookItem::class or BookCollection::class.
canMap should be modified accordingly
Additional Context
We tried a bunch of things with @mtarld (see https://github.com/mtarld/sfcon-apip)
We do read the input at https://github.com/api-platform/core/blob/0ef0ba63a41af000836dd5631b43bcdf10c50c71/src/State/Processor/ObjectMapperProcessor.php but maybe we need to force the output at
https://github.com/api-platform/core/blob/0ef0ba63a41af000836dd5631b43bcdf10c50c71/src/State/Processor/ObjectMapperProcessor.php#L65
Note that it's quite hard currently without https://github.com/symfony/symfony/pull/62522 to do reverse mapping (using only source). Ideally I think that API Platform should never specify the target argument of ObjectMapper::map() so that the choice is done by the ObjectMapper metadata factory.
Oh I got it!
Many thanks.
Yoiu are right the input class is considered by the ObjectMapperProcessor, but this is not the case with the ObjectMapperProvider.
I tested on my project and it works fine when I add $class = $operation->getOutput()['class'] ?? $operation->getClass(); and $class insted of $operation->getClass() where needed.
I will prepare a PR.