Description
API Platform version(s) affected: 4.1.12
Description
I only expose DTO with output and custom providers/processors. All works fine except GetCollection and Post operations on subresource : the IRI generation does not work in this context although it works with Get and Put operations.
How to reproduce
I have a resource App\EmployeeOutput
(not a Doctrine entity) mapped as follow
resources:
App\EmployeeOutput:
operations:
-
class: ApiPlatform\Metadata\Get
uriTemplate: /company/{id}/employees/{employee}
uriVariables:
id:
fromClass: App\Company
employee:
fromClass: App\Employee
output: App\EmployeeOutput
-
class: ApiPlatform\Metadata\GetCollection
uriTemplate: /company/{id}/employees
uriVariables:
id:
fromClass: App\Company
toProperty: company
provider: App\EmployeeCollectionProvider
output: App\EmployeeOutput
-
class: ApiPlatform\Metadata\Post
uriTemplate: /company/{id}/employees
uriVariables:
id:
fromClass: App\Company
toProperty: cra
input: App\AddEmployeeInput
processor: App\AddEmployeeProcessor
output: App\EmployeeOutput
My DTO
readonly class EmployeeOutput
{
public function __construct(
private string $id,
public string $firstName,
public string $lastName,
) {
}
public function id(): string
{
return $this->id;
}
}
And my Doctrine entities
class Company
{
private Id $id;
/** @var iterable<int, Employee> */
private iterable $employees = [];
// ...
}
class Employee
{
private Id $id;
private Company $company;
// ...
}
Company Doctrine mapping
<one-to-many field="employees" target-entity="App\Employee" mapped-by="company" orphan-removal="true">
<cascade>
<cascade-persist />
<cascade-remove />
</cascade>
</one-to-many>
Employee Doctrine mapping
<many-to-one field="company" target-entity="App\Company" inversed-by="employees">
<join-column nullable="false" on-delete="CASCADE"/>
</many-to-one>
In my custom collection provider EmployeeCollectionProvider
, I must call the decorated @api_platform.doctrine.orm.state.collection_provider
with $operation->withClass(Employee::class)
to get the result. The query generated is correct and the results are ok.
The problem is on the normalization side at src/Metadata/IdentifiersExtractor.php:135
: Unable to generate an IRI for the item of type "App\EmployeeOutput".
IdentifiersExtractor::getIdentifierValue()
is called with
$item
:App\EmployeeOutput
instance$class
: "App\Company"$property
: "id"$parameterName
: "id"$toProperty
: null
Same problem with Post operation.
I tried everything but I suspect that subresource and DTO are not very well supported when the subresource ID is not in the uriTemplate, or I messed up with the config.
If I expose my entities without using output, it works fine.
How can I achieve the generation of IRI in the GetCollection or Post operation context ?
Possible Solution
🤷
Additional Context
The Get and Put operations work good and the IRI are ok.