diff --git a/lib/Doctrine/ORM/AbstractQuery.php b/lib/Doctrine/ORM/AbstractQuery.php index 26eee1fb8..88bbfc2c1 100644 --- a/lib/Doctrine/ORM/AbstractQuery.php +++ b/lib/Doctrine/ORM/AbstractQuery.php @@ -195,6 +195,8 @@ abstract class AbstractQuery */ public function setParameter($key, $value, $type = null) { + $key = trim($key, ':'); + if ($type === null) { $type = Query\ParameterTypeInferer::inferType($value); } diff --git a/lib/Doctrine/ORM/Query/AST/InstanceOfExpression.php b/lib/Doctrine/ORM/Query/AST/InstanceOfExpression.php index 3aefd61d9..b586f4812 100644 --- a/lib/Doctrine/ORM/Query/AST/InstanceOfExpression.php +++ b/lib/Doctrine/ORM/Query/AST/InstanceOfExpression.php @@ -20,7 +20,8 @@ namespace Doctrine\ORM\Query\AST; /** - * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (AbstractSchemaName | InputParameter) + * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")") + * InstanceOfParameter ::= AbstractSchemaName | InputParameter * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php index 0f7c88538..699537456 100644 --- a/lib/Doctrine/ORM/Query/Parser.php +++ b/lib/Doctrine/ORM/Query/Parser.php @@ -2676,7 +2676,7 @@ class Parser } /** - * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (AbstractSchemaName | InputParameter) + * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")") * * @return \Doctrine\ORM\Query\AST\InstanceOfExpression */ @@ -2690,22 +2690,50 @@ class Parser } $this->match(Lexer::T_INSTANCE); + $this->match(Lexer::T_OF); + + $exprValues = array(); + + if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) { + $this->match(Lexer::T_OPEN_PARENTHESIS); + + $exprValues[] = $this->InstanceOfParameter(); - if ($this->_lexer->isNextToken(Lexer::T_OF)) { - $this->match(Lexer::T_OF); + while ($this->_lexer->isNextToken(Lexer::T_COMMA)) { + $this->match(Lexer::T_COMMA); + + $exprValues[] = $this->InstanceOfParameter(); + } + + $this->match(Lexer::T_CLOSE_PARENTHESIS); + + $instanceOfExpression->value = $exprValues; + + return $instanceOfExpression; } - if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { - $this->match(Lexer::T_INPUT_PARAMETER); - $exprValue = new AST\InputParameter($this->_lexer->token['value']); - } else { - $exprValue = $this->AliasIdentificationVariable(); - } + $exprValues[] = $this->InstanceOfParameter(); - $instanceOfExpression->value = $exprValue; + $instanceOfExpression->value = $exprValues; return $instanceOfExpression; } + + /** + * InstanceOfParameter ::= AbstractSchemaName | InputParameter + * + * @return mixed + */ + public function InstanceOfParameter() + { + if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { + $this->match(Lexer::T_INPUT_PARAMETER); + + return new AST\InputParameter($this->_lexer->token['value']); + } + + return $this->AliasIdentificationVariable(); + } /** * LikeExpression ::= StringExpression ["NOT"] "LIKE" (string | input_parameter) ["ESCAPE" char] diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index cc387543c..dc97d6bb5 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -1756,34 +1756,41 @@ class SqlWalker implements TreeWalker if ($this->_useSqlTableAliases) { $sql .= $this->getSQLTableAlias($discrClass->table['name'], $dqlAlias) . '.'; } + + $sql .= $class->discriminatorColumn['name'] . ($instanceOfExpr->not ? ' NOT IN ' : ' IN '); + + $sqlParameterList = array(); + + foreach ($instanceOfExpr->value as $parameter) { + if ($parameter instanceof AST\InputParameter) { + // We need to modify the parameter value to be its correspondent mapped value + $dqlParamKey = $parameter->name; + $paramValue = $this->_query->getParameter($dqlParamKey); - $sql .= $class->discriminatorColumn['name'] . ($instanceOfExpr->not ? ' <> ' : ' = '); + if ( ! ($paramValue instanceof \Doctrine\ORM\Mapping\ClassMetadata)) { + throw QueryException::invalidParameterType('ClassMetadata', get_class($paramValue)); + } - if ($instanceOfExpr->value instanceof AST\InputParameter) { - // We need to modify the parameter value to be its correspondent mapped value - $dqlParamKey = $instanceOfExpr->value->name; - $paramValue = $this->_query->getParameter($dqlParamKey); - - if ( ! ($paramValue instanceof \Doctrine\ORM\Mapping\ClassMetadata)) { - throw QueryException::invalidParameterType('ClassMetadata', get_class($paramValue)); + $entityClassName = $paramValue->name; + } else { + // Get name from ClassMetadata to resolve aliases. + $entityClassName = $this->_em->getClassMetadata($parameter)->name; } - - $entityClassName = $paramValue->name; - } else { - // Get name from ClassMetadata to resolve aliases. - $entityClassName = $this->_em->getClassMetadata($instanceOfExpr->value)->name; - } - if ($entityClassName == $class->name) { - $sql .= $this->_conn->quote($class->discriminatorValue); - } else { - $discrMap = array_flip($class->discriminatorMap); - if (!isset($discrMap[$entityClassName])) { - throw QueryException::instanceOfUnrelatedClass($entityClassName, $class->rootEntityName); + if ($entityClassName == $class->name) { + $sqlParameterList[] = $this->_conn->quote($class->discriminatorValue); + } else { + $discrMap = array_flip($class->discriminatorMap); + + if (!isset($discrMap[$entityClassName])) { + throw QueryException::instanceOfUnrelatedClass($entityClassName, $class->rootEntityName); + } + + $sqlParameterList[] = $this->_conn->quote($discrMap[$entityClassName]); } - - $sql .= $this->_conn->quote($discrMap[$entityClassName]); } + + $sql .= '(' . implode(', ', $sqlParameterList) . ')'; return $sql; } diff --git a/lib/Doctrine/ORM/QueryBuilder.php b/lib/Doctrine/ORM/QueryBuilder.php index 4facce77f..9b2829408 100644 --- a/lib/Doctrine/ORM/QueryBuilder.php +++ b/lib/Doctrine/ORM/QueryBuilder.php @@ -323,6 +323,8 @@ class QueryBuilder */ public function setParameter($key, $value, $type = null) { + $key = trim($key, ':'); + if ($type === null) { $type = Query\ParameterTypeInferer::inferType($value); } diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index 503807594..4c081402d 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -380,7 +380,15 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( "SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyEmployee", - "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr = 'employee'" + "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee')" + ); + } + + public function testSupportsInstanceOfExpressionInWherePartWithMultipleValues() + { + $this->assertSqlGeneration( + "SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF (Doctrine\Tests\Models\Company\CompanyEmployee, \Doctrine\Tests\Models\Company\CompanyManager)", + "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee', 'manager')" ); } @@ -391,7 +399,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( "SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF \Doctrine\Tests\Models\Company\CompanyEmployee", - "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr = 'employee'" + "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee')" ); } @@ -410,7 +418,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( "SELECT u FROM Doctrine\Tests\Models\Company\CompanyEmployee u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyManager", - "SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c0_.discr AS discr4 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id WHERE c0_.discr = 'manager'" + "SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c0_.discr AS discr4 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id WHERE c0_.discr IN ('manager')" ); } @@ -418,7 +426,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( "SELECT u FROM Doctrine\Tests\Models\Company\CompanyManager u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyManager", - "SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c2_.title AS title4, c0_.discr AS discr5 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id WHERE c0_.discr = 'manager'" + "SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c2_.title AS title4, c0_.discr AS discr5 FROM company_managers c2_ INNER JOIN company_employees c1_ ON c2_.id = c1_.id INNER JOIN company_persons c0_ ON c2_.id = c0_.id WHERE c0_.discr IN ('manager')" ); } @@ -426,7 +434,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase { $this->assertSqlGeneration( "SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF ?1", - "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr = 'employee'", + "SELECT c0_.id AS id0, c0_.name AS name1, c0_.discr AS discr2 FROM company_persons c0_ WHERE c0_.discr IN ('employee')", array(), array(1 => $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyEmployee')) ); }