diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php index e603cb9a81..7d90fd4df2 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php @@ -32,14 +32,14 @@ class AddSecurityVotersPass implements CompilerPassInterface return; } - $voters = new \SplPriorityQueue(); + $voters = array(); foreach ($container->findTaggedServiceIds('security.voter') as $id => $attributes) { $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; - $voters->insert(new Reference($id), $priority); + $voters[$priority][] = new Reference($id); } - $voters = iterator_to_array($voters); - ksort($voters); + krsort($voters); + $voters = call_user_func_array('array_merge', $voters); if (!$voters) { throw new LogicException('No security voters found. You need to tag at least one with "security.voter"'); @@ -47,5 +47,6 @@ class AddSecurityVotersPass implements CompilerPassInterface $adm = $container->getDefinition($container->hasDefinition('debug.security.access.decision_manager') ? 'debug.security.access.decision_manager' : 'security.access.decision_manager'); $adm->addMethodCall('setVoters', array(array_values($voters))); + $adm->addMethodCall('setVoters', array($voters)); } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSecurityVotersPassTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSecurityVotersPassTest.php new file mode 100644 index 0000000000..6e58a8ce6e --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSecurityVotersPassTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\Tests\DependencyInjection\Compiler; + +use PHPUnit\Framework\TestCase; +use Symfony\Bundle\SecurityBundle\DependencyInjection\Compiler\AddSecurityVotersPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +class AddSecurityVotersPassTest extends TestCase +{ + public function testThatSecurityVotersAreProcessedInPriorityOrder() + { + $container = new ContainerBuilder(); + $container + ->register('security.access.decision_manager', 'Symfony\Component\Security\Core\Authorization\AccessDecisionManager') + ->addArgument(array()) + ; + $container + ->register('no_prio_service') + ->addTag('security.voter') + ; + $container + ->register('lowest_prio_service') + ->addTag('security.voter', array('priority' => 100)) + ; + $container + ->register('highest_prio_service') + ->addTag('security.voter', array('priority' => 200)) + ; + $container + ->register('zero_prio_service') + ->addTag('security.voter', array('priority' => 0)) + ; + $compilerPass = new AddSecurityVotersPass(); + $compilerPass->process($container); + + $calls = $container->getDefinition('security.access.decision_manager')->getMethodCalls(); + + $this->assertEquals( + array( + new Reference('highest_prio_service'), + new Reference('lowest_prio_service'), + new Reference('no_prio_service'), + new Reference('zero_prio_service'), + ), + $calls[0][1][0] + ); + } +}