1
0
mirror of synced 2024-12-14 07:06:04 +03:00

Merge pull request #689 from FabioBatSilva/DDC-1995

[WIP][DDC-1995 ] Support metadata class as parameter for instance of expression
This commit is contained in:
Guilherme Blanco 2013-06-07 14:42:59 -07:00
commit 462173ad71
5 changed files with 148 additions and 21 deletions

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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.
*

View File

@ -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) . ')';

View File

@ -0,0 +1,81 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\Models\Company\CompanyPerson;
use Doctrine\Tests\Models\Company\CompanyEmployee;
/**
* @group DDC-1995
*/
class DDC1995Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
public function setUp()
{
$this->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]);
}
}