1
0
mirror of synced 2025-01-18 14:31:40 +03:00

[2.0] Refactorings in DQL parser to allow more granular enhancements scheduled for later versions. Fixed issues with missing validations of invalid ResultVariable, Unknown query components and Re-declaration of query compoenents.

This commit is contained in:
guilhermeblanco 2009-12-27 03:26:15 +00:00
parent 64f59a7a49
commit 262855a66c
7 changed files with 311 additions and 154 deletions

View File

@ -59,15 +59,6 @@ class PathExpression extends Node
public function dispatch($walker)
{
switch ($this->type) {
case self::TYPE_STATE_FIELD:
return $walker->walkStateFieldPathExpression($this);
case self::TYPE_SINGLE_VALUED_ASSOCIATION:
return $walker->walkSingleValuedAssociationPathExpression($this);
case self::TYPE_COLLECTION_VALUED_ASSOCIATION:
return $walker->walkCollectionValuedAssociationPathExpression($this);
default:
throw new \Exception("Unexhaustive match.");
}
return $walker->walkPathExpression($this);
}
}

View File

@ -66,12 +66,12 @@ class Parser
);
/**
* Path expressions that were encountered during parsing of SelectExpressions
* Expressions that were encountered during parsing of identifiers and expressions
* and still need to be validated.
*
* @var array
*/
private $_deferredPathExpressionStacks = array();
private $_deferredExpressionsStack = array();
/**
* The lexer.
@ -485,25 +485,172 @@ class Parser
}
/**
* Begins a new stack of deferred path expressions.
* Subscribe expression to be validated.
*
* @param mixed $expression
* @param string $method
* @param array $token
* @param integer $nestingLevel
*/
private function _beginDeferredPathExpressionStack()
private function _subscribeExpression($expression, $method, $token, $nextingLevel = null)
{
$this->_deferredPathExpressionStacks[] = array();
$nestingLevel = ($nestingLevel !== null) ?: $this->_nestingLevel;
$exprStack[] = array(
'method' => $method,
'expression' => $expression,
'nestingLevel' => $nestingLevel,
'token' => $token,
);
array_push($this->_deferredExpressionsStack, $exprStack);
}
/**
* Processes the topmost stack of deferred path expressions.
*/
private function _processDeferredPathExpressionStack()
private function _processDeferredExpressionsStack()
{
$exprStack = array_pop($this->_deferredPathExpressionStacks);
foreach ($exprStack as $item) {
$this->_validatePathExpression(
$item['pathExpression'], $item['nestingLevel'], $item['token']
foreach ($this->_deferredExpressionsStack as $item) {
$method = '_validate' . $item['method'];
$this->$method($item['expression'], $item['token'], $item['nestingLevel']);
}
}
/**
* Validates that the given <tt>IdentificationVariable</tt> is a semantically correct.
* It must exist in query components list.
*
* @param string $identVariable
* @param array $token
* @param integer $nestingLevel
*
* @return array Query Component
*/
private function _validateIdentificationVariable($identVariable, $token, $nestingLevel)
{
// Check if IdentificationVariable exists in queryComponents
if ( ! isset($this->_queryComponents[$identVariable])) {
$this->semanticalError("'$identVariable' is not defined.", $token);
}
$qComp = $this->_queryComponents[$identVariable];
// Check if queryComponent points to an AbstractSchemaName or a ResultVariable
if ( ! isset($qComp['metadata'])) {
$this->semanticalError("'$identVariable' does not point to a Class.", $token);
}
// Validate if identification variable nesting level is lower or equal than the current one
if ($qComp['nestingLevel'] > $nestingLevel) {
$this->semanticalError(
"'$identVariable' is used outside the scope of its declaration.", $token
);
}
return $qComp;
}
/**
* Validates that the given <tt>AliasIdentificationVariable</tt> is a semantically correct.
* It must not exist in query components list.
*
* @param string $aliasIdentVariable
* @param array $token
* @param integer $nestingLevel
*
* @return boolean
*/
private function _validateAliasIdentificationVariable($aliasIdentVariable, $token, $nestingLevel)
{
$exists = isset($this->_queryComponents[$aliasIdentVariable]);
if ($exists) {
$this->semanticalError("'$aliasIdentVariable' is already defined.", $token);
}
return $exists;
}
/**
* Validates that the given <tt>AbstractSchemaName</tt> is a semantically correct.
* It must be defined in the scope of Application.
*
* @param string $schemaName
* @param array $token
* @param integer $nestingLevel
*
* @return boolean
*/
private function _validateAbstractSchemaName($schemaName, $token, $nestingLevel)
{
$exists = class_exists($schemaName, true);
if ( ! $exists) {
$this->semanticalError("Class '$schemaName' is not defined.", $token);
}
return $exists;
}
/**
* Validates that the given <tt>AliasIdentificationVariable</tt> is a semantically correct.
* It must exist in query components list.
*
* @param string $resultVariable
* @param array $token
* @param integer $nestingLevel
*
* @return array Query Component
*/
private function _validateResultVariable($resultVariable, $token, $nestingLevel)
{
// Check if ResultVariable exists in queryComponents
if ( ! isset($this->_queryComponents[$resultVariable])) {
$this->semanticalError("'$resultVariable' is not defined.", $token);
}
$qComp = $this->_queryComponents[$resultVariable];
// Check if queryComponent points to an AbstractSchemaName or a ResultVariable
if ( ! isset($qComp['resultVariable'])) {
$this->semanticalError("'$identVariable' does not point to a ResultVariable.", $token);
}
// Validate if identification variable nesting level is lower or equal than the current one
if ($qComp['nestingLevel'] > $nestingLevel) {
$this->semanticalError(
"'$resultVariable' is used outside the scope of its declaration.", $token
);
}
return $qComp;
}
/**
* Validates that the given <tt>JoinAssociationPathExpression</tt> is a semantically correct.
*
* @param JoinAssociationPathExpression $pathExpression
* @param array $token
* @param integer $nestingLevel
*
* @return array Query Component
*/
private function _validateJoinAssociationPathExpression(AST\JoinAssociationPathExpression $pathExpression, $token, $nestingLevel)
{
$qComp = $this->_queryComponents[$pathExpression->identificationVariable];;
// Validating association field (*-to-one or *-to-many)
$field = $pathExpression->associationField;
$class = $qComp['metadata'];
if ( ! isset($class->associationMappings[$field])) {
$this->semanticalError('Class ' . $class->name . ' has no association named ' . $field);
}
return $qComp;
}
/**
@ -516,19 +663,16 @@ class Parser
* CollectionValuedPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* CollectionValuedAssociationField
*
* @param PathExpression $pathExpression
* @param integer $nestingLevel
* @param array $token
* @param integer $nestingLevel
*
* @return integer
*/
private function _validatePathExpression(AST\PathExpression $pathExpression, $nestingLevel = null, $token = null)
private function _validatePathExpression(AST\PathExpression $pathExpression, $token, $nestingLevel)
{
$identVariable = $pathExpression->identificationVariable;
$nestingLevel = ($nestingLevel !== null) ?: $this->_nestingLevel;
$token = ($token) ?: $this->_lexer->lookahead;
$qComp = $this->_queryComponents[$pathExpression->identificationVariable];
$this->_validateIdentificationVariable($identVariable, $nestingLevel, $token);
$class = $this->_queryComponents[$identVariable]['metadata'];
$class = $qComp['metadata'];
$stateField = $collectionField = null;
foreach ($pathExpression->parts as $field) {
@ -550,7 +694,7 @@ class Parser
// Check if field exists
if ( ! isset($class->associationMappings[$field]) && ! isset($class->fieldMappings[$field])) {
$this->semanticalError(
'Class ' . $class->name . ' has no field named ' . $field, $token
'Class ' . $class->name . ' has no field or association named ' . $field, $token
);
}
@ -597,12 +741,12 @@ class Parser
}
// Build the error message
$semanticalError = 'Invalid PathExpression.';
$semanticalError = 'Invalid PathExpression. ';
if (count($expectedStringTypes) == 1) {
$semanticalError .= ' Must be a ' . $expectedStringTypes[0] . '.';
$semanticalError .= 'Must be a ' . $expectedStringTypes[0] . '.';
} else {
$semanticalError .= ' ' . implode(' or ', $expectedStringTypes) . ' expected.';
$semanticalError .= implode(' or ', $expectedStringTypes) . ' expected.';
}
$this->semanticalError($semanticalError, $token);
@ -613,35 +757,6 @@ class Parser
return $expressionType;
}
/**
* Validates that the given <tt>IdentificationVariable</tt> is a semantically correct.
* It must exist in query components list.
*
* @param string $identVariable
* @param integer $nestingLevel
* @param array $token
* @return array Query Component
*/
private function _validateIdentificationVariable($identVariable, $nestingLevel = null, $token = null)
{
$nestingLevel = ($nestingLevel !== null) ?: $this->_nestingLevel;
$token = ($token) ?: $this->_lexer->lookahead;
if ( ! isset($this->_queryComponents[$identVariable])) {
$this->semanticalError("'$identVariable' is not defined", $token);
}
// Validate if identification variable nesting level is lower or equal than the current one
if ($this->_queryComponents[$identVariable]['nestingLevel'] > $nestingLevel) {
$this->semanticalError(
"'$idVariable' is used outside the scope of its declaration",
$token
);
}
return $this->_queryComponents[$identVariable];
}
/**
@ -679,15 +794,8 @@ class Parser
*/
public function SelectStatement()
{
// We need to prevent semantical checks on SelectClause,
// since we do not have any IdentificationVariable yet
$this->_beginDeferredPathExpressionStack();
$selectStatement = new AST\SelectStatement($this->SelectClause(), $this->FromClause());
// Activate semantical checks after this point. Process all deferred checks in pipeline
$this->_processDeferredPathExpressionStack();
$selectStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE)
? $this->WhereClause() : null;
@ -700,6 +808,9 @@ class Parser
$selectStatement->orderByClause = $this->_lexer->isNextToken(Lexer::T_ORDER)
? $this->OrderByClause() : null;
// Activate semantical checks after this point. Process all deferred checks in pipeline
$this->_processDeferredExpressionsStack();
return $selectStatement;
}
@ -713,6 +824,9 @@ class Parser
$updateStatement = new AST\UpdateStatement($this->UpdateClause());
$updateStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE)
? $this->WhereClause() : null;
// Activate semantical checks after this point. Process all deferred checks in pipeline
$this->_processDeferredExpressionsStack();
return $updateStatement;
}
@ -727,6 +841,9 @@ class Parser
$deleteStatement = new AST\DeleteStatement($this->DeleteClause());
$deleteStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE)
? $this->WhereClause() : null;
// Activate semantical checks after this point. Process all deferred checks in pipeline
$this->_processDeferredExpressionsStack();
return $deleteStatement;
}
@ -741,7 +858,19 @@ class Parser
{
$this->match(Lexer::T_IDENTIFIER);
return $this->_lexer->token['value'];
$identVariable = $this->_lexer->token['value'];
// Defer IdentificationVariable validation
$exprStack = array(
'method' => 'IdentificationVariable',
'expression' => $identVariable,
'nestingLevel' => $this->_nestingLevel,
'token' => $this->_lexer->token,
);
array_push($this->_deferredExpressionsStack, $exprStack);
return $identVariable;
}
/**
@ -752,8 +881,15 @@ class Parser
public function AliasIdentificationVariable()
{
$this->match(Lexer::T_IDENTIFIER);
$aliasIdentVariable = $this->_lexer->token['value'];
// Apply AliasIdentificationVariable validation
$this->_validateAliasIdentificationVariable(
$aliasIdentVariable, $this->_lexer->token, $this->_nestingLevel
);
return $this->_lexer->token['value'];
return $aliasIdentVariable;
}
/**
@ -765,7 +901,14 @@ class Parser
{
$this->match(Lexer::T_IDENTIFIER);
return $this->_lexer->token['value'];
$schemaName = $this->_lexer->token['value'];
// Apply AbstractSchemaName validation
$this->_validateAbstractSchemaName(
$schemaName, $this->_lexer->token, $this->_nestingLevel
);
return $schemaName;
}
/**
@ -777,7 +920,19 @@ class Parser
{
$this->match(Lexer::T_IDENTIFIER);
return $this->_lexer->token['value'];
$resultVariable = $this->_lexer->token['value'];
// Defer ResultVariable validation
$exprStack = array(
'method' => 'ResultVariable',
'expression' => $resultVariable,
'nestingLevel' => $this->_nestingLevel,
'token' => $this->_lexer->token,
);
array_push($this->_deferredExpressionsStack, $exprStack);
return $resultVariable;
}
@ -789,34 +944,37 @@ class Parser
public function JoinAssociationPathExpression()
{
$token = $this->_lexer->lookahead;
$identVariable = $this->IdentificationVariable();
$this->match(Lexer::T_DOT);
$this->match(Lexer::T_IDENTIFIER);
$field = $this->_lexer->token['value'];
// Validating IdentificationVariable (it was already defined previously)
$this->_validateIdentificationVariable($identVariable, null, $token);
$pathExpr = new AST\JoinAssociationPathExpression($identVariable, $field);
// Validating association field (*-to-one or *-to-many)
$class = $this->_queryComponents[$identVariable]['metadata'];
// Defer JoinAssociationPathExpression validation
$exprStack = array(
'method' => 'JoinAssociationPathExpression',
'expression' => $pathExpr,
'nestingLevel' => $this->_nestingLevel,
'token' => $token,
);
array_push($this->_deferredExpressionsStack, $exprStack);
if ( ! isset($class->associationMappings[$field])) {
$this->semanticalError('Class ' . $class->name . ' has no field named ' . $field);
}
return new AST\JoinAssociationPathExpression($identVariable, $field);
return $pathExpr;
}
/**
* Parses an arbitrary path expression. Applies or defer semantical validation
* Parses an arbitrary path expression and defers semantical validation
* based on expected types.
*
* PathExpression ::= IdentificationVariable "." {identifier "."}* identifier
*
* @param integer $expectedType
* @param integer $expectedTypes
* @return \Doctrine\ORM\Query\AST\PathExpression
*/
public function PathExpression($expectedType)
public function PathExpression($expectedTypes)
{
$token = $this->_lexer->lookahead;
$identVariable = $this->IdentificationVariable();
@ -830,24 +988,18 @@ class Parser
} while ($this->_lexer->isNextToken(Lexer::T_DOT));
// Creating AST node
$pathExpr = new AST\PathExpression($expectedType, $identVariable, $parts);
$pathExpr = new AST\PathExpression($expectedTypes, $identVariable, $parts);
// Defer PathExpression validation if requested to be defered
if ( ! empty($this->_deferredPathExpressionStacks)) {
$exprStack = array_pop($this->_deferredPathExpressionStacks);
$exprStack[] = array(
'pathExpression' => $pathExpr,
'nestingLevel' => $this->_nestingLevel,
'token' => $token,
);
array_push($this->_deferredPathExpressionStacks, $exprStack);
return $pathExpr;
}
// Apply PathExpression validation normally (not in defer mode)
$this->_validatePathExpression($pathExpr, $this->_nestingLevel, $token);
$exprStack = array(
'method' => 'PathExpression',
'expression' => $pathExpr,
'nestingLevel' => $this->_nestingLevel,
'token' => $token,
);
array_push($this->_deferredExpressionsStack, $exprStack);
return $pathExpr;
}
@ -975,7 +1127,7 @@ class Parser
}
/**
* UpdateClause ::= "UPDATE" AbstractSchemaName [["AS"] AliasIdentificationVariable] "SET" UpdateItem {"," UpdateItem}*
* UpdateClause ::= "UPDATE" AbstractSchemaName ["AS"] AliasIdentificationVariable "SET" UpdateItem {"," UpdateItem}*
*
* @return \Doctrine\ORM\Query\AST\UpdateClause
*/
@ -984,18 +1136,12 @@ class Parser
$this->match(Lexer::T_UPDATE);
$token = $this->_lexer->lookahead;
$abstractSchemaName = $this->AbstractSchemaName();
$aliasIdentificationVariable = null;
if ($this->_lexer->isNextToken(Lexer::T_AS)) {
$this->match(Lexer::T_AS);
}
if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
$token = $this->_lexer->lookahead;
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
} else {
$aliasIdentificationVariable = $abstractSchemaName;
}
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
$class = $this->_em->getClassMetadata($abstractSchemaName);
@ -1011,6 +1157,7 @@ class Parser
$this->_queryComponents[$aliasIdentificationVariable] = $queryComponent;
$this->match(Lexer::T_SET);
$updateItems = array();
$updateItems[] = $this->UpdateItem();
@ -1026,7 +1173,7 @@ class Parser
}
/**
* DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName [["AS"] AliasIdentificationVariable]
* DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName ["AS"] AliasIdentificationVariable
*
* @return \Doctrine\ORM\Query\AST\DeleteClause
*/
@ -1040,18 +1187,12 @@ class Parser
$token = $this->_lexer->lookahead;
$deleteClause = new AST\DeleteClause($this->AbstractSchemaName());
$aliasIdentificationVariable = null;
if ($this->_lexer->isNextToken(Lexer::T_AS)) {
$this->match(Lexer::T_AS);
}
if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
$token = $this->_lexer->lookahead;
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
} else {
$aliasIdentificationVariable = $deleteClause->abstractSchemaName;
}
$aliasIdentificationVariable = $this->AliasIdentificationVariable();
$deleteClause->aliasIdentificationVariable = $aliasIdentificationVariable;
$class = $this->_em->getClassMetadata($deleteClause->abstractSchemaName);
@ -1183,12 +1324,8 @@ class Parser
// Increase query nesting level
$this->_nestingLevel++;
$this->_beginDeferredPathExpressionStack();
$subselect = new AST\Subselect($this->SimpleSelectClause(), $this->SubselectFromClause());
$this->_processDeferredPathExpressionStack();
$subselect->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE)
? $this->WhereClause() : null;
@ -1216,17 +1353,14 @@ class Parser
public function UpdateItem()
{
$token = $this->_lexer->lookahead;
$identVariable = $this->IdentificationVariable();
// Validate if IdentificationVariable is defined
$queryComponent = $this->_validateIdentificationVariable($identVariable, null, $token);
$this->match(Lexer::T_DOT);
$this->match(Lexer::T_IDENTIFIER);
$field = $this->_lexer->token['value'];
// Check if field exists
$class = $queryComponent['metadata'];
$class = $this->_queryComponents[$identVariable]['metadata'];
if ( ! isset($class->associationMappings[$field]) && ! isset($class->fieldMappings[$field])) {
$this->semanticalError(
@ -1285,17 +1419,6 @@ class Parser
if ($glimpse['value'] != '.') {
$token = $this->_lexer->lookahead;
$expr = $this->ResultVariable();
// Check if ResultVariable is defined in query components
$queryComponent = $this->_validateIdentificationVariable($expr, null, $token);
// Outer defininition used in inner subselect is not enough.
// ResultVariable exists in queryComponents, check nesting level
if ($queryComponent['nestingLevel'] != $this->_nestingLevel) {
$this->semanticalError(
"'$expr' is used outside the scope of its declaration"
);
}
} else {
$expr = $this->StateFieldPathExpression();
}
@ -1564,7 +1687,7 @@ class Parser
// Include ResultVariable in query components.
$this->_queryComponents[$fieldAliasIdentificationVariable] = array(
'resultvariable' => $expression,
'resultVariable' => $expression,
'nestingLevel' => $this->_nestingLevel,
'token' => $token,
);

View File

@ -21,6 +21,8 @@
namespace Doctrine\ORM\Query;
use Doctrine\ORM\Query\AST\PathExpression;
/**
* Description of QueryException
*
@ -63,6 +65,14 @@ class QueryException extends \Doctrine\Common\DoctrineException
{
return new self("Invalid parameter: token ".$key." is not defined in the query.");
}
public static function invalidPathExpression($pathExpr)
{
return new self(
"Invalid PathExpression '" . $pathExpr->identificationVariable .
"." . implode('.', $pathExpr->parts) . "'."
);
}
/**
* @param Doctrine\ORM\Mapping\AssociationMapping $assoc

View File

@ -22,6 +22,7 @@
namespace Doctrine\ORM\Query;
use Doctrine\ORM\Query,
Doctrine\ORM\Query\QueryException,
Doctrine\Common\DoctrineException;
/**
@ -425,12 +426,35 @@ class SqlWalker implements TreeWalker
$sql .= $class->getQuotedColumnName($fieldName, $this->_platform);
break;
case AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION:
// "u.Group" should be converted to:
// 1- IdentificationVariable is the owning side:
// Just append the condition: u.group_id = ?
/*$parts = $pathExpr->parts;
$numParts = count($parts);
$dqlAlias = $pathExpr->identificationVariable;
$fieldName = $parts[$numParts - 1];
$qComp = $this->_queryComponents[$dqlAlias];
$class = $qComp['metadata'];
$assoc = $class->associationMappings[$fieldName];
if ($assoc->isOwningSide) {
foreach ($assoc->)
$sql .= $this->walkIdentificationVariable($dqlAlias, $fieldName) . '.';
}
// 2- IdentificationVariable is the inverse side:
// Join required: INNER JOIN u.Group g
// Append condition: g.id = ?
break;*/
case AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION:
throw DoctrineException::notImplemented();
default:
throw DoctrineException::invalidPathExpression($pathExpr->type);
throw QueryException::invalidPathExpression($pathExpr);
}
return $sql;

View File

@ -52,10 +52,6 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
parent::assertEquals($sqlToBeConfirmed, $query->getSql());
$query->free();
} catch (\Exception $e) {
if ($debug) {
echo $e->getTraceAsString() . PHP_EOL;
}
$this->fail($e->getMessage());
}
}

View File

@ -1,7 +1,8 @@
<?php
namespace Doctrine\Tests\ORM\Query;
use Doctrine\ORM\Query;
use Doctrine\ORM\Query,
Doctrine\ORM\Query\QueryException;
require_once __DIR__ . '/../../TestInit.php';
@ -18,7 +19,7 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
{
try {
$parserResult = $this->parseDql($dql);
} catch (\Exception $e) {
} catch (QueryException $e) {
if ($debug) {
echo $e->getTraceAsString() . PHP_EOL;
}
@ -31,8 +32,9 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
{
try {
$parserResult = $this->parseDql($dql);
$this->fail('No syntax errors were detected, when syntax errors were expected');
} catch (\Exception $e) {
} catch (QueryException $e) {
if ($debug) {
echo $e->getMessage() . PHP_EOL;
echo $e->getTraceAsString() . PHP_EOL;
@ -248,6 +250,16 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
$this->assertValidDql("SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name LIKE 'z|%' ESCAPE '|'");
}
public function testFieldComparisonWithoutAlias()
{
$this->assertInvalidDql("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE id = 1");
}
public function testDuplicatedAliasDeclaration()
{
$this->assertInvalidDql("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles u WHERE u.id = 1");
}
/*public function testImplicitJoinInWhereOnSingleValuedAssociationPathExpression()
{
// This should be allowed because avatar is a single-value association.
@ -288,7 +300,7 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
public function testDeleteAll()
{
$this->assertValidDql('DELETE FROM Doctrine\Tests\Models\CMS\CmsUser');
$this->assertValidDql('DELETE FROM Doctrine\Tests\Models\CMS\CmsUser u');
}
public function testDeleteWithCondition()

View File

@ -464,16 +464,17 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
}
/* Not yet implemented, needs more thought
/* Not yet implemented, needs more thought */
public function testSingleValuedAssociationFieldInWhere()
{
$this->assertSqlGeneration(
/*$this->assertSqlGeneration(
"SELECT p FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.user = ?1",
"SELECT c0_.phonenumber AS phonenumber0 FROM cms_phonenumbers c0_ WHERE c0_.user_id = ?"
"SELECT c0_.id AS id0, c0_user_id AS user_id1, c0_.phonenumber AS phonenumber2 FROM cms_phonenumbers c0_ WHERE c0_.user_id = ?"
);
$this->assertSqlGeneration(
"SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.address = ?1",
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.id = (SELECT c1_.user_id FROM cms_addresses c1_ WHERE c1_.id = ?)"
);
}*/
//"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE c0_.id = (SELECT c1_.user_id FROM cms_addresses c1_ WHERE c1_.id = ?)"
"SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ WHERE EXISTS (SELECT 1 FROM cms_addresses c1_ WHERE c1_.user_id = c0_.id AND c1_.id = ?)"
);*/
}
}