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

Implemented missing support in CollectionMemberComparison. Removed old todo in ArrayHydrator. Finished implementation of IdentificationVariable in ArithmeticPrimary.

This commit is contained in:
Guilherme Blanco 2011-12-03 15:19:21 -05:00
parent 2642daa438
commit 2f6b930a8d
5 changed files with 120 additions and 74 deletions

View File

@ -28,11 +28,6 @@ use PDO, Doctrine\DBAL\Connection, Doctrine\ORM\Mapping\ClassMetadata;
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @author Guilherme Blanco <guilhermeblanoc@hotmail.com>
*
* @todo General behavior is "wrong" if you define an alias to selected IdentificationVariable.
* Example: SELECT u AS user FROM User u
* The result should contains an array where each array index is an array: array('user' => [User object])
* Problem must be solved somehow by removing the isMixed in ResultSetMapping
*/
class ArrayHydrator extends AbstractHydrator
{

View File

@ -2607,7 +2607,7 @@ class Parser
return $this->InputParameter();
}
return $this->IdentificationVariable();
return $this->StateFieldPathExpression();
}
/**

View File

@ -411,7 +411,8 @@ class SqlWalker implements TreeWalker
{
$this->_useSqlTableAliases = false;
return $this->walkUpdateClause($AST->updateClause) . $this->walkWhereClause($AST->whereClause);
return $this->walkUpdateClause($AST->updateClause)
. $this->walkWhereClause($AST->whereClause);
}
/**
@ -424,9 +425,29 @@ class SqlWalker implements TreeWalker
{
$this->_useSqlTableAliases = false;
return $this->walkDeleteClause($AST->deleteClause) . $this->walkWhereClause($AST->whereClause);
return $this->walkDeleteClause($AST->deleteClause)
. $this->walkWhereClause($AST->whereClause);
}
/**
* Walks down an IdentificationVariable AST node, thereby generating the appropriate SQL.
* This one differs of ->walkIdentificationVariable() because it generates the entity identifiers.
*
* @param string $identVariable
* @return string
*/
public function walkEntityIdentificationVariable($identVariable)
{
$class = $this->_queryComponents[$identVariable]['metadata'];
$tableAlias = $this->getSQLTableAlias($class->getTableName(), $identVariable);
$sqlParts = array();
foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) {
$sqlParts[] = $tableAlias . '.' . $columnName;
}
return implode(', ', $sqlParts);
}
/**
* Walks down an IdentificationVariable (no AST node associated), thereby generating the SQL.
@ -689,7 +710,7 @@ class SqlWalker implements TreeWalker
$expr = $orderByItem->expression;
$sql = ($expr instanceof AST\PathExpression)
? $this->walkPathExpression($expr)
: $this->_scalarResultAliasMap[$this->_queryComponents[$expr]['token']['value']];
: $this->walkResultVariable($this->_queryComponents[$expr]['token']['value']);
return $sql . ' ' . strtoupper($orderByItem->type);
}
@ -1287,15 +1308,7 @@ class SqlWalker implements TreeWalker
break;
default: // IdentificationVariable
$class = $this->_queryComponents[$expr]['metadata'];
$tableAlias = $this->getSQLTableAlias($class->getTableName(), $expr);
$sqlParts = array();
foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) {
$sqlParts[] = $tableAlias . '.' . $columnName;
}
$sql .= implode(', ', $sqlParts);
$sql .= $this->walkEntityIdentificationVariable($expr);
break;
}
@ -1558,20 +1571,30 @@ class SqlWalker implements TreeWalker
{
$sql = $collMemberExpr->not ? 'NOT ' : '';
$sql .= 'EXISTS (SELECT 1 FROM ';
$entityExpr = $collMemberExpr->entityExpression;
$entityExpr = $collMemberExpr->entityExpression;
$collPathExpr = $collMemberExpr->collectionValuedPathExpression;
$fieldName = $collPathExpr->field;
$dqlAlias = $collPathExpr->identificationVariable;
$dqlAlias = $collPathExpr->identificationVariable;
$class = $this->_queryComponents[$dqlAlias]['metadata'];
if ($entityExpr instanceof AST\InputParameter) {
$dqlParamKey = $entityExpr->name;
$entity = $this->_query->getParameter($dqlParamKey);
} else {
//TODO
throw new \BadMethodCallException("Not implemented");
switch (true) {
// InputParameter
case ($entityExpr instanceof AST\InputParameter):
$dqlParamKey = $entityExpr->name;
$entity = $this->_query->getParameter($dqlParamKey);
$entitySql = '?';
break;
// SingleValuedAssociationPathExpression | IdentificationVariable
case ($entityExpr instanceof AST\PathExpression):
$entitySql = $this->walkPathExpression($entityExpr);
break;
default:
throw new \BadMethodCallException("Not implemented");
}
$assoc = $class->associationMappings[$fieldName];
@ -1584,25 +1607,23 @@ class SqlWalker implements TreeWalker
$sql .= $targetClass->getQuotedTableName($this->_platform) . ' ' . $targetTableAlias . ' WHERE ';
$owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']];
$first = true;
$sqlParts = array();
foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) {
if ($first) $first = false; else $sql .= ' AND ';
$targetColumn = $class->getQuotedColumnName($class->fieldNames[$targetColumn], $this->_platform);
$sql .= $sourceTableAlias . '.' . $class->getQuotedColumnName($class->fieldNames[$targetColumn], $this->_platform)
. ' = '
. $targetTableAlias . '.' . $sourceColumn;
$sqlParts[] = $sourceTableAlias . '.' . $targetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn;
}
$sql .= ' AND ';
$first = true;
foreach ($targetClass->getQuotedIdentifierColumnNames($this->_platform) as $targetColumnName) {
if ($first) $first = false; else $sql .= ' AND ';
if (isset($dqlParamKey)) {
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
}
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
$sql .= $targetTableAlias . '.' . $targetColumnName . ' = ?';
$sqlParts[] = $targetTableAlias . '.' . $targetColumnName . ' = ' . $entitySql;
}
$sql .= implode(' AND ', $sqlParts);
} else { // many-to-many
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
@ -1619,39 +1640,42 @@ class SqlWalker implements TreeWalker
. ' INNER JOIN ' . $targetClass->getQuotedTableName($this->_platform) . ' ' . $targetTableAlias . ' ON ';
// join conditions
$joinColumns = $assoc['isOwningSide']
? $joinTable['inverseJoinColumns']
: $joinTable['joinColumns'];
$joinColumns = $assoc['isOwningSide'] ? $joinTable['inverseJoinColumns'] : $joinTable['joinColumns'];
$joinSqlParts = array();
$first = true;
foreach ($joinColumns as $joinColumn) {
if ($first) $first = false; else $sql .= ' AND ';
$targetColumn = $targetClass->getQuotedColumnName(
$targetClass->fieldNames[$joinColumn['referencedColumnName']],
$this->_platform
);
$sql .= $joinTableAlias . '.' . $joinColumn['name'] . ' = '
. $targetTableAlias . '.' . $targetClass->getQuotedColumnName($targetClass->fieldNames[$joinColumn['referencedColumnName']], $this->_platform);
$joinSqlParts[] = $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $targetTableAlias . '.' . $targetColumn;
}
$sql .= implode(' AND ', $joinSqlParts);
$sql .= ' WHERE ';
$joinColumns = $assoc['isOwningSide'] ? $joinTable['joinColumns'] : $joinTable['inverseJoinColumns'];
$first = true;
$sqlParts = array();
foreach ($joinColumns as $joinColumn) {
if ($first) $first = false; else $sql .= ' AND ';
$targetColumn = $class->getQuotedColumnName(
$class->fieldNames[$joinColumn['referencedColumnName']],
$this->_platform
);
$sql .= $joinTableAlias . '.' . $joinColumn['name'] . ' = '
. $sourceTableAlias . '.' . $class->getQuotedColumnName($class->fieldNames[$joinColumn['referencedColumnName']], $this->_platform);
$sqlParts[] = $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $sourceTableAlias . '.' . $targetColumn;
}
$sql .= ' AND ';
$first = true;
foreach ($targetClass->getQuotedIdentifierColumnNames($this->_platform) as $targetColumnName) {
if ($first) $first = false; else $sql .= ' AND ';
if (isset($dqlParamKey)) {
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
}
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
$sql .= $targetTableAlias . '.' . $targetColumnName . ' = ?';
$sqlParts[] = $targetTableAlias . '.' . $targetColumnName . ' = ' . $entitySql;
}
$sql .= implode(' AND ', $sqlParts);
}
return $sql . ')';
@ -1946,7 +1970,7 @@ class SqlWalker implements TreeWalker
{
if (is_string($term)) {
return (isset($this->_queryComponents[$term]))
? $this->_scalarResultAliasMap[$this->_queryComponents[$term]['token']['value']]
? $this->walkResultVariable($this->_queryComponents[$term]['token']['value'])
: $term;
}
@ -1998,8 +2022,7 @@ class SqlWalker implements TreeWalker
return $primary->dispatch($this);
}
// TODO: We need to deal with IdentificationVariable here
return '';
return $this->walkEntityIdentificationVariable($primary);
}
/**

View File

@ -196,7 +196,7 @@ public function <methodName>()
if ($this->_backupExisting && file_exists($path)) {
$backupPath = dirname($path) . DIRECTORY_SEPARATOR . basename($path) . "~";
if (!copy($path, $backupPath)) {
throw new \RuntimeException("Attempt to backup overwritten entitiy file but copy operation failed.");
throw new \RuntimeException("Attempt to backup overwritten entity file but copy operation failed.");
}
}
@ -754,7 +754,7 @@ public function <methodName>()
'<variableName>' => Inflector::camelize($fieldName),
'<methodName>' => $methodName,
'<fieldName>' => $fieldName,
'<variableDefault>' => ($defaultValue !== null ) ? ('='.$defaultValue) : '',
'<variableDefault>' => ($defaultValue !== null ) ? (' = '.$defaultValue) : '',
'<entity>' => $this->_getClassName($metadata)
);

View File

@ -536,43 +536,71 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
);
}
public function testSupportsMemberOfExpression()
public function testSupportsMemberOfExpressionOneToMany()
{
// "Get all users who have $phone as a phonenumber." (*cough* doesnt really make sense...)
$q1 = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.phonenumbers');
$q1->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.phonenumbers');
$q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$phone = new \Doctrine\Tests\Models\CMS\CmsPhonenumber;
$phone->phonenumber = 101;
$q1->setParameter('param', $phone);
$q->setParameter('param', $phone);
$this->assertEquals(
'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_phonenumbers c1_ WHERE c0_.id = c1_.user_id AND c1_.phonenumber = ?)',
$q1->getSql()
$q->getSql()
);
}
public function testSupportsMemberOfExpressionManyToMany()
{
// "Get all users who are members of $group."
$q2 = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.groups');
$q2->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE :param MEMBER OF u.groups');
$q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$group = new \Doctrine\Tests\Models\CMS\CmsGroup;
$group->id = 101;
$q2->setParameter('param', $group);
$q->setParameter('param', $group);
$this->assertEquals(
'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id = ?)',
$q2->getSql()
$q->getSql()
);
}
public function testSupportsMemberOfExpressionSelfReferencing()
{
// "Get all persons who have $person as a friend."
// Tough one: Many-many self-referencing ("friends") with class table inheritance
$q3 = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p WHERE :param MEMBER OF p.friends');
$q = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p WHERE :param MEMBER OF p.friends');
$person = new \Doctrine\Tests\Models\Company\CompanyPerson;
$this->_em->getClassMetadata(get_class($person))->setIdentifierValues($person, array('id' => 101));
$q3->setParameter('param', $person);
$q->setParameter('param', $person);
$this->assertEquals(
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c2_.salary AS salary3, c2_.department AS department4, c2_.startDate AS startDate5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c1_.car_id AS car_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE EXISTS (SELECT 1 FROM company_persons_friends c3_ INNER JOIN company_persons c4_ ON c3_.friend_id = c4_.id WHERE c3_.person_id = c0_.id AND c4_.id = ?)',
$q3->getSql()
$q->getSql()
);
}
public function testSupportsMemberOfWithSingleValuedAssociation()
{
// Impossible example, but it illustrates the purpose
$q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.email MEMBER OF u.groups');
$this->assertEquals(
'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id = c0_.email_id)',
$q->getSql()
);
}
public function testSupportsMemberOfWithIdentificationVariable()
{
// Impossible example, but it illustrates the purpose
$q = $this->_em->createQuery('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u MEMBER OF u.groups');
$this->assertEquals(
'SELECT c0_.id AS id0 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_users_groups c1_ INNER JOIN cms_groups c2_ ON c1_.group_id = c2_.id WHERE c1_.user_id = c0_.id AND c2_.id = c0_.id)',
$q->getSql()
);
}