diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php index 6a1e32acd..762cf67ce 100644 --- a/lib/Doctrine/ORM/Query/Parser.php +++ b/lib/Doctrine/ORM/Query/Parser.php @@ -3406,10 +3406,13 @@ class Parser public function CustomFunctionsReturningNumerics() { // getCustomNumericFunction is case-insensitive - $funcName = strtolower($this->lexer->lookahead['value']); - $funcClass = $this->em->getConfiguration()->getCustomNumericFunction($funcName); + $functionName = strtolower($this->lexer->lookahead['value']); + $functionClass = $this->em->getConfiguration()->getCustomNumericFunction($functionName); + + $function = is_string($functionClass) + ? new $functionClass($functionName) + : $functionClass($functionName); - $function = new $funcClass($funcName); $function->parse($this); return $function; @@ -3442,10 +3445,13 @@ class Parser public function CustomFunctionsReturningDatetime() { // getCustomDatetimeFunction is case-insensitive - $funcName = $this->lexer->lookahead['value']; - $funcClass = $this->em->getConfiguration()->getCustomDatetimeFunction($funcName); + $functionName = $this->lexer->lookahead['value']; + $functionClass = $this->em->getConfiguration()->getCustomDatetimeFunction($functionName); + + $function = is_string($functionClass) + ? new $functionClass($functionName) + : $functionClass($functionName); - $function = new $funcClass($funcName); $function->parse($this); return $function; @@ -3479,10 +3485,13 @@ class Parser public function CustomFunctionsReturningStrings() { // getCustomStringFunction is case-insensitive - $funcName = $this->lexer->lookahead['value']; - $funcClass = $this->em->getConfiguration()->getCustomStringFunction($funcName); + $functionName = $this->lexer->lookahead['value']; + $functionClass = $this->em->getConfiguration()->getCustomStringFunction($functionName); + + $function = is_string($functionClass) + ? new $functionClass($functionName) + : $functionClass($functionName); - $function = new $funcClass($funcName); $function->parse($this); return $function; diff --git a/tests/Doctrine/Tests/ORM/Functional/CustomFunctionsTest.php b/tests/Doctrine/Tests/ORM/Functional/CustomFunctionsTest.php new file mode 100644 index 000000000..63c3e4ee9 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/CustomFunctionsTest.php @@ -0,0 +1,72 @@ +useModelSet('cms'); + + parent::setUp(); + } + + public function testCustomFunctionDefinedWithCallback() + { + $user = new CmsUser(); + $user->name = 'Bob'; + $user->username = 'Dylan'; + $this->_em->persist($user); + $this->_em->flush(); + + // Instead of defining the function with the class name, we use a callback + $this->_em->getConfiguration()->addCustomStringFunction('FOO', function($funcName) { + return new NoOp($funcName); + }); + $this->_em->getConfiguration()->addCustomNumericFunction('BAR', function($funcName) { + return new NoOp($funcName); + }); + + $query = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u' + . ' WHERE FOO(u.name) = \'Bob\'' + . ' AND BAR(1) = 1'); + + $users = $query->getResult(); + + $this->assertEquals(1, count($users)); + $this->assertSame($user, $users[0]); + } +} + +class NoOp extends FunctionNode +{ + /** + * @var PathExpression + */ + private $field; + + public function parse(Parser $parser) + { + $parser->match(Lexer::T_IDENTIFIER); + $parser->match(Lexer::T_OPEN_PARENTHESIS); + $this->field = $parser->ArithmeticPrimary(); + $parser->match(Lexer::T_CLOSE_PARENTHESIS); + } + + public function getSql(SqlWalker $sqlWalker) + { + return $this->field->dispatch($sqlWalker); + } +} +