Description
Is it by design that ApiPlatform is meant to always pass Collections as array, e.g. when submitting to the POST Endpoint?
According to the code yes, but is this intended? https://github.com/api-platform/core/blob/master/src/Serializer/AbstractItemNormalizer.php#L397
To paraphrase the error I got:
Argument n passed to App\\Entity\\Product::__construct() must be an instance of App\\Collection\\PriceCollection, array given
- (it is passing me an array of Prices, but I need the Prices inside a PriceCollection)
This wouldn't be a problem if I could use a custom Item Denormalizer to create the PriceCollection, but I cant with 2.4.2 anymore.
In 2.4.2 I never even see PriceCollection reach the "supportsDenormalization" method of my Normalizer.
As soon as I downgrade from 2.4.2 to 2.3.6 my custom Denormalizer "works" again.
With 2.3.6 the PriceCollection reaches the Normalizer and submitting to "POST" works.
Could be related to #2662 ? (not sure though)
I already tried #2679 but it didn't do anything in my case, unless I missed something.
In the simplified php code (I left out most Annotations, this is mostly to exemplify the way it is setup) below ApiPlatform always passes "array" to the Product Constructor while ProductCollection is expected.
Note Product
and Price
are Entities/ Resources. PriceCollection however is not (it's just a simple object to ensure only entities of Type Price
are actually passed to Product
)
class PriceCollection
{
/** @var ArrayCollection Doctrine ArrayCollection */
private $prices;
public function __construct(Price ...$prices)
{
$this->prices = new ArrayCollection($prices);
}
public function getPrices(): ArrayCollection
{
return $this->prices;
}
}
class Product
{
/**
* @var Collection
* @ApiSubresource()
* @ORM\ManyToMany(targetEntity="Price", cascade={"persist", "remove"})
* @ORM\JoinTable(name="product_prices",
* joinColumns={@ORM\JoinColumn(name="product_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="price_id", referencedColumnName="id", unique=true)}
* )
*/
private $prices;
public function __construct($paramA, PriceCollection $prices, $otherParam)
{
...
$this->prices = $prices->getPrices();
}
}