-
Notifications
You must be signed in to change notification settings - Fork 20
Open
Description
I have custom provider in api-platform that uses automapper. My expectation would be that automapper handles IRI's where needed, but it does not do that. It works well if needs to return an object, but totally fails with IRI's.
In example below, I expected media to be returned as array of iri strings, when I call records collection, and it fails to do that.
PHP: 8.3.20
Symfony: 7.2.5
jolicode/automapper 9.4.1
api-platform: 4.1.7
#[ApiResource(
shortName: 'Media',
operations: [new Get()],
normalizationContext: ['openapi_definition_name' => 'item-Read', 'groups' => ['media:item:read']],
denormalizationContext: ['openapi_definition_name' => 'item-Write', 'groups' => ['media:item:write']],
provider: EntityToDtoStateProvider::class,
processor: EntityClassDtoStateProcessor::class,
stateOptions: new Options(
entityClass: RecordMedia::class,
),
)]
class MediaApi implements ApiInterface
{
#[Groups(['media:list', 'media:item:read'])]
private string $id;
// rest of props
public function getId(): string
{
return $this->id;
}
public function setId(string $id): void
{
$this->id = $id;
}
/// rest of methods
}
#[ApiResource(
shortName: 'Record',
operations: [
new Get(
security: 'is_granted("CAN_VIEW_RECORD", object)',
),
new GetCollection(
normalizationContext: [
'openapi_definition_name' => 'list',
'groups' => RecordApi::RECORD_LIST_NORMALIZATION_GROUP,
],
security: 'is_granted("CAN_VIEW_RECORD", object)',
),
],
normalizationContext: [
'openapi_definition_name' => 'item-Read',
'groups' => RecordApi::RECORD_ITEM_NORMALIZATION_GROUP,
],
denormalizationContext: ['openapi_definition_name' => 'item-Write', 'groups' => ['record:item:write']],
provider: RecordProvider::class,
processor: EntityClassDtoStateProcessor::class,
stateOptions: new Options(
entityClass: Record::class,
),
)]
class RecordApi implements ApiInterface
{
public const array RECORD_LIST_NORMALIZATION_GROUP = [
'record:list',
];
public const array RECORD_ITEM_NORMALIZATION_GROUP = [
'record:item:read',
'media:item:read',
];
#[Groups(['record:item:read', 'record:list'])]
private string $id;
// automapper check singularity of property plural: Media - Medium for adder and remover methods
// that is the reason why we have addMedium/removeMedium methods
// ideally, it should use some reflection class check, but it is what it is
// adder and remover are essential for automapper to work for Collection to array
/**
* @var MediaApi[]$media
*/
#[Groups(['record:item:read', 'record:list'])]
#[MapFrom(property: 'recordMedia')]
private array $media;
public function __construct()
{
$this->media = [];
}
public function getId(): string
{
return $this->id;
}
// rest of methods
readonly class RecordProvider implements ProviderInterface
{
public function __construct(
// consructor arguments
) {
}
/**
* @param MapperContextArray $context
*
* @throws \Exception
*/
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
/** @var class-string<object> $resourceClass */
$resourceClass = $operation->getClass();
if ($operation instanceof CollectionOperationInterface) {
// some logic
$recordsResponse = $this->recordsRepository->findFromExternalApiRequest($indexRecordsRequest);
$dtos = [];
foreach ($recordsResponse->getResults() as $entity) {
$dtos[] = $this->mapEntityToDto($entity, $resourceClass, $context);
}
return new TraversablePaginator(
new \ArrayIterator($dtos),
$currentPage,
$itemsPerPage,
$recordsResponse->getTotalResultCount(),
);
}
$entity = $this->itemProvider->provide($operation, $uriVariables, $context);
if (!$entity) {
return null;
}
return $this->mapEntityToDto($entity, $resourceClass, $context);
}
/**
* @param class-string<object> $resourceClass
* @param MapperContextArray $context
*
* @throws \Exception
*/
private function mapEntityToDto(object $entity, string $resourceClass, array $context): object
{
$mapped = $this->autoMapper->map($entity, $resourceClass, $context);
assert(is_object($mapped));
return $mapped;
}
}```Metadata
Metadata
Assignees
Labels
No labels