diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddExpressionLanguageProvidersPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddExpressionLanguageProvidersPass.php index 6510d02c83063..f60e4df8cd5ee 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddExpressionLanguageProvidersPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddExpressionLanguageProvidersPass.php @@ -36,10 +36,10 @@ public function process(ContainerBuilder $container) } // security - if ($container->has('security.access.expression_voter')) { - $definition = $container->findDefinition('security.access.expression_voter'); + if ($container->has('security.expression_language')) { + $definition = $container->findDefinition('security.expression_language'); foreach ($container->findTaggedServiceIds('security.expression_language_provider') as $id => $attributes) { - $definition->addMethodCall('addExpressionLanguageProvider', array(new Reference($id))); + $definition->addMethodCall('registerProvider', array(new Reference($id))); } } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ParseSecurityExpressionsPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ParseSecurityExpressionsPass.php new file mode 100644 index 0000000000000..8e24451b4b2be --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ParseSecurityExpressionsPass.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * Parses expressions used in the security access_control configuration to make sure they are dumped as SerializedParsedExpression + * This compiler pass must be registered after AddExpressionLanguageProvidersPass so custom functions can also be parsed. + * + * @author David Maicher + */ +class ParseSecurityExpressionsPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container) + { + if (!$container->has('security.expression_language')) { + return; + } + + $expressionLanguage = $container->get('security.expression_language'); + + foreach ($container->findTaggedServiceIds('security.expression') as $id => $attributes) { + $definition = $container->getDefinition($id); + $definition + ->setClass('Symfony\Component\ExpressionLanguage\SerializedParsedExpression') + ->addArgument(serialize($expressionLanguage->parse($definition->getArgument(0), array('token', 'user', 'object', 'roles', 'request', 'trust_resolver'))->getNodes())) + ->setTags(array()); + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 01f400d7d5e44..2e460411f6010 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -16,6 +16,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\DataCollectorTranslatorPass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ParseSecurityExpressionsPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RoutingResolverPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass; @@ -85,6 +86,7 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new AddCacheWarmerPass()); $container->addCompilerPass(new AddCacheClearerPass()); $container->addCompilerPass(new AddExpressionLanguageProvidersPass()); + $container->addCompilerPass(new ParseSecurityExpressionsPass()); // must be registered after AddExpressionLanguageProvidersPass $container->addCompilerPass(new TranslationExtractorPass()); $container->addCompilerPass(new TranslationDumperPass()); $container->addCompilerPass(new FragmentRendererPass(), PassConfig::TYPE_AFTER_REMOVING); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddExpressionLanguageProvidersPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddExpressionLanguageProvidersPassTest.php index 0934fe31c0c40..1d5f6365bf4eb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddExpressionLanguageProvidersPassTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddExpressionLanguageProvidersPassTest.php @@ -24,7 +24,7 @@ public function testProcessForRouter() $container = new ContainerBuilder(); $container->addCompilerPass(new AddExpressionLanguageProvidersPass()); - $definition = new Definition('Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\TestProvider'); + $definition = new Definition('\stdClass'); $definition->addTag('routing.expression_language_provider'); $container->setDefinition('some_routing_provider', $definition); @@ -43,7 +43,7 @@ public function testProcessForRouterAlias() $container = new ContainerBuilder(); $container->addCompilerPass(new AddExpressionLanguageProvidersPass()); - $definition = new Definition('Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\TestProvider'); + $definition = new Definition('\stdClass'); $definition->addTag('routing.expression_language_provider'); $container->setDefinition('some_routing_provider', $definition); @@ -63,17 +63,16 @@ public function testProcessForSecurity() $container = new ContainerBuilder(); $container->addCompilerPass(new AddExpressionLanguageProvidersPass()); - $definition = new Definition('Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\TestProvider'); + $definition = new Definition('\stdClass'); $definition->addTag('security.expression_language_provider'); $container->setDefinition('some_security_provider', $definition); - $container->register('security.access.expression_voter', '\stdClass'); + $container->register('security.expression_language', '\stdClass'); $container->compile(); - $router = $container->getDefinition('security.access.expression_voter'); - $calls = $router->getMethodCalls(); + $calls = $container->getDefinition('security.expression_language')->getMethodCalls(); $this->assertCount(1, $calls); - $this->assertEquals('addExpressionLanguageProvider', $calls[0][0]); + $this->assertEquals('registerProvider', $calls[0][0]); $this->assertEquals(new Reference('some_security_provider'), $calls[0][1][0]); } @@ -82,22 +81,17 @@ public function testProcessForSecurityAlias() $container = new ContainerBuilder(); $container->addCompilerPass(new AddExpressionLanguageProvidersPass()); - $definition = new Definition('Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\TestProvider'); + $definition = new Definition('\stdClass'); $definition->addTag('security.expression_language_provider'); $container->setDefinition('some_security_provider', $definition); - $container->register('my_security.access.expression_voter', '\stdClass'); - $container->setAlias('security.access.expression_voter', 'my_security.access.expression_voter'); + $container->register('my.security.expression_language', '\stdClass'); + $container->setAlias('security.expression_language', 'my.security.expression_language'); $container->compile(); - $router = $container->getDefinition('my_security.access.expression_voter'); - $calls = $router->getMethodCalls(); + $calls = $container->getDefinition('my.security.expression_language')->getMethodCalls(); $this->assertCount(1, $calls); - $this->assertEquals('addExpressionLanguageProvider', $calls[0][0]); + $this->assertEquals('registerProvider', $calls[0][0]); $this->assertEquals(new Reference('some_security_provider'), $calls[0][1][0]); } } - -class TestProvider -{ -} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/ParseSecurityExpressionsPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/ParseSecurityExpressionsPassTest.php new file mode 100644 index 0000000000000..b53457f90b553 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/ParseSecurityExpressionsPassTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler; + +use PHPUnit\Framework\TestCase; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ParseSecurityExpressionsPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +class ParseSecurityExpressionsPassTest extends TestCase +{ + public function testProcess() + { + $container = new ContainerBuilder(); + $container->addCompilerPass(new ParseSecurityExpressionsPass()); + $container->register('security.expression_language', 'Symfony\Component\Security\Core\Authorization\ExpressionLanguage'); + + $container->register('security.expression.one', 'Symfony\Component\ExpressionLanguage\Expression') + ->addArgument('true or false') + ->addTag('security.expression'); + + $container->register('security.expression.two', 'Symfony\Component\ExpressionLanguage\Expression') + ->addArgument('false or true') + ->addTag('security.expression'); + + $container->compile(); + + $expressionOne = $container->getDefinition('security.expression.one'); + $this->assertSame('Symfony\Component\ExpressionLanguage\SerializedParsedExpression', $expressionOne->getClass()); + $this->assertInstanceOf('Symfony\Component\ExpressionLanguage\Node\BinaryNode', unserialize($expressionOne->getArgument(1))); + + $expressionTwo = $container->getDefinition('security.expression.one'); + $this->assertSame('Symfony\Component\ExpressionLanguage\SerializedParsedExpression', $expressionTwo->getClass()); + $this->assertInstanceOf('Symfony\Component\ExpressionLanguage\Node\BinaryNode', unserialize($expressionTwo->getArgument(1))); + } +} diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 3ffe2876e88d8..cc106f3f70e48 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -38,7 +38,6 @@ class SecurityExtension extends Extension private $listenerPositions = array('pre_auth', 'form', 'http', 'remember_me'); private $factories = array(); private $userProviderFactories = array(); - private $expressionLanguage; public function __construct() { @@ -583,11 +582,15 @@ private function createExpression($container, $expression) return $this->expressions[$id]; } + if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { + throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.'); + } + $container - ->register($id, 'Symfony\Component\ExpressionLanguage\SerializedParsedExpression') + ->register($id, 'Symfony\Component\ExpressionLanguage\Expression') ->setPublic(false) ->addArgument($expression) - ->addArgument(serialize($this->getExpressionLanguage()->parse($expression, array('token', 'user', 'object', 'roles', 'request', 'trust_resolver'))->getNodes())) + ->addTag('security.expression') ; return $this->expressions[$id] = new Reference($id); @@ -651,16 +654,4 @@ public function getConfiguration(array $config, ContainerBuilder $container) // first assemble the factories return new MainConfiguration($this->factories, $this->userProviderFactories); } - - private function getExpressionLanguage() - { - if (null === $this->expressionLanguage) { - if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { - throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.'); - } - $this->expressionLanguage = new ExpressionLanguage(); - } - - return $this->expressionLanguage; - } }