I have a Symfony3 project using Doctrine 2.6 to manage the database.
I get an Integrity constraint violation error when I call the remove method the EntityManager in a certain order.
I've always considered this method (as well as persist) to work no matter in which order entities are passed to them, I was wrong.
The database runs on MySQL and has the following structure:
The goal is to remove a Menu entity. I've simplified the case so the Menu is only linked to one Offer, and one Component.
The offer is linked to the same Component as the menu.
So it looks like this:
- Menu [#12 Menu Of the Day]
| - Component [#23 Dessert]
| | - Product [#14 Pineapple]
| - Offer [#42 Dessert only]
| | - Component [#23 Dessert]
| | | - Product [#14 Pineapple]
Now this is the code that crashes :
$em = $this->doctrine->getManager();
$menu = $em->getRepository(Menu::class)->findOneBy(['ref' => 'V0dQ']);
// Remove menu components (ex: starter, dish, dessert, etc.)
$menuComponents = $menu->getComponents();
$menuComponent = $menuComponents[0];
$menu->removeComponent($menuComponent);
// Remove components products
$componentsProducts = $menuComponent->getComponentProducts();
$componentProduct = $componentsProducts[0];
$menuComponent->removeComponentProduct($componentProduct);
// Remove offers (ex: start + dish, dish + dessert, etc.)
$offers = $menu->getOffers();
$offer = $offers[0];
$menu->removeOffer($offer);
// Same as menu components
$offerComponents = $offer->getComponents();
$offerComponent = $offerComponents[0];
$offer->removeComponent($offerComponent);
// Everything MUST be persisted/removed in one place.
$em->remove($componentProduct);
$em->remove($menuComponent);
$em->remove($offer);
$em->remove($offerComponent);
$em->remove($menu);
$em->flush();
I works by putting the call to remove($menuComponent) after the call to remove($offer), like so:
$em->remove($componentProduct);
$em->remove($offer);
$em->remove($menuComponent);
$em->remove($offerComponent);
$em->remove($menu);
This is a raw example of the problem. In reality I have a pretty complex "Api engine" (like Api Platform) in which everything is handled in a generic way.
I need a clear understanding of what happens to abstract a solution to any case in the future, that's where I call for your help.
Do you see a simple rule to determine which entity must be passed to remove() first?
