Skip to content
Browse files

Implemented missing support in CollectionMemberComparison. Removed ol…

…d todo in ArrayHydrator. Finished implementation of IdentificationVariable in ArithmeticPrimary.
  • Loading branch information...
1 parent 2642daa commit 2f6b930a8d418fc34572de1867806a63c34abc6d @guilhermeblanco guilhermeblanco committed Dec 3, 2011
View
5 lib/Doctrine/ORM/Internal/Hydration/ArrayHydrator.php
@@ -28,11 +28,6 @@
* @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
2 lib/Doctrine/ORM/Query/Parser.php
@@ -2607,7 +2607,7 @@ public function SimpleEntityExpression()
return $this->InputParameter();
}
- return $this->IdentificationVariable();
+ return $this->StateFieldPathExpression();
}
/**
View
125 lib/Doctrine/ORM/Query/SqlWalker.php
@@ -411,7 +411,8 @@ public function walkUpdateStatement(AST\UpdateStatement $AST)
{
$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 @@ public function walkDeleteStatement(AST\DeleteStatement $AST)
{
$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 @@ public function walkOrderByItem($orderByItem)
$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 @@ public function walkSimpleSelectExpression($simpleSelectExpression)
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 @@ public function walkCollectionMemberExpression($collMemberExpr)
{
$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 @@ public function walkCollectionMemberExpression($collMemberExpr)
$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 @@ public function walkCollectionMemberExpression($collMemberExpr)
. ' 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 @@ public function walkArithmeticTerm($term)
{
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 @@ public function walkArithmeticPrimary($primary)
return $primary->dispatch($this);
}
- // TODO: We need to deal with IdentificationVariable here
- return '';
+ return $this->walkEntityIdentificationVariable($primary);
}
/**
View
10 lib/Doctrine/ORM/Tools/EntityGenerator.php
@@ -196,7 +196,7 @@ public function writeEntityClass(ClassMetadataInfo $metadata, $outputDirectory)
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.");
}
}
@@ -404,11 +404,11 @@ private function _generateEntityConstructor(ClassMetadataInfo $metadata)
$collections[] = '$this->'.$mapping['fieldName'].' = new \Doctrine\Common\Collections\ArrayCollection();';
}
}
-
+
if ($collections) {
return $this->_prefixCodeWithSpaces(str_replace("<collections>", implode("\n".$this->_spaces, $collections), self::$_constructorMethodTemplate));
}
-
+
return '';
}
@@ -576,7 +576,7 @@ private function _generateTableAnnotation($metadata)
if (isset($metadata->table['schema'])) {
$table[] = 'schema="' . $metadata->table['schema'] . '"';
}
-
+
if (isset($metadata->table['name'])) {
$table[] = 'name="' . $metadata->table['name'] . '"';
}
@@ -754,7 +754,7 @@ private function _generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $
'<variableName>' => Inflector::camelize($fieldName),
'<methodName>' => $methodName,
'<fieldName>' => $fieldName,
- '<variableDefault>' => ($defaultValue !== null ) ? ('='.$defaultValue) : '',
+ '<variableDefault>' => ($defaultValue !== null ) ? (' = '.$defaultValue) : '',
'<entity>' => $this->_getClassName($metadata)
);
View
52 tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php
@@ -536,43 +536,71 @@ public function testSubqueriesInComparisonExpression()
);
}
- 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()
);
}

0 comments on commit 2f6b930

Please sign in to comment.
Something went wrong with that request. Please try again.