Created
August 29, 2012 17:51
-
-
Save lavoiesl/3516195 to your computer and use it in GitHub Desktop.
DoctrineEntityListener
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Acme\CommonBundle\DependencyInjection; | |
use Symfony\Component\DependencyInjection\ContainerBuilder; | |
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; | |
use Symfony\Component\DependencyInjection\Reference; | |
class DoctrineEntityCompilerPass implements CompilerPassInterface | |
{ | |
public function process(ContainerBuilder $container) | |
{ | |
$tagged = $container->findTaggedServiceIds('acme.listener.doctrine_entity'); | |
if (!$tagged) { | |
return; | |
} | |
$definition = $container->register('acme.listener.doctrine_entity', 'Acme\DemoBundle\Listener\DoctrineEntityListener'); | |
$events = array(); | |
foreach ($tagged as $id => $tags) { | |
foreach ($tags as $tag) { | |
if (empty($tag['event']) || empty($tag['class'])) { | |
throw new \Exception("Services tagged acme.listener.doctrine_entity must have an event and a class argument"); | |
} | |
$method = empty($tag['method']) ? null : $tag['method']; | |
$definition->addMethodCall('register', array($tag['class'], $tag['event'], new Reference($id), $method)); | |
$events[$tag['event']] = 1; | |
} | |
} | |
// TODO support more than one evm | |
$evm = $container->getDefinition('doctrine.dbal.default_connection.event_manager'); | |
$evm->addMethodCall('addEventSubscriber', array(new Reference('acme.listener.doctrine_entity'))); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Acme\DemoBundle\Listener; | |
use Doctrine\ORM\Event\LifecycleEventArgs; | |
use Doctrine\Common\EventSubscriber; | |
class DoctrineEntityListener implements EventSubscriber | |
{ | |
/** | |
* $hooks[$class][$event][get_class($service)] = $method | |
*/ | |
private $hooks = array(); | |
/** | |
* Built once each for each entity class submitted to resolve all class inheritance | |
* $cache[$class][$event][get_class($service)] = $method; | |
*/ | |
private $cache = array(); | |
/** | |
* Map of service_id => service to reduce size of $hooks and $cache | |
*/ | |
private $services = array(); | |
/** | |
* Registered events | |
* Used to build the service and hook only relevant events | |
*/ | |
private $events = array(); | |
/** | |
* Supported events by Doctrine so we detect errors early | |
*/ | |
private static $validEvents = array( | |
'preRemove', | |
'postRemove', | |
'prePersist', | |
'postPersist', | |
'preUpdate', | |
'postUpdate', | |
'postLoad', | |
); | |
public function register($class, $event, $service, $method = null) | |
{ | |
// Index with service class to ensure it is called only once | |
if (!in_array($event, self::$validEvents)) { | |
throw new \InvalidArgumentException("$event is not a valid Doctrine LifecycleEvent"); | |
} | |
if (null === $method) { | |
$method = $event; | |
} | |
$this->services[get_class($service)] = $service; | |
$this->hooks[$class][$event][get_class($service)] = $method; | |
$this->events[$event] = 1; | |
} | |
/** | |
* Called by Doctrine EVM | |
*/ | |
public function getSubscribedEvents() | |
{ | |
return array_keys($this->events); | |
} | |
private function trigger($event, LifecycleEventArgs $args) | |
{ | |
$class = get_class($args->getEntity()); | |
foreach ($this->getServices($class, $event) as $service_id => $method) { | |
$service = $this->services[$service_id]; | |
$service->$method($args); | |
} | |
} | |
private function getServices($class, $event) | |
{ | |
if (!isset($this->cache[$class])) { | |
$this->cache[$class] = array(); | |
foreach ($this->hooks as $parent => $events) { | |
// Test inheritance | |
if (is_a($parent, $class, true)) { | |
foreach ($events as $event => $services) { | |
foreach ($services as $service => $method) { | |
$this->cache[$class][$event][$service] = $method; | |
} | |
} | |
} | |
} | |
} | |
if (isset($this->cache[$class][$event])) { | |
return $this->cache[$class][$event]; | |
} else { | |
return array(); | |
} | |
} | |
/** | |
* Handles calls by Doctrine EVM | |
*/ | |
public function __call($event, $args) | |
{ | |
if (isset($this->events[$event]) && isset($args[0]) && $args[0] instanceof LifecycleEventArgs) { | |
$this->trigger($event, $args[0]); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
services: | |
acme.listener.doctrine.user: | |
class: Acme\DemoBundle\Listener\AclListener | |
tags: | |
- { name: acme.listener.doctrine_entity, class: Acme\DemoBundle\Entity\User, event: postPersist } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment