symfony - preUpdate() siblings manage into tree: how to break ->persist() recursion? -
let's i've got entity this
class fooentity { $id; //foreign key fooentity $parent_id; //if no parent level =1, if have parent without parent = 2 , on... $level; //sorting index relative level $sorting_index } now on delete , on edit change level , sorting_index of entity.
so i've decided take advantage of doctrine2 entitylisteners , i've done similar to
class foolistener { public function preupdate(foo $entity, lifecycleeventargs $args) { $em = $args->getentitymanager(); $this->handleentityordering($entity, $em); } public function preremove(foo $entity, lifecycleeventargs $args) { $level = $entity->getlevel(); $cur_sorting_index = $entity->getsortingindex(); $em = $args->getentitymanager(); $this->handlesiblingordering($level, $cur_sorting_index, $em); } private function handleentityordering($entity, $em) { error_log('entity to_update_category stop flag: '.$entity->getstopeventpropagationstatus()); error_log('entity splobj: '.spl_object_hash($entity)); //code calculate new sorting_index , level entity (omitted) $this->handlesiblingordering($old_level, $old_sorting_index, $em); } } private function handlesiblingordering($level, $cur_sorting_index, $em) { $to_update_foos = //retrieve db siblings needs update //some code update sibling ordering (omitted) foreach ($to_update_foos $to_update_foo) { $em->persist($to_update_foo); } $em->flush(); } } the problem here pretty clear: if persist foo entity, preupdate() (into handlesiblingordering function) trigger raised , cause infinite loop.
my first idea insert special variable inside entity prevent loop: when started sibling update, variable setted , before executing update code checked. works charm preremove() not preupdate().
if notice i'm logging spl_obj_hash understand behaviour. big surprise can see obj passed preupdate() after preremove() same (so setting "status flag" fine) object passed preupdate() after preupdate() isn't same.
so ...
first question
someone point me in right direction manage situation?
second question
why doctrine needs generate different objects if 2 similar events raised?
i've founded workaround
best approach problem seem create custom eventsubscriber custom event dispatched programmatically controller update action.
way can "break" loop , having working code.
just make answer complete report snippet of code clarify che concept
create custom events bundle
//src/path/to/your/bundle/yourbundlenameevents.php final class yourbundlenameevents { const foo_event_update = 'bundle_name.foo.update'; } this special class not provide custom events our bundle
create custom event foo update
//src/path/to/your/bundle/event/fooupdateevent class fooupdateevent { //this class dispatched add properties useful own logic. in example 2 properties $level , $sorting_index. values setted before dispatch event } create custom event subscriber
//src/path/to/your/bundle/eventlistener/foosubscriber class foosubscriber implements eventsubscriberinterface { public static function getsubscribedevents() { return array(yourbundlenameevents::fooupdate => 'handlesiblingsordering'); } public function handlesiblingsordering(fooupdateevent $event) { //i can retrieve there, $event, data setted event itself. can run own logic code re-order siblings } } register subscriber service
//app/config/config.yml services: your_bundlename.foo_listener: class: your\bundle\name\eventlistener\foolistener tags: - { name: kernel.event_subscriber } create , dispatch events controller
//src/path/to/your/bundle/controller/foocontroller class foocontroller extends controller { public function updateaction() { //some code here $dispatcher = $this->get('event_dispatcher'); $foo_event = new fooevent(); $foo_event->setlevel($level); //just example $foo_event->setorderingindex($ordering_index); //just examle $dispatcher->dispatch(yourbundlenameevents::fooupdate, $foo_event); } } alternative solution
of course above solution best 1 but, if have property mapped db used flag, access directly lifecycleeventargs of preupdate() event calling
$event->getnewvalue('flag_name'); //$event object of lifecycleeventargs type by using flag check changes , stop propagation
Comments
Post a Comment