From 00895742717df38c6d8033fc9e731577e4936735 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Thu, 31 Jan 2013 12:03:36 +0100 Subject: [PATCH] Moved the preconditions of function arguments before the function This allows to call compileInternal on arguments when compiling preconditions of the function as the preconditions should be compiled before compiling the expression. --- .../Expression/ExpressionCompiler.php | 6 +-- .../Expression/ExpressionCompilerTest.php | 54 +++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/Security/Authorization/Expression/ExpressionCompiler.php b/Security/Authorization/Expression/ExpressionCompiler.php index 6643776..13c75ca 100644 --- a/Security/Authorization/Expression/ExpressionCompiler.php +++ b/Security/Authorization/Expression/ExpressionCompiler.php @@ -129,7 +129,7 @@ public function outdent() $this->indentationLevel -= 1; if ($this->indentationLevel < 0) { - throw new RuntimeException('The identation level cannot be less than zero.'); + throw new RuntimeException('The indentation level cannot be less than zero.'); } return $this; @@ -266,12 +266,12 @@ public function compilePreconditions(ExpressionInterface $expr) } if ($expr instanceof FunctionExpression) { - $this->getFunctionCompiler($expr->name)->compilePreconditions($this, $expr); - foreach ($expr->args as $arg) { $this->compilePreconditions($arg); } + $this->getFunctionCompiler($expr->name)->compilePreconditions($this, $expr); + return $this; } diff --git a/Tests/Security/Authorization/Expression/ExpressionCompilerTest.php b/Tests/Security/Authorization/Expression/ExpressionCompilerTest.php index 1843264..982dc69 100644 --- a/Tests/Security/Authorization/Expression/ExpressionCompilerTest.php +++ b/Tests/Security/Authorization/Expression/ExpressionCompilerTest.php @@ -3,6 +3,8 @@ namespace JMS\SecurityExtraBundle\Tests\Security\Authorization\Expression; use JMS\SecurityExtraBundle\Security\Authorization\Expression\Compiler\ParameterExpressionCompiler; +use JMS\SecurityExtraBundle\Security\Authorization\Expression\Ast\FunctionExpression; +use JMS\SecurityExtraBundle\Security\Authorization\Expression\Compiler\Func\FunctionCompilerInterface; use JMS\SecurityExtraBundle\Security\Acl\Expression\HasPermissionFunctionCompiler; @@ -110,6 +112,27 @@ public function testCompileWhenParameterIsWrappedInMethodCall() $this->assertFalse($evaluator($context)); } + public function testCompileInternalInPreconditions() + { + $this->compiler->addTypeCompiler(new ParameterExpressionCompiler()); + $this->compiler->addFunctionCompiler(new TestIssue108FunctionCompiler()); + + // the first call ensure that state is reset correctly + $this->compiler->compileExpression(new Expression( + 'testIssue(#project)')); + $evaluator = eval($this->compiler->compileExpression( + new Expression('testIssue(#project)'))); + + $secureObject = new SecuredObject(); + $project = new Project(); + + $context = array( + 'object' => new MethodInvocation(new \ReflectionMethod($secureObject, 'delete'), $secureObject, array($project), array()), + ); + + $this->assertTrue($evaluator($context)); + } + /** * @dataProvider getUnaryNotTests */ @@ -148,3 +171,34 @@ protected function setUp() $this->compiler = new ExpressionCompiler(); } } + +class TestIssue108FunctionCompiler implements FunctionCompilerInterface +{ + public function getName() + { + return 'testIssue'; + } + + public function compilePreconditions(ExpressionCompiler $compiler, FunctionExpression $function) + { + if (1 !== count($function->args)) { + throw new \RuntimeException(sprintf('The %s() function expects exactly one argument, but got "%s".', $this->getName(), var_export($function->args, true))); + } + + $argName = $compiler->nextName(); + + $compiler + ->write("\$$argName = ") + ->compileInternal($function->args[0]) + ->writeln(';'); + + $compiler->attributes['arg_name'] = $argName; + } + + public function compile(ExpressionCompiler $compiler, FunctionExpression $function) + { + $argName = $compiler->attributes['arg_name']; + + $compiler->write("\$$argName !== null"); + } +}