[DoctrineBridge] Compiler pass for registering event listeners/subscribers
This was imported from DoctrineBundle (see: doctrine/DoctrineBundle#23), since it can be used by other Doctrine bundles, too. It utilizes the ContainerAwareEventManager from f15dde6c59
.
This commit is contained in:
parent
f15dde6c59
commit
71493a2d94
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
|
||||
class RegisterEventListenersAndSubscribersPass implements CompilerPassInterface
|
||||
{
|
||||
private $connections;
|
||||
private $container;
|
||||
private $eventManagers;
|
||||
private $managerTemplate;
|
||||
private $tagPrefix;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $connections Parameter ID for connections
|
||||
* @param string $managerTemplate sprintf() template for generating the event
|
||||
* manager's service ID for a connection name
|
||||
* @param string $tagPrefix Tag prefix for listeners and subscribers
|
||||
*/
|
||||
public function __construct($connections, $managerTemplate, $tagPrefix)
|
||||
{
|
||||
$this->connections = $connections;
|
||||
$this->managerTemplate = $managerTemplate;
|
||||
$this->tagPrefix = $tagPrefix;
|
||||
}
|
||||
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasParameter($this->connections)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->container = $container;
|
||||
$this->connections = $container->getParameter($this->connections);
|
||||
$sortFunc = function($a, $b) {
|
||||
$a = isset($a['priority']) ? $a['priority'] : 0;
|
||||
$b = isset($b['priority']) ? $b['priority'] : 0;
|
||||
|
||||
return $a > $b ? -1 : 1;
|
||||
};
|
||||
|
||||
$subscribersPerCon = $this->groupByConnection($container->findTaggedServiceIds($this->tagPrefix.'.event_subscriber'));
|
||||
foreach ($subscribersPerCon as $con => $subscribers) {
|
||||
$em = $this->getEventManager($con);
|
||||
|
||||
uasort($subscribers, $sortFunc);
|
||||
foreach ($subscribers as $id => $instance) {
|
||||
$em->addMethodCall('addEventSubscriber', array(new Reference($id)));
|
||||
}
|
||||
}
|
||||
|
||||
$listenersPerCon = $this->groupByConnection($container->findTaggedServiceIds($this->tagPrefix.'.event_listener'), true);
|
||||
foreach ($listenersPerCon as $con => $listeners) {
|
||||
$em = $this->getEventManager($con);
|
||||
|
||||
uasort($listeners, $sortFunc);
|
||||
foreach ($listeners as $id => $instance) {
|
||||
$em->addMethodCall('addEventListener', array(
|
||||
array_unique($instance['event']),
|
||||
isset($instance['lazy']) && $instance['lazy'] ? $id : new Reference($id),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function groupByConnection(array $services, $isListener = false)
|
||||
{
|
||||
$grouped = array();
|
||||
foreach (array_keys($this->connections) as $con) {
|
||||
$grouped[$con] = array();
|
||||
}
|
||||
|
||||
foreach ($services as $id => $instances) {
|
||||
foreach ($instances as $instance) {
|
||||
$cons = isset($instance['connection']) ? array($instance['connection']) : array_keys($this->connections);
|
||||
foreach ($cons as $con) {
|
||||
if (!isset($grouped[$con])) {
|
||||
throw new \RuntimeException(sprintf('The Doctrine connection "%s" referenced in service "%s" does not exist. Available connections names: %s', $con, $id, implode(', ', array_keys($this->connections))));
|
||||
}
|
||||
|
||||
if ($isListener) {
|
||||
if (!isset($instance['event'])) {
|
||||
throw new \InvalidArgumentException(sprintf('Doctrine event listener "%s" must specify the "event" attribute.', $id));
|
||||
}
|
||||
$instance['event'] = array($instance['event']);
|
||||
|
||||
if (isset($instance['lazy']) && $instance['lazy']) {
|
||||
$this->container->getDefinition($id)->setPublic(true);
|
||||
}
|
||||
|
||||
if (isset($grouped[$con][$id])) {
|
||||
$grouped[$con][$id]['event'] = array_merge($grouped[$con][$id]['event'], $instance['event']);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$grouped[$con][$id] = $instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
private function getEventManager($name)
|
||||
{
|
||||
if (null === $this->eventManagers) {
|
||||
$this->eventManagers = array();
|
||||
foreach ($this->connections as $n => $id) {
|
||||
$this->eventManagers[$n] = $this->container->getDefinition(sprintf($this->managerTemplate, $n));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->eventManagers[$name];
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Tests\Bridge\Doctrine\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass\RegisterEventListenersAndSubscribersPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class RegisterEventListenersAndSubscribersPassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testProcessEventListenersWithPriorities()
|
||||
{
|
||||
$container = $this->createBuilder();
|
||||
|
||||
$container
|
||||
->register('a', 'stdClass')
|
||||
->addTag('doctrine.event_listener', array(
|
||||
'event' => 'foo',
|
||||
'priority' => -5,
|
||||
))
|
||||
->addTag('doctrine.event_listener', array(
|
||||
'event' => 'bar',
|
||||
))
|
||||
;
|
||||
$container
|
||||
->register('b', 'stdClass')
|
||||
->addTag('doctrine.event_listener', array(
|
||||
'event' => 'foo',
|
||||
))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
$this->assertEquals(array('b', 'a'), $this->getServiceOrder($container, 'addEventListener'));
|
||||
|
||||
$calls = $container->getDefinition('doctrine.dbal.default_connection.event_manager')->getMethodCalls();
|
||||
$this->assertEquals(array('foo', 'bar'), $calls[1][1][0]);
|
||||
}
|
||||
|
||||
public function testProcessEventSubscribersWithPriorities()
|
||||
{
|
||||
$container = $this->createBuilder();
|
||||
|
||||
$container
|
||||
->register('a', 'stdClass')
|
||||
->addTag('doctrine.event_subscriber')
|
||||
;
|
||||
$container
|
||||
->register('b', 'stdClass')
|
||||
->addTag('doctrine.event_subscriber', array(
|
||||
'priority' => 5,
|
||||
))
|
||||
;
|
||||
$container
|
||||
->register('c', 'stdClass')
|
||||
->addTag('doctrine.event_subscriber', array(
|
||||
'priority' => 10,
|
||||
))
|
||||
;
|
||||
$container
|
||||
->register('d', 'stdClass')
|
||||
->addTag('doctrine.event_subscriber', array(
|
||||
'priority' => 10,
|
||||
))
|
||||
;
|
||||
$container
|
||||
->register('e', 'stdClass')
|
||||
->addTag('doctrine.event_subscriber', array(
|
||||
'priority' => 10,
|
||||
))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
$this->assertEquals(array('c', 'd', 'e', 'b', 'a'), $this->getServiceOrder($container, 'addEventSubscriber'));
|
||||
}
|
||||
|
||||
private function process(ContainerBuilder $container)
|
||||
{
|
||||
$pass = new RegisterEventListenersAndSubscribersPass('doctrine.connections', 'doctrine.dbal.%s_connection.event_manager', 'doctrine');
|
||||
$pass->process($container);
|
||||
}
|
||||
|
||||
private function getServiceOrder(ContainerBuilder $container, $method)
|
||||
{
|
||||
$order = array();
|
||||
foreach ($container->getDefinition('doctrine.dbal.default_connection.event_manager')->getMethodCalls() as $call) {
|
||||
list($name, $arguments) = $call;
|
||||
if ($method !== $name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('addEventListener' === $name) {
|
||||
$order[] = (string) $arguments[1];
|
||||
continue;
|
||||
}
|
||||
|
||||
$order[] = (string) $arguments[0];
|
||||
}
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
private function createBuilder()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('doctrine.dbal.default_connection.event_manager', 'stdClass');
|
||||
$container->register('doctrine.dbal.default_connection', 'stdClass');
|
||||
$container->setParameter('doctrine.connections', array('default' => 'doctrine.dbal.default_connection'));
|
||||
|
||||
return $container;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user