I have two entity classes: Product and Price. Product has many Prices. The relations are defined as (only relevant code is shown):
Product.php
public function __construct()
{
$this->prices = new ArrayCollection();
}
/**
* @var Collection|Price[]
* @ORM\OneToMany(targetEntity="Price", mappedBy="product", cascade={"persist", "remove"})
*/
private Collection $prices;
/**
* @return Collection|Price[]
*/
public function getPrices()
{
return $this->prices;
}
/**
* @param Collection|Price[] $prices
*/
public function setPrices(Collection $prices) : void
{
$this->prices = $prices;
}
Price.php
/**
* @ORM\ManyToOne(targetEntity="Product", inversedBy="prices")
*/
private Product $product;
public function getProduct() : Product
{
return $this->product;
}
public function setProduct(?Product $product) : self
{
$this->product = $product;
return $this;
}
ProductType::buildForm()
$builder
->add('prices', EntityType::class, [
'class' => Price::class,
'multiple' => true,
'constraints' => [
new NotNull(),
],
]);
ProductController::add()
public function add(Request $request, EntityManagerInterface $manager) : Response
{
$form = $this->container->get('form.factory')->createNamed('', ProductType::class);
$form->handleRequest($request);
if (! $form->isSubmitted() || !$form->isValid()) {
return $this->handleView($this->view($form, Response::HTTP_BAD_REQUEST));
}
/** @var Product $product */
$product = $form->getData();
$manager->persist($product);
$manager->flush();
return $this->respond($product, Response::HTTP_CREATED);
}
Request JSON
{
"name": "added",
"prices": [
{
"currency": "EUR",
"value": 100
},
{
"currency": "PLN",
"value": 400
}
],
"description": "test desc"
}
JSON Response
{
"code": 400,
"message": "Validation Failed",
"errors": {
"children": {
"name": {},
"description": {},
"prices": {
"errors": [
"Not valid"
]
}
}
}
}
The problem is specifically with prices - passing empty prices array creates the product without errors. I use FOSRestBundle.
I've been Googling many hours, but no success. I'm new to Symfony, so it's likely that I miss something obvious :)
The problem was in the ProductType class.
Instead of:
$builder
->add('prices', EntityType::class, [
'class' => Price::class,
'multiple' => true,
'constraints' => [
new NotNull(),
],
]);
one should use
$builder
->add('prices', CollectionType::class, [
'entry_type' => PriceType::class,
'allow_add' => true,
'constraints' => [
new NotNull(),
],
]);
Answer found here