8000 Implementation of kernel.event_subscriber tag for services. · Faianca/symfony@8b240d4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8b240d4

Browse files
committed
Implementation of kernel.event_subscriber tag for services.
1 parent 02b30d9 commit 8b240d4

File tree

4 files changed

+173
-0
lines changed

4 files changed

+173
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/ContainerAwareEventDispatcher.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
*
2222
* @author Fabien Potencier <fabien@symfony.com>
2323
* @author Bernhard Schussek <bernhard.schussek@symfony.com>
24+
* @author Jordan Alliot <jordan.alliot@gmail.com>
2425
*/
2526
class ContainerAwareEventDispatcher extends EventDispatcher
2627
{
@@ -103,6 +104,32 @@ public function getListeners($eventName = null)
103104
return parent::getListeners($eventName);
104105
}
105106

107+
/**
108+
* Adds a service as event subscriber
109+
*
110+
* If this service is created by a factory, its class value must be correctly filled.
111+
* The service's class must implement Symfony\Component\EventDispatcher\EventSubscriberInterface.
112+
*
113+
* @param string $serviceId The service ID of the subscriber service
114+
* @param string $class The service's class name
115+
*/
116+
public function addSubscriberService($serviceId, $class)
117+
{
118+
$refClass = new \ReflectionClass($class);
119+
$interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
120+
if (!$refClass->implementsInterface($interface)) {
121+
throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $serviceId, $interface));
122+
}
123+
124+
foreach ($class::getSubscribedEvents() as $eventName => $params) {
125+
if (is_string($params)) {
126+
$this->listenerIds[$eventName][] = array($serviceId, $params, 0);
127+
} else {
128+
$this->listenerIds[$eventName][] = array($serviceId, $params[0], $params[1]);
129+
}
130+
}
131+
}
132+
106133
/**
107134
* {@inheritDoc}
108135
*

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/RegisterKernelListenersPass.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,18 @@ public function process(ContainerBuilder $container)
4343
$definition->addMethodCall('addListenerService', array($event['event'], array($id, $event['method']), $priority));
4444
}
4545
}
46+
47+
foreach ($container->findTaggedServiceIds('kernel.event_subscriber') as $id => $attributes) {
48+
// We must assume that the class value has been correcly filled, even if the service is created by a factory
49+
$class = $container->getDefinition($id)->getClass();
50+
51+
$refClass = new \ReflectionClass($class);
52+
$interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
53+
if (!$refClass->implementsInterface($interface)) {
54+
throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface));
55+
}
56+
57+
$definition->addMethodCall('addSubscriberService', array($id, $class));
58+
}
4659
}
4760
}

src/Symfony/Bundle/FrameworkBundle/Tests/ContainerAwareEventDispatcherTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\DependencyInjection\Container;
1515
use Symfony\Bundle\FrameworkBundle\ContainerAwareEventDispatcher;
1616
use Symfony\Component\EventDispatcher\Event;
17+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
1718
use Symfony\Component\DependencyInjection\Scope;
1819

1920
class ContainerAwareEventDispatcherTest extends \PHPUnit_Framework_TestCase
@@ -39,6 +40,36 @@ public function testAddAListenerService()
3940
$dispatcher->dispatch('onEvent', $event);
4041
}
4142

43+
public function 6DB6 testAddASubscriberService()
44+
{
45+
$event = new Event();
46+
47+
$service = $this->getMock('Symfony\Bundle\FrameworkBundle\Tests\SubscriberService');
48+
49+
$service
50+
->expects($this->once())
51+
->method('onEvent')
52+
->with($event)
53+
;
54+
55+
$container = new Container();
56+
$container->set('service.subscriber', $service);
57+
58+
$dispatcher = new ContainerAwareEventDispatcher($container);
59+
$dispatcher->addSubscriberService('service.subscriber', 'Symfony\Bundle\FrameworkBundle\Tests\SubscriberService');
60+
61+
$dispatcher->dispatch('onEvent', $event);
62+
}
63+
64+
/**
65+
* @expectedException \InvalidArgumentException
66+
*/
67+
public function testTriggerASubscriberDoesntImplementInterface()
68+
{
69+
$dispatcher = new ContainerAwareEventDispatcher(new Container());
70+
$dispatcher->addSubscriberService('service.subscriber', 'Symfony\Bundle\FrameworkBundle\Tests\Service');
71+
}
72+
4273
public function testPreventDuplicateListenerService()
4374
{
4475
$event = new Event();
@@ -174,3 +205,16 @@ function onEvent(Event $e)
174205
{
175206
}
176207
}
208+
209+
class SubscriberService implements EventSubscriberInterface
210+
{
211+
static function getSubscribedEvents() {
212+
return array(
213+
'onEvent' => 'onEvent',
214+
);
215+
}
216+
217+
function onEvent(Event $e)
218+
{
219+
}
220+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\ContainerBuilder;
15+
use Symfony\Component\DependencyInjection\Definition;
16+
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RegisterKernelListenersPass;
17+
18+
class RegisterKernelListenersPassTest extends \PHPUnit_Framework_TestCase
19+
{
20+
/**
21+
* Tests that event subscribers not implementing EventSubscriberInterface
22+
* trigger an exception.
23+
*
24+
* @expectedException \InvalidArgumentException
25+
*/
26+
public function testEventSubscriberWithoutInterface()
27+
{
28+
// one service, not implementing any interface
29+
$services = array(
30+
'my_event_subscriber' => array(0 => array()),
31+
);
32+
33+
$definition = $this->getMock('Symfony\Component\DependencyInjection\Definition');
34+
$definition->expects($this->atLeastOnce())
35+
->method('getClass')
36+
->will($this->returnValue('stdClass'));
37+
38+
$builder = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
39+
$builder->expects($this->any())
40+
->method('hasDefinition')
41+
->will($this->returnValue(true));
42+
43+
// We don't test kernel.event_listener here
44+
$builder->expects($this->atLeastOnce())
45+
->method('findTaggedServiceIds')
46+
->will($this->onConsecutiveCalls(array(), $services));
47+
48+
$builder->expects($this->atLeastOnce())
49+
->method('getDefinition')
50+
->will($this->returnValue($definition));
51+
52+
$registerListenersPass = new RegisterKernelListenersPass();
53+
$registerListenersPass->process($builder);
54+
}
55+
56+
public function testValidEventSubscriber()
57+
{
58+
$services = array(
59+
'my_event_subscriber' => array(0 => array()),
60+
);
61+
62+
$definition = $this->getMock('Symfony\Component\DependencyInjection\Definition');
63+
$definition->expects($this->atLeastOnce())
64+
->method('getClass')
65+
->will($this->returnValue('Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\SubscriberService'));
66+
67+
$builder = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
68+
$builder->expects($this->any())
69+
->method('hasDefinition')
70+
->will($this->returnValue(true));
71+
72+
// We don't test kernel.event_listener here
73+
$builder->expects($this->atLeastOnce())
74+
->method('findTaggedServiceIds')
75+
->will($this->onConsecutiveCalls(array(), $services));
76+
77+
$builder->expects($this->atLeastOnce())
78+
->method('getDefinition')
79+
->will($this->returnValue($definition));
80+
81+
$registerListenersPass = new RegisterKernelListenersPass();
82+
$registerListenersPass->process($builder);
83+
}
84+
}
85+
86+
class SubscriberService implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
87+
{
88+
static function getSubscribedEvents() {}
89+
}

0 commit comments

Comments
 (0)
0