Skip to content

Commit a061f57

Browse files
committed
Added a listener to inject the master request in voters
1 parent 8aee89d commit a061f57

File tree

5 files changed

+137
-3
lines changed

5 files changed

+137
-3
lines changed

DependencyInjection/Compiler/AddVotersPass.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,18 @@ public function process(ContainerBuilder $container)
1818
if (!$container->hasDefinition('knp_menu.matcher')) {
1919
return;
2020
}
21+
2122
$definition = $container->getDefinition('knp_menu.matcher');
23+
$listener = $container->getDefinition('knp_menu.listener.voters');
2224

2325
foreach ($container->findTaggedServiceIds('knp_menu.voter') as $id => $tags) {
2426
$definition->addMethodCall('addVoter', array(new Reference($id)));
27+
28+
foreach ($tags as $tag) {
29+
if (isset($tag['request']) && $tag['request']) {
30+
$listener->addMethodCall('addVoter', array(new Reference($id)));
31+
}
32+
}
2533
}
2634
}
2735
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace Knp\Bundle\MenuBundle\EventListener;
4+
5+
use Knp\Menu\Matcher\Voter\VoterInterface;
6+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
7+
use Symfony\Component\HttpKernel\HttpKernelInterface;
8+
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
9+
use Symfony\Component\HttpKernel\KernelEvents;
10+
11+
/**
12+
* VoterInitializerListener sets the master request in voters needing it.
13+
*
14+
* @author Fabien Potencier <fabien@symfony.com>
15+
*/
16+
class VoterInitializerListener implements EventSubscriberInterface
17+
{
18+
protected $voters = array();
19+
20+
public function onKernelRequest(GetResponseEvent $event)
21+
{
22+
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
23+
return;
24+
}
25+
26+
foreach ($this->voters as $voter) {
27+
if (method_exists($voter, 'setRequest')) {
28+
$voter->setRequest($event->getRequest());
29+
}
30+
}
31+
}
32+
33+
/**
34+
* Adds a voter in the matcher.
35+
*
36+
* @param VoterInterface $voter
37+
*/
38+
public function addVoter(VoterInterface $voter)
39+
{
40+
$this->voters[] = $voter;
41+
}
42+
43+
public static function getSubscribedEvents()
44+
{
45+
return array(
46+
KernelEvents::REQUEST => 'onKernelRequest',
47+
);
48+
}
49+
}

Resources/config/menu.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@
5555
<argument>%knp_menu.renderer.list.options%</argument>
5656
<argument>%kernel.charset%</argument>
5757
</service>
58+
59+
<service id="knp_menu.listener.voters" class="Knp\Bundle\MenuBundle\EventListener\VoterInitializerListener">
60+
<tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" />
61+
</service>
5862
</services>
5963

6064
</container>

Tests/DependencyInjection/Compiler/AddVotersPassTest.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,19 @@ public function testProcessWithAlias()
2626
$definitionMock = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')
2727
->disableOriginalConstructor()
2828
->getMock();
29-
$definitionMock->expects($this->once())
29+
$definitionMock->expects($this->at(0))
3030
->method('addMethodCall')
3131
->with($this->equalTo('addVoter'), $this->equalTo(array(new Reference('id'))));
32+
$definitionMock->expects($this->at(1))
33+
->method('addMethodCall')
34+
->with($this->equalTo('addVoter'), $this->equalTo(array(new Reference('foo'))));
35+
36+
$listenerMock = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')
37+
->disableOriginalConstructor()
38+
->getMock();
39+
$listenerMock->expects($this->once())
40+
->method('addMethodCall')
41+
->with($this->equalTo('addVoter'), $this->equalTo(array(new Reference('foo'))));
3242

3343
$containerBuilderMock = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder');
3444
$containerBuilderMock->expects($this->once())
@@ -37,11 +47,15 @@ public function testProcessWithAlias()
3747
$containerBuilderMock->expects($this->once())
3848
->method('findTaggedServiceIds')
3949
->with($this->equalTo('knp_menu.voter'))
40-
->will($this->returnValue(array('id' => array('tag1' => array()))));
41-
$containerBuilderMock->expects($this->once())
50+
->will($this->returnValue(array('id' => array('tag1' => array(), 'tag2' => array('request' => false)), 'foo' => array('tag1' => array('request' => true)))));
51+
$containerBuilderMock->expects($this->at(1))
4252
->method('getDefinition')
4353
->with($this->equalTo('knp_menu.matcher'))
4454
->will($this->returnValue($definitionMock));
55+
$containerBuilderMock->expects($this->at(2))
56+
->method('getDefinition')
57+
->with($this->equalTo('knp_menu.listener.voters'))
58+
->will($this->returnValue($listenerMock));
4559

4660
$menuPass = new AddVotersPass();
4761
$menuPass->process($containerBuilderMock);
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace Knp\Bundle\MenuBundle\Tests\EventListener;
4+
5+
use Knp\Bundle\MenuBundle\EventListener\VoterInitializerListener;
6+
use Symfony\Component\HttpFoundation\Request;
7+
use Symfony\Component\HttpKernel\HttpKernelInterface;
8+
9+
class MenuPassTest extends \PHPUnit_Framework_TestCase
10+
{
11+
public function testHandleSubRequest()
12+
{
13+
$event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')
14+
->disableOriginalConstructor()
15+
->getMock();
16+
$event->expects($this->once())
17+
->method('getRequestType')
18+
->will($this->returnValue(HttpKernelInterface::SUB_REQUEST));
19+
20+
$voter = $this->getMockBuilder('Knp\Menu\Silex\Voter\RouteVoter')
21+
->disableOriginalConstructor()
22+
->getMock();
23+
$voter->expects($this->never())
24+
->method('setRequest');
25+
26+
$listener = new VoterInitializerListener();
27+
$listener->addVoter($voter);
28+
29+
$listener->onKernelRequest($event);
30+
}
31+
32+
public function testHandleMasterRequest()
33+
{
34+
$request = new Request();
35+
36+
$event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')
37+
->disableOriginalConstructor()
38+
->getMock();
39+
$event->expects($this->once())
40+
->method('getRequestType')
41+
->will($this->returnValue(HttpKernelInterface::MASTER_REQUEST));
42+
$event->expects($this->once())
43+
->method('getRequest')
44+
->will($this->returnValue($request));
45+
46+
$voter = $this->getMockBuilder('Knp\Menu\Silex\Voter\RouteVoter')
47+
->disableOriginalConstructor()
48+
->getMock();
49+
$voter->expects($this->once())
50+
->method('setRequest')
51+
->with($this->equalTo($request));
52+
53+
$listener = new VoterInitializerListener();
54+
$listener->addVoter($voter);
55+
$listener->addVoter($this->getMock('Knp\Menu\Matcher\Voter\VoterInterface'));
56+
57+
$listener->onKernelRequest($event);
58+
}
59+
}

0 commit comments

Comments
 (0)