removing entities in preUpdate event lister - symfony

I have a preUpdate listener for an Entity where I do some calculations, set values etc.
In that listener I would like to remove some other related entities, but this does not seem to be flushed by the entity manager. How can I go about achieving this?

According to the Doctrine2 docs:
Changes to associations of the updated entity are never allowed in
this event, since Doctrine cannot guarantee to correctly handle
referential integrity at this point of the flush operation.
Which means you shouldn't mess with the entities during the preUpdate event handling. I suggest you move your logic up to the service layer by using an entity manager. Write a specific method for updating your entitty and do all the complex stuff there. A nice example of an entity manager would be the FOSUserBundle's UserManager

If you make a change to an entity in a preUpdate event listener you need to tell the unit of work to recompute that entity's changeset:
$em = $eventArgs->getEntityManager();
$cm = $em->getClassMetadata(get_class($entity));
$em->getUnitOfWork()->recomputeSingleEntityChangeSet($cm, $entity);

Related

need explanation on postPersist and data flushed

i had trouble with an entity who was not flushed correctly.
In a service, i setted somme values. before flushing them in the service, i call another service and i saw there was a listener linked.
In this listener, there was a postPersist method in witch was called "$entityManager->flush();"
It was the source of my problem.
I found this post : Doctrine inserting in postPersist event
So, i deleted the flush who was done in the postPersist.
But i don't understand the need of the method postFlush.
In my case, data is flushed even if i don't have this method. how is it possible that the properties setted in the listener are flushed correctly without this event ?
If i look other entry points, i see that i need to declare the postFlush event and i see the need of this method.
thanks for your help
No, you don't need to flush in a postPersist event, because it will be done soon, just after Persist. You don't need to use all the functions of the list, neither declaring them.
ps.: Only if you need to get/set data before persist/flush. You would need to compute changes then get them in the action 'couple' (e.g prePersist and postPersist, preUpdate and postUpdate).
docs says:
Changes to fields of the passed entities are not recognized by the
flush operation anymore, use the computed change-set passed to the
event to modify primitive field values.
and
getEntityChangeSet() to get a copy of the changeset array. Changes to
this returned array do not affect updating.
PostFlush
The postFlush is made at the end of a flush operation. According to the docs this event is not a lifecycle callback. You can use it to set something after registering, or even send notifications, clearly with postFlush you won't need to worry about lifeCycle events.
postFlush - The postFlush event occurs at the end of a flush
operation. This event is not a lifecycle callback.
For postPersist in the docs
postPersist - The postPersist event occurs for an entity after the
entity has been made persistent. It will be invoked after the database
insert operations. Generated primary key values are available in the
postPersist event.
Here you can have ids if you need before flush.
You can check the docs about LifeCycleEvents here:
https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#lifecycle-events

Migrate procedural cache busting to PSR-6 cache pool service

Up till now our Doctrine entities did the cache busting via their LifecycleEvents. The APCu cache was deleted based on the entity's id in combination with a cache key constant:
/**
* #ORM\PostPersist()
*/
public function postPersist(LifecycleEventArgs $event)
{
apc_delete(sprintf(selff::CACHE_KEY, $event->getEntity()->getId()));
}
This was possible because of the procedural apc method, but this will never allow us to upgrade to PSR-6 because it makes use of a CacheItemPool that should be injected as a service.
As we will never going to inject the cache pool in the entities, my guess would be that we should create a EventSubscriber or EventListener for more than half the entities we have. This possible overhead frightens me a bit.
Will the subscriber / listener restructuring add a lot of overhead, and is that the right way to go? Should we add one global listener/subscriber for all entities (1..n) that handles all events or would it be better to add one listener/subscriber for every entity (n..m)?
Will the subscriber / listener restructuring add a lot of overhead, and is that the right way to go?
postPersist method is also added as listener to doctrine EventManager. http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html
Based on this I would guess that there would be no significant overhead.
However, I wouldn't base my decision on this but instead try it out. You can use Symfony profiler to see if any overhead exists and how big it is.
Really cool service I use for this kind of comparison is Blackfire.io.
Should we add one global listener/subscriber for all entities (1..n) that handles all events or would it be better to add one listener/subscriber for every entity (n..m)?
I would create global listener for all entities. In case you need different caching logic for any particular entity you can always create separate case.

Trigger Doctrine lifecycle events in my code

Question: how to trigger Doctrine lifecycle events in my code, having the entity data available?
Details
I have an active listener on the Doctrine postPersist and postUpdate events.
I cannot modify / override this listener.
In some places in my code, for performance reasons, I use DBAL to save data instead of ORM methods.
I'd like to stick to the same event system.
Thank you in advance for your help.
Extending #Cerad answer, here's a very basic sample code to achieve the result (trigger a Doctrine LifeCycle event). This sample assumes we're in a Symfony controller:
use Doctrine\ORM\Event\LifecycleEventArgs;
// ...
$user = new AppBundle\Entity\User();
// ... do something with the user
$entityManager = $this->getDoctrine()->getManager();
$eventManager = $entityManager->getEventManager();
$eventArgs = new LifecycleEventArgs($user, $entityManager);
$eventManager->dispatchEvent(\Doctrine\ORM\Events::postPersist, $eventArgs);
Assuming you have access to the entity manager then:
$eventManager = $entityManager->getEventManager();
After that you can build and dispatch events per the documentation.
I checked to see if there is a predefined service but did not see one. But you probably define one as a factory and inject it as needed.
Hope this is what you are asking for.

postLoad entity with association without lazy load?

This is my pb.
I have an entity game, and an entity console
It's a ManyToMany association.
For more performance, i load game and console in the same query like this :
$this->_em->getRepository('MyBundle:Console')
->createQueryBuilder('console')
->join('console.game', 'game')
->select('game', 'console')
->getQuery()->getResult();
When I use $console->getGames() that display all games without perform any query
When I use the postLoad event, every $console->getGames() perform query because the event start before the object is completely hydrated.
On doctrine website, I found this advise :
"Note that, when using Doctrine\ORM\AbstractQuery#iterate(), postLoad
events will be executed immediately after objects are being hydrated,
and therefore associations are not guaranteed to be initialized. It is
not safe to combine usage of Doctrine\ORM\AbstractQuery#iterate() and
postLoad event handlers."
So, someone knows how use postLoad event with the complete hydrated Entity ? I don't want lazy load.
But it's not my case
This behaviour has actually changed in Doctrine 2.5. From 2.5 all associations should be loaded in postLoad event. Doctrine 2.5 should fix your problem, reference:
http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/changelog/migration_2_5.html#events-postload-now-triggered-after-associations-are-loaded

Doctrine / Symfony2 : postSave event?

I have an issue with doctrine 2. I can't find how to achieve a result similar to the function postSave in Doctrine 1.
Basically, what I want to do is to persist, update or remove an entity and once the database is updated I want to perform operation on related entities.
I tried to do it in postPersist, postUpdate and postRemove, but the database is not updated at that point.
I'm using Entity listener, with my own entity listener resolver to inject my own services in my listener.
The onFLush method doesn't seam to work.
On this page http://doctrine-orm.readthedocs.org/en/latest/reference/events.html#entity-listeners there is no mention of postFlush or even onFlush event in entity listener.
If anyone knows how to execute some code AFTER the database is updated I would be very gratefull :)
Thanks in advance.
You need lifecycle callbacks:
Doctrine2 docs
Symfony2 docs
I suspect that you need postUpdate or onFlush (which are described in the first page)
This:
postUpdate - The postUpdate event occurs after the database update operations to entity data. It is not called for a DQL UPDATE statement.
And this:
onFlush - The onFlush event occurs after the change-sets of all managed entities are computed. This event is not a lifecycle callback.

Resources