From 710d0d1109720810cb3d4a226cbb2d9db8ba668f Mon Sep 17 00:00:00 2001 From: "Fabio B. Silva" Date: Fri, 7 Jun 2013 17:01:52 -0400 Subject: [PATCH] Fix DDC-1995 --- .../ORM/Mapping/ClassMetadataInfo.php | 14 ++++ lib/Doctrine/ORM/Query.php | 21 +++-- lib/Doctrine/ORM/Query/ResultSetMapping.php | 18 +++++ lib/Doctrine/ORM/Query/SqlWalker.php | 35 ++++---- .../ORM/Functional/Ticket/DDC1995Test.php | 81 +++++++++++++++++++ 5 files changed, 148 insertions(+), 21 deletions(-) create mode 100644 tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1995Test.php diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index cda11d44b..da2b1caa6 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -3026,4 +3026,18 @@ class ClassMetadataInfo implements ClassMetadata return $className; } + + /** + * @param string $name + * + * @return mixed + */ + public function getMetadataValue($name) { + + if (isset($this->$name)) { + return $this->$name; + } + + return null; + } } diff --git a/lib/Doctrine/ORM/Query.php b/lib/Doctrine/ORM/Query.php index 107055ed3..71f5f5550 100644 --- a/lib/Doctrine/ORM/Query.php +++ b/lib/Doctrine/ORM/Query.php @@ -26,6 +26,8 @@ use Doctrine\DBAL\LockMode; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\ParserResult; use Doctrine\ORM\Query\QueryException; +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Query\ParameterTypeInferer; /** * A Query object represents a DQL query. @@ -268,6 +270,10 @@ final class Query extends AbstractQuery $executor->setQueryCacheProfile($this->_queryCacheProfile); } + if ($this->_resultSetMapping === null) { + $this->_resultSetMapping = $this->_parserResult->getResultSetMapping(); + } + // Prepare parameters $paramMappings = $this->_parserResult->getParameterMappings(); @@ -277,10 +283,6 @@ final class Query extends AbstractQuery list($sqlParams, $types) = $this->processParameterMappings($paramMappings); - if ($this->_resultSetMapping === null) { - $this->_resultSetMapping = $this->_parserResult->getResultSetMapping(); - } - return $executor->execute($this->_em->getConnection(), $sqlParams, $types); } @@ -299,16 +301,21 @@ final class Query extends AbstractQuery $types = array(); foreach ($this->parameters as $parameter) { - $key = $parameter->getName(); + $key = $parameter->getName(); + $value = $parameter->getValue(); if ( ! isset($paramMappings[$key])) { throw QueryException::unknownParameter($key); } - $value = $this->processParameterValue($parameter->getValue()); + if (isset($this->_resultSetMapping->metadataParameterMapping[$key]) && $value instanceof ClassMetadata) { + $value = $value->getMetadataValue($this->_resultSetMapping->metadataParameterMapping[$key]); + } + + $value = $this->processParameterValue($value); $type = ($parameter->getValue() === $value) ? $parameter->getType() - : Query\ParameterTypeInferer::inferType($value); + : ParameterTypeInferer::inferType($value); foreach ($paramMappings[$key] as $position) { $types[$position] = $type; diff --git a/lib/Doctrine/ORM/Query/ResultSetMapping.php b/lib/Doctrine/ORM/Query/ResultSetMapping.php index b06b68385..2f1727383 100644 --- a/lib/Doctrine/ORM/Query/ResultSetMapping.php +++ b/lib/Doctrine/ORM/Query/ResultSetMapping.php @@ -153,6 +153,13 @@ class ResultSetMapping */ public $newObjectMappings = array(); + /** + * Maps metadata parameter names to the metadata attribute. + * + * @var array + */ + public $metadataParameterMapping = array(); + /** * Adds an entity result to this ResultSetMapping. * @@ -371,6 +378,17 @@ class ResultSetMapping return $this; } + /** + * Adds a metadata parameter mappings. + * + * @param mixed $parameter The parameter name in the SQL result set. + * @param string $attribute The metadata attribute. + */ + public function addMetadataParameterMapping($parameter, $attribute) + { + $this->metadataParameterMapping[$parameter] = $attribute; + } + /** * Checks whether a column with a given name is mapped as a scalar result. * diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index b971bcfe5..c048ba2c9 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -1972,24 +1972,31 @@ class SqlWalker implements TreeWalker $sqlParameterList = array(); foreach ($instanceOfExpr->value as $parameter) { + if ($parameter instanceof AST\InputParameter) { + + $this->rsm->addMetadataParameterMapping($parameter->name, 'discriminatorValue'); + $sqlParameterList[] = $this->walkInputParameter($parameter); - } else { - // Get name from ClassMetadata to resolve aliases. - $entityClassName = $this->em->getClassMetadata($parameter)->name; - 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]); - } + continue; } + + // Get name from ClassMetadata to resolve aliases. + $entityClassName = $this->em->getClassMetadata($parameter)->name; + $discriminatorValue = $class->discriminatorValue; + + if ($entityClassName !== $class->name) { + $discrMap = array_flip($class->discriminatorMap); + + if ( ! isset($discrMap[$entityClassName])) { + throw QueryException::instanceOfUnrelatedClass($entityClassName, $class->rootEntityName); + } + + $discriminatorValue = $discrMap[$entityClassName]; + } + + $sqlParameterList[] = $this->conn->quote($discriminatorValue); } $sql .= '(' . implode(', ', $sqlParameterList) . ')'; diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1995Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1995Test.php new file mode 100644 index 000000000..0bfd73960 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1995Test.php @@ -0,0 +1,81 @@ +useModelSet('company'); + parent::setUp(); + } + + public function testIssue() + { + $person = new CompanyPerson; + $person->setName('p1'); + + $employee = new CompanyEmployee; + $employee->setName('Foo'); + $employee->setDepartment('bar'); + $employee->setSalary(1000); + + $this->_em->persist($person); + $this->_em->persist($employee); + $this->_em->flush(); + $this->_em->clear(); + + $dql = 'SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF ?1'; + $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyEmployee'); + + $result = $this->_em->createQuery($dql) + ->setParameter(1, $class) + ->getResult(); + + $this->assertCount(1, $result); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $result[0]); + } + + public function testQueryCache() + { + $person = new CompanyPerson; + $person->setName('p1'); + + $employee = new CompanyEmployee; + $employee->setName('Foo'); + $employee->setDepartment('bar'); + $employee->setSalary(1000); + + $this->_em->persist($person); + $this->_em->persist($employee); + $this->_em->flush(); + $this->_em->clear(); + + $dql = 'SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF :type'; + $class1 = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyEmployee'); + $class2 = $this->_em->getClassMetadata('Doctrine\Tests\Models\Company\CompanyPerson'); + + $result1 = $this->_em->createQuery($dql) + ->setParameter('type', $class1) + ->useQueryCache(true) + ->getResult(); + + $result2 = $this->_em->createQuery($dql) + ->setParameter('type', $class2) + ->useQueryCache(true) + ->getResult(); + + $this->assertCount(1, $result1); + $this->assertCount(1, $result2); + + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $result1[0]); + $this->assertInstanceOf('Doctrine\Tests\Models\Company\CompanyPerson', $result2[0]); + $this->assertNotInstanceOf('Doctrine\Tests\Models\Company\CompanyEmployee', $result2[0]); + } +} \ No newline at end of file