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:
commit
462173ad71
@ -3026,4 +3026,18 @@ class ClassMetadataInfo implements ClassMetadata
|
|||||||
|
|
||||||
return $className;
|
return $className;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getMetadataValue($name) {
|
||||||
|
|
||||||
|
if (isset($this->$name)) {
|
||||||
|
return $this->$name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ use Doctrine\DBAL\LockMode;
|
|||||||
use Doctrine\ORM\Query\Parser;
|
use Doctrine\ORM\Query\Parser;
|
||||||
use Doctrine\ORM\Query\ParserResult;
|
use Doctrine\ORM\Query\ParserResult;
|
||||||
use Doctrine\ORM\Query\QueryException;
|
use Doctrine\ORM\Query\QueryException;
|
||||||
|
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||||
|
use Doctrine\ORM\Query\ParameterTypeInferer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Query object represents a DQL query.
|
* A Query object represents a DQL query.
|
||||||
@ -268,6 +270,10 @@ final class Query extends AbstractQuery
|
|||||||
$executor->setQueryCacheProfile($this->_queryCacheProfile);
|
$executor->setQueryCacheProfile($this->_queryCacheProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->_resultSetMapping === null) {
|
||||||
|
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare parameters
|
// Prepare parameters
|
||||||
$paramMappings = $this->_parserResult->getParameterMappings();
|
$paramMappings = $this->_parserResult->getParameterMappings();
|
||||||
|
|
||||||
@ -277,10 +283,6 @@ final class Query extends AbstractQuery
|
|||||||
|
|
||||||
list($sqlParams, $types) = $this->processParameterMappings($paramMappings);
|
list($sqlParams, $types) = $this->processParameterMappings($paramMappings);
|
||||||
|
|
||||||
if ($this->_resultSetMapping === null) {
|
|
||||||
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $executor->execute($this->_em->getConnection(), $sqlParams, $types);
|
return $executor->execute($this->_em->getConnection(), $sqlParams, $types);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,16 +301,21 @@ final class Query extends AbstractQuery
|
|||||||
$types = array();
|
$types = array();
|
||||||
|
|
||||||
foreach ($this->parameters as $parameter) {
|
foreach ($this->parameters as $parameter) {
|
||||||
$key = $parameter->getName();
|
$key = $parameter->getName();
|
||||||
|
$value = $parameter->getValue();
|
||||||
|
|
||||||
if ( ! isset($paramMappings[$key])) {
|
if ( ! isset($paramMappings[$key])) {
|
||||||
throw QueryException::unknownParameter($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)
|
$type = ($parameter->getValue() === $value)
|
||||||
? $parameter->getType()
|
? $parameter->getType()
|
||||||
: Query\ParameterTypeInferer::inferType($value);
|
: ParameterTypeInferer::inferType($value);
|
||||||
|
|
||||||
foreach ($paramMappings[$key] as $position) {
|
foreach ($paramMappings[$key] as $position) {
|
||||||
$types[$position] = $type;
|
$types[$position] = $type;
|
||||||
|
@ -153,6 +153,13 @@ class ResultSetMapping
|
|||||||
*/
|
*/
|
||||||
public $newObjectMappings = array();
|
public $newObjectMappings = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps metadata parameter names to the metadata attribute.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $metadataParameterMapping = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an entity result to this ResultSetMapping.
|
* Adds an entity result to this ResultSetMapping.
|
||||||
*
|
*
|
||||||
@ -371,6 +378,17 @@ class ResultSetMapping
|
|||||||
return $this;
|
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.
|
* Checks whether a column with a given name is mapped as a scalar result.
|
||||||
*
|
*
|
||||||
|
@ -1972,24 +1972,31 @@ class SqlWalker implements TreeWalker
|
|||||||
$sqlParameterList = array();
|
$sqlParameterList = array();
|
||||||
|
|
||||||
foreach ($instanceOfExpr->value as $parameter) {
|
foreach ($instanceOfExpr->value as $parameter) {
|
||||||
|
|
||||||
if ($parameter instanceof AST\InputParameter) {
|
if ($parameter instanceof AST\InputParameter) {
|
||||||
|
|
||||||
|
$this->rsm->addMetadataParameterMapping($parameter->name, 'discriminatorValue');
|
||||||
|
|
||||||
$sqlParameterList[] = $this->walkInputParameter($parameter);
|
$sqlParameterList[] = $this->walkInputParameter($parameter);
|
||||||
} else {
|
|
||||||
// Get name from ClassMetadata to resolve aliases.
|
|
||||||
$entityClassName = $this->em->getClassMetadata($parameter)->name;
|
|
||||||
|
|
||||||
if ($entityClassName == $class->name) {
|
continue;
|
||||||
$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]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) . ')';
|
$sql .= '(' . implode(', ', $sqlParameterList) . ')';
|
||||||
|
81
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1995Test.php
Normal file
81
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1995Test.php
Normal 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]);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user