The question relates to the technology stack I use:
- Symfony 4.2.3
- Doctrine ORM 2.6.3
- Sonata Admin 3.45.2
- sqlite3 3.22 (although the RDBMS shouldn't play a role)
Let's say we have two entities: Category
and Product
where the relation category to product is 1:n and product to category is n:1. This would look like:
Category.php
class Category
{
// ...
/**
* @ORM\OneToMany(
* targetEntity="App\Entity\Product",
* mappedBy="category",
* cascade={"persist"}
* )
* @Assert\Valid()
*/
private $products;
// ...
}
Product.php
class Product
{
// ...
/**
* @ORM\ManyToOne(
* targetEntity="App\Entity\Category",
* inversedBy="products"
* )
* @ORM\JoinColumn(nullable=false)
* @Assert\NotBlank()
*/
private $category;
// ...
}
Product must be assigned to a Category. Category can have 0 or more Products. If Category contains any Products it must NOT be deleted. Category can be deleted only if no Products are assigned to it.
When I try to delete a Category which has Products in the Sonata Admin, the deletion is prevented, as expected, and an Exception is thrown:
PDOException
SQLSTATE[23000]: Integrity constraint violation: 19 FOREIGN KEY constraint failed
Now, that is expected, but not very nice for the end user. I'd like to provide a message and inform the user that the Category can not be deleted because it still holds Products.
In Sonata Admin I use a workaround, writing CategoryAdminController
and implementing the preDelete
hook:
public function preDelete(Request $request, $object)
{
if ($object->getProducts()->isEmpty()) {
return null;
}
$count = $object->getProducts()->count();
$objectName = $this->admin->toString($object);
$this->addFlash(
'sonata_flash_error',
sprintf(
'The category "%s" can not be deleted because it contains %s product(s).',
$objectName,
$count
)
);
return $this->redirectTo($object);
}
However this doesn't feel right, because I have to reimplement it outside the admin.
What is the best practice to handle this? Can I implement some kind of validation in the entity? Or maybe Doctrine event listeners are the right thing?