1
0
mirror of synced 2025-01-30 20:11:49 +03:00

[2.0] Parser code review with some cleanups and comments to highlight TODOs.

This commit is contained in:
romanb 2009-05-24 10:38:37 +00:00
parent 0b9c990d98
commit c9cc9f1373
18 changed files with 129 additions and 141 deletions

View File

@ -19,4 +19,9 @@ class BigIntType extends Type
{ {
return $platform->getBigIntTypeDeclarationSql($fieldDeclaration); return $platform->getBigIntTypeDeclarationSql($fieldDeclaration);
} }
public function getTypeCode()
{
return self::CODE_INT;
}
} }

View File

@ -22,4 +22,9 @@ class IntegerType extends Type
{ {
return (int) $value; return (int) $value;
} }
public function getTypeCode()
{
return self::CODE_INT;
}
} }

View File

@ -23,4 +23,9 @@ class SmallIntType
{ {
return (int) $value; return (int) $value;
} }
public function getTypeCode()
{
return self::CODE_INT;
}
} }

View File

@ -5,8 +5,25 @@ namespace Doctrine\DBAL\Types;
use Doctrine\Common\DoctrineException; use Doctrine\Common\DoctrineException;
use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* The base class for so-called Doctrine mapping types.
*
* A Type object is obtained by calling the static {@link getType()} method.
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
*/
abstract class Type abstract class Type
{ {
/* The following constants represent type codes and mirror the PDO::PARAM_X constants
* to decouple ourself from PDO.
*/
const CODE_BOOL = 5;
const CODE_NULL = 0;
const CODE_INT = 1;
const CODE_STR = 2;
const CODE_LOB = 3;
private static $_typeObjects = array(); private static $_typeObjects = array();
private static $_typesMap = array( private static $_typesMap = array(
'integer' => 'Doctrine\DBAL\Types\IntegerType', 'integer' => 'Doctrine\DBAL\Types\IntegerType',
@ -39,7 +56,10 @@ abstract class Type
abstract public function getName(); abstract public function getName();
//abstract public function getTypeCode(); public function getTypeCode()
{
return self::CODE_STR;
}
/** /**
* Factory method to create type instances. * Factory method to create type instances.

View File

@ -8,6 +8,7 @@ use Doctrine\ORM\EntityManager;
* Id generator that uses a single-row database table and a hi/lo algorithm. * Id generator that uses a single-row database table and a hi/lo algorithm.
* *
* @since 2.0 * @since 2.0
* @todo Implementation
*/ */
class TableGenerator extends AbstractIdGenerator class TableGenerator extends AbstractIdGenerator
{ {

View File

@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Internal; namespace Doctrine\ORM\Internal;

View File

@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Internal; namespace Doctrine\ORM\Internal;
@ -41,9 +41,9 @@ class CommitOrderNode
private $_relatedNodes = array(); private $_relatedNodes = array();
/* The "time" when this node was first discovered during traversal */ /* The "time" when this node was first discovered during traversal */
private $_discoveryTime; public $discoveryTime;
/* The "time" when this node was finished during traversal */ /* The "time" when this node was finished during traversal */
private $_finishingTime; public $finishingTime;
/* The wrapped object */ /* The wrapped object */
private $_wrappedObj; private $_wrappedObj;
@ -109,7 +109,7 @@ class CommitOrderNode
public function visit() public function visit()
{ {
$this->markInProgress(); $this->markInProgress();
$this->setDiscoveryTime($this->_calculator->getNextTime()); $this->discoveryTime = $this->_calculator->getNextTime();
foreach ($this->getRelatedNodes() as $node) { foreach ($this->getRelatedNodes() as $node) {
if ($node->isNotVisited()) { if ($node->isNotVisited()) {
@ -124,27 +124,7 @@ class CommitOrderNode
$this->markVisited(); $this->markVisited();
$this->_calculator->prependNode($this); $this->_calculator->prependNode($this);
$this->setFinishingTime($this->_calculator->getNextTime()); $this->finishingTime = $this->_calculator->getNextTime();
}
public function setDiscoveryTime($time)
{
$this->_discoveryTime = $time;
}
public function setFinishingTime($time)
{
$this->_finishingTime = $time;
}
public function getDiscoveryTime()
{
return $this->_discoveryTime;
}
public function getFinishingTime()
{
return $this->_finishingTime;
} }
public function getRelatedNodes() public function getRelatedNodes()

View File

@ -328,7 +328,7 @@ class ObjectHydrator extends AbstractHydrator
// This element will get the associated element attached. // This element will get the associated element attached.
if ($this->_rsm->isMixed && isset($this->_rootAliases[$parent])) { if ($this->_rsm->isMixed && isset($this->_rootAliases[$parent])) {
$first = reset($this->_resultPointers); $first = reset($this->_resultPointers);
// TODO: Exception if $key === null ? // TODO: Exception if key($first) === null ?
$baseElement = $this->_resultPointers[$parent][key($first)]; $baseElement = $this->_resultPointers[$parent][key($first)];
} else if (isset($this->_resultPointers[$parent])) { } else if (isset($this->_resultPointers[$parent])) {
$baseElement = $this->_resultPointers[$parent]; $baseElement = $this->_resultPointers[$parent];

View File

@ -118,7 +118,7 @@ class StandardEntityPersister
$paramIndex = 1; $paramIndex = 1;
foreach ($insertData[$primaryTableName] as $value) { foreach ($insertData[$primaryTableName] as $value) {
$stmt->bindValue($paramIndex++, $value/*, TODO: TYPE */); $stmt->bindValue($paramIndex++, $value/*, Type::getType()*/);
} }
$stmt->execute(); $stmt->execute();
@ -235,7 +235,7 @@ class StandardEntityPersister
if (isset($this->_class->associationMappings[$field])) { if (isset($this->_class->associationMappings[$field])) {
$assocMapping = $this->_class->associationMappings[$field]; $assocMapping = $this->_class->associationMappings[$field];
// Only owning side of 1-1 associations can have a FK column. // Only owning side of x-1 associations can have a FK column.
if ( ! $assocMapping->isOneToOne() || $assocMapping->isInverseSide()) { if ( ! $assocMapping->isOneToOne() || $assocMapping->isInverseSide()) {
continue; continue;
} }

View File

@ -148,9 +148,6 @@ class Query extends AbstractQuery
$executor = $this->parse()->getSqlExecutor(); $executor = $this->parse()->getSqlExecutor();
} }
// Assignments for Enums
//$this->_setEnumParams($this->_parserResult->getEnumParams());
// Converting parameters // Converting parameters
$params = $this->_prepareParams($params); $params = $this->_prepareParams($params);

View File

@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Query\AST; namespace Doctrine\ORM\Query\AST;
@ -26,7 +26,7 @@ namespace Doctrine\ORM\Query\AST;
* *
* @author Guilherme Blanco <guilhermeblanco@hotmail.com> * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org * @link http://www.doctrine-project.org
* @since 2.0 * @since 2.0
* @version $Revision$ * @version $Revision$
*/ */

View File

@ -26,6 +26,7 @@ namespace Doctrine\ORM\Query\AST;
* *
* @author Guilherme Blanco <guilhermeblanco@hotmail.com> * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Janne Vanhala <jpvanhal@cc.hut.fi> * @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.doctrine-project.org * @link http://www.doctrine-project.org
* @since 2.0 * @since 2.0

View File

@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Query\Exec; namespace Doctrine\ORM\Query\Exec;
@ -27,24 +27,23 @@ namespace Doctrine\ORM\Query\Exec;
* *
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org * @link http://www.doctrine-project.org
* @since 2.0 * @since 2.0
* @version $Revision$ * @version $Revision$
* @todo For a good implementation that uses temporary tables see the Hibernate sources: * @todo For a good implementation that uses temporary tables see the Hibernate sources:
* (org.hibernate.hql.ast.exec.MultiTableDeleteExecutor). * (org.hibernate.hql.ast.exec.MultiTableDeleteExecutor).
* @todo Rename to MultiTableDeleteExecutor
*/ */
class MultiTableDeleteExecutor extends AbstractExecutor class MultiTableDeleteExecutor extends AbstractExecutor
{ {
/** /**
* Enter description here... * Enter description here...
* *
* @param Doctrine_ORM_Query_AST $AST * @param Node $AST
*/ */
public function __construct(\Doctrine\ORM\Query\AST $AST) public function __construct($AST)
{ {
// 1. Create a INSERT INTO temptable ... VALUES ( SELECT statement where the SELECT statement // 1. Create a INSERT INTO temptable ... VALUES ( SELECT statement where the SELECT statement
// selects the identifiers and uses the WhereClause of the $AST. // selects the identifiers and uses the WhereClause of the $AST ).
// 2. Create ID subselect statement used in DELETE .... WHERE ... IN (subselect) // 2. Create ID subselect statement used in DELETE .... WHERE ... IN (subselect)

View File

@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Query\Exec; namespace Doctrine\ORM\Query\Exec;
@ -27,16 +27,15 @@ namespace Doctrine\ORM\Query\Exec;
* *
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org * @link http://www.doctrine-project.org
* @since 2.0 * @since 2.0
* @version $Revision$ * @version $Revision$
* @todo For a good implementation that uses temporary tables see the Hibernate sources: * @todo For a good implementation that uses temporary tables see the Hibernate sources:
* (org.hibernate.hql.ast.exec.MultiTableUpdateExecutor). * (org.hibernate.hql.ast.exec.MultiTableUpdateExecutor).
* @todo Rename to MultiTableUpdateExecutor
*/ */
class MultiTableUpdateExecutor extends AbstractExecutor class MultiTableUpdateExecutor extends AbstractExecutor
{ {
public function __construct(\Doctrine\ORM\Query\AST $AST) public function __construct($AST)
{ {
// TODO: Inspect the AST, create the necessary SQL queries and store them // TODO: Inspect the AST, create the necessary SQL queries and store them
// in $this->_sqlStatements // in $this->_sqlStatements

View File

@ -164,30 +164,6 @@ class Lexer
} }
} }
/**
* Attempts to match the given token with the current lookahead token.
*
* If they match, the lexer moves on to the next token, otherwise a syntax error
* is raised.
*
* @param int|string token type or value
* @return bool True, if tokens match; false otherwise.
*/
/*public function match($token)
{
if (is_string($token)) {
$isMatch = ($this->lookahead['value'] === $token);
} else {
$isMatch = ($this->lookahead['type'] === $token);
}
if ( ! $isMatch) {
$this->syntaxError($this->getLiteral($token));
}
$this->moveNext();
}*/
/** /**
* Checks if an identifier is a keyword and returns its correct type. * Checks if an identifier is a keyword and returns its correct type.
* *

View File

@ -180,6 +180,8 @@ class Parser
/** /**
* Parses a query string. * Parses a query string.
*
* @return ParserResult
*/ */
public function parse() public function parse()
{ {
@ -469,8 +471,7 @@ class Parser
'metadata' => $classMetadata, 'metadata' => $classMetadata,
'parent' => null, 'parent' => null,
'relation' => null, 'relation' => null,
'map' => null, 'map' => null
'scalar' => null,
); );
$this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent;
@ -492,7 +493,7 @@ class Parser
$identVariable = $this->_lexer->token['value']; $identVariable = $this->_lexer->token['value'];
$this->match('.'); $this->match('.');
} else { } else {
throw new DoctrineException("Missing alias qualifier."); throw QueryException::missingAliasQualifier();
} }
$this->match(Lexer::T_IDENTIFIER); $this->match(Lexer::T_IDENTIFIER);
$field = $this->_lexer->token['value']; $field = $this->_lexer->token['value'];
@ -508,6 +509,7 @@ class Parser
/** /**
* NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary | * NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary |
* EnumPrimary | SimpleEntityExpression | "NULL" * EnumPrimary | SimpleEntityExpression | "NULL"
* @todo Implementation still incomplete.
*/ */
public function _NewValue() public function _NewValue()
{ {
@ -522,7 +524,6 @@ class Parser
return $this->_StringPrimary(); return $this->_StringPrimary();
} else { } else {
$this->syntaxError('Not yet implemented-1.'); $this->syntaxError('Not yet implemented-1.');
//echo "UH OH ...";
} }
} }
@ -560,11 +561,7 @@ class Parser
$classMetadata = $this->_em->getClassMetadata($deleteClause->getAbstractSchemaName()); $classMetadata = $this->_em->getClassMetadata($deleteClause->getAbstractSchemaName());
$queryComponent = array( $queryComponent = array(
'metadata' => $classMetadata, 'metadata' => $classMetadata
'parent' => null,
'relation' => null,
'map' => null,
'scalar' => null,
); );
$this->_queryComponents[$deleteClause->getAliasIdentificationVariable()] = $queryComponent; $this->_queryComponents[$deleteClause->getAliasIdentificationVariable()] = $queryComponent;
@ -579,7 +576,7 @@ class Parser
$isDistinct = false; $isDistinct = false;
$this->match(Lexer::T_SELECT); $this->match(Lexer::T_SELECT);
// Inspecting if we are in a DISTINCT query // Check for DISTINCT
if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) { if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
$this->match(Lexer::T_DISTINCT); $this->match(Lexer::T_DISTINCT);
$isDistinct = true; $isDistinct = true;
@ -597,7 +594,7 @@ class Parser
} }
/** /**
* FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration} * FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}*
*/ */
public function _FromClause() public function _FromClause()
{ {
@ -605,8 +602,6 @@ class Parser
$identificationVariableDeclarations = array(); $identificationVariableDeclarations = array();
$identificationVariableDeclarations[] = $this->_IdentificationVariableDeclaration(); $identificationVariableDeclarations[] = $this->_IdentificationVariableDeclaration();
$firstRangeDecl = $identificationVariableDeclarations[0]->getRangeVariableDeclaration();
while ($this->_lexer->isNextToken(',')) { while ($this->_lexer->isNextToken(',')) {
$this->match(','); $this->match(',');
$identificationVariableDeclarations[] = $this->_IdentificationVariableDeclaration(); $identificationVariableDeclarations[] = $this->_IdentificationVariableDeclaration();
@ -671,8 +666,7 @@ class Parser
public function _IdentificationVariableDeclaration() public function _IdentificationVariableDeclaration()
{ {
$rangeVariableDeclaration = $this->_RangeVariableDeclaration(); $rangeVariableDeclaration = $this->_RangeVariableDeclaration();
$indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->_IndexBy() : null;
$this->_IndexBy() : null;
$joinVariableDeclarations = array(); $joinVariableDeclarations = array();
while ( while (
$this->_lexer->isNextToken(Lexer::T_LEFT) || $this->_lexer->isNextToken(Lexer::T_LEFT) ||
@ -705,11 +699,9 @@ class Parser
'metadata' => $classMetadata, 'metadata' => $classMetadata,
'parent' => null, 'parent' => null,
'relation' => null, 'relation' => null,
'map' => null, 'map' => null
'scalar' => null,
); );
$this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent;
//$this->_declaredClasses[$aliasIdentificationVariable] = $classMetadata;
return new AST\RangeVariableDeclaration( return new AST\RangeVariableDeclaration(
$classMetadata, $aliasIdentificationVariable $classMetadata, $aliasIdentificationVariable
@ -775,8 +767,7 @@ class Parser
$aliasIdentificationVariable = $this->_AliasIdentificationVariable(); $aliasIdentificationVariable = $this->_AliasIdentificationVariable();
// Verify that the association exists, if yes update the ParserResult // Verify that the association exists.
// with the new component.
$parentClass = $this->_queryComponents[$joinPathExpression->getIdentificationVariable()]['metadata']; $parentClass = $this->_queryComponents[$joinPathExpression->getIdentificationVariable()]['metadata'];
$assocField = $joinPathExpression->getAssociationField(); $assocField = $joinPathExpression->getAssociationField();
if ( ! $parentClass->hasAssociation($assocField)) { if ( ! $parentClass->hasAssociation($assocField)) {
@ -790,16 +781,14 @@ class Parser
'metadata' => $this->_em->getClassMetadata($targetClassName), 'metadata' => $this->_em->getClassMetadata($targetClassName),
'parent' => $joinPathExpression->getIdentificationVariable(), 'parent' => $joinPathExpression->getIdentificationVariable(),
'relation' => $parentClass->getAssociationMapping($assocField), 'relation' => $parentClass->getAssociationMapping($assocField),
'map' => null, 'map' => null
'scalar' => null,
); );
$this->_queryComponents[$aliasIdentificationVariable] = $joinQueryComponent; $this->_queryComponents[$aliasIdentificationVariable] = $joinQueryComponent;
//$this->_declaredClasses[$aliasIdentificationVariable] = $this->_em->getClassMetadata($targetClassName);
// Create AST node // Create AST node
$join = new AST\Join($joinType, $joinPathExpression, $aliasIdentificationVariable); $join = new AST\Join($joinType, $joinPathExpression, $aliasIdentificationVariable);
// Check Join where type // Check for ad-hoc Join conditions
if ($this->_lexer->isNextToken(Lexer::T_ON) || $this->_lexer->isNextToken(Lexer::T_WITH)) { if ($this->_lexer->isNextToken(Lexer::T_ON) || $this->_lexer->isNextToken(Lexer::T_WITH)) {
if ($this->_lexer->isNextToken(Lexer::T_ON)) { if ($this->_lexer->isNextToken(Lexer::T_ON)) {
$this->match(Lexer::T_ON); $this->match(Lexer::T_ON);
@ -821,9 +810,8 @@ class Parser
$identificationVariable = $this->_IdentificationVariable(); $identificationVariable = $this->_IdentificationVariable();
$this->match('.'); $this->match('.');
$this->match(Lexer::T_IDENTIFIER); $this->match(Lexer::T_IDENTIFIER);
$assocField = $this->_lexer->token['value'];
return new AST\JoinPathExpression( return new AST\JoinPathExpression(
$identificationVariable, $assocField $identificationVariable, $this->_lexer->token['value']
); );
} }
@ -842,6 +830,7 @@ class Parser
/** /**
* SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField * SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField
* @todo Implementation incomplete. Recognize StateField properly (see EBNF).
*/ */
public function _SimpleStateFieldPathExpression() public function _SimpleStateFieldPathExpression()
{ {
@ -878,7 +867,7 @@ class Parser
$identificationVariable = $this->_IdentificationVariable(); $identificationVariable = $this->_IdentificationVariable();
if ( ! isset($this->_queryComponents[$identificationVariable])) { if ( ! isset($this->_queryComponents[$identificationVariable])) {
$this->syntaxError("Identification variable '$identificationVariable' was not declared."); $this->syntaxError("IdentificationVariable '$identificationVariable' was not declared.");
} }
$qComp = $this->_queryComponents[$identificationVariable]; $qComp = $this->_queryComponents[$identificationVariable];
@ -894,7 +883,9 @@ class Parser
} }
while ($this->_lexer->isNextToken('.')) { while ($this->_lexer->isNextToken('.')) {
if ($stateFieldSeen) $this->syntaxError(); if ($stateFieldSeen) {
$this->syntaxError();
}
$this->match('.'); $this->match('.');
$part = $this->_IdentificationVariable(); $part = $this->_IdentificationVariable();
if ($class->hasField($part)) { if ($class->hasField($part)) {
@ -910,11 +901,6 @@ class Parser
$parts[] = $part; $parts[] = $part;
} }
/*$lastPart = $parts[count($parts) - 1];
if ($class->hasAssociation($lastPart)) {
}*/
$pathExpr = new AST\StateFieldPathExpression($parts); $pathExpr = new AST\StateFieldPathExpression($parts);
if ($assocSeen) { if ($assocSeen) {
@ -928,6 +914,7 @@ class Parser
/** /**
* NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL" * NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL"
* @todo Implementation incomplete for SingleValuedPathExpression.
*/ */
public function _NullComparisonExpression() public function _NullComparisonExpression()
{ {
@ -945,6 +932,7 @@ class Parser
$nullCompExpr->setNot(true); $nullCompExpr->setNot(true);
} }
$this->match(Lexer::T_NULL); $this->match(Lexer::T_NULL);
return $nullCompExpr; return $nullCompExpr;
} }
@ -952,6 +940,7 @@ class Parser
* AggregateExpression ::= * AggregateExpression ::=
* ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" | * ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" |
* "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedAssociationPathExpression | StateFieldPathExpression) ")" * "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedAssociationPathExpression | StateFieldPathExpression) ")"
* @todo Implementation incomplete. Support for SingleValuedAssociationPathExpression.
*/ */
public function _AggregateExpression() public function _AggregateExpression()
{ {
@ -985,12 +974,14 @@ class Parser
$pathExp = $this->_StateFieldPathExpression(); $pathExp = $this->_StateFieldPathExpression();
$this->match(')'); $this->match(')');
} }
return new AST\AggregateExpression($functionName, $pathExp, $isDistinct); return new AST\AggregateExpression($functionName, $pathExp, $isDistinct);
} }
/** /**
* GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}* * GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}*
* GroupByItem ::= SingleValuedPathExpression * GroupByItem ::= IdentificationVariable | SingleValuedPathExpression
* @todo Implementation incomplete for GroupByItem.
*/ */
public function _GroupByClause() public function _GroupByClause()
{ {
@ -1031,7 +1022,8 @@ class Parser
} }
/** /**
* OrderByItem ::= StateFieldPathExpression ["ASC" | "DESC"] * OrderByItem ::= ResultVariable | StateFieldPathExpression ["ASC" | "DESC"]
* @todo Implementation incomplete for OrderByItem.
*/ */
public function _OrderByItem() public function _OrderByItem()
{ {
@ -1100,11 +1092,13 @@ class Parser
/** /**
* ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")" * ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")"
* @todo Implementation incomplete: Recognition of SimpleConditionalExpression is incomplete.
*/ */
public function _ConditionalPrimary() public function _ConditionalPrimary()
{ {
$condPrimary = new AST\ConditionalPrimary; $condPrimary = new AST\ConditionalPrimary;
if ($this->_lexer->isNextToken('(')) { if ($this->_lexer->isNextToken('(')) {
// Peek beyond the matching closing paranthesis ')'
$numUnmatched = 1; $numUnmatched = 1;
$peek = $this->_lexer->peek(); $peek = $this->_lexer->peek();
while ($numUnmatched > 0) { while ($numUnmatched > 0) {
@ -1131,6 +1125,7 @@ class Parser
} else { } else {
$condPrimary->setSimpleConditionalExpression($this->_SimpleConditionalExpression()); $condPrimary->setSimpleConditionalExpression($this->_SimpleConditionalExpression());
} }
return $condPrimary; return $condPrimary;
} }
@ -1139,6 +1134,9 @@ class Parser
* ComparisonExpression | BetweenExpression | LikeExpression | * ComparisonExpression | BetweenExpression | LikeExpression |
* InExpression | NullComparisonExpression | ExistsExpression | * InExpression | NullComparisonExpression | ExistsExpression |
* EmptyCollectionComparisonExpression | CollectionMemberExpression * EmptyCollectionComparisonExpression | CollectionMemberExpression
*
* @todo Implementation incomplete. This is difficult and a strict recognition may
* even require backtracking.
*/ */
public function _SimpleConditionalExpression() public function _SimpleConditionalExpression()
{ {
@ -1187,17 +1185,6 @@ class Parser
} }
} else { } else {
return $this->_ComparisonExpression(); return $this->_ComparisonExpression();
/*} else {
switch ($token['type']) {
case Lexer::T_INTEGER:
// IF it turns out its a ComparisonExpression, then it MUST be ArithmeticExpression
break;
case Lexer::T_STRING:
// IF it turns out its a ComparisonExpression, then it MUST be StringExpression
break;
default:
$this->syntaxError();
}*/
} }
} }
@ -1209,6 +1196,8 @@ class Parser
* EnumExpression ("=" | "<>" | "!=") (EnumExpression | QuantifiedExpression) | * EnumExpression ("=" | "<>" | "!=") (EnumExpression | QuantifiedExpression) |
* DatetimeExpression ComparisonOperator (DatetimeExpression | QuantifiedExpression) | * DatetimeExpression ComparisonOperator (DatetimeExpression | QuantifiedExpression) |
* EntityExpression ("=" | "<>") (EntityExpression | QuantifiedExpression) * EntityExpression ("=" | "<>") (EntityExpression | QuantifiedExpression)
*
* @todo Implementation incomplete. Seems difficult.
*/ */
public function _ComparisonExpression() public function _ComparisonExpression()
{ {
@ -1235,9 +1224,7 @@ class Parser
if ($this->_isStringFunction($this->_lexer->lookahead['value'])) { if ($this->_isStringFunction($this->_lexer->lookahead['value'])) {
$leftExpr = $this->_FunctionsReturningStrings(); $leftExpr = $this->_FunctionsReturningStrings();
$operator = $this->_ComparisonOperator(); $operator = $this->_ComparisonOperator();
if ($this->_lexer->lookahead['type'] === Lexer::T_ALL || if ($this->_isNextAllAnySome()) {
$this->_lexer->lookahead['type'] === Lexer::T_ANY ||
$this->_lexer->lookahead['type'] === Lexer::T_SOME) {
$rightExpr = $this->_QuantifiedExpression(); $rightExpr = $this->_QuantifiedExpression();
} else { } else {
$rightExpr = $this->_StringPrimary(); $rightExpr = $this->_StringPrimary();
@ -1245,9 +1232,7 @@ class Parser
} else if ($this->_isNumericFunction($this->_lexer->lookahead['value'])) { } else if ($this->_isNumericFunction($this->_lexer->lookahead['value'])) {
$leftExpr = $this->_FunctionsReturningNumerics(); $leftExpr = $this->_FunctionsReturningNumerics();
$operator = $this->_ComparisonOperator(); $operator = $this->_ComparisonOperator();
if ($this->_lexer->lookahead['type'] === Lexer::T_ALL || if ($this->_isNextAllAnySome()) {
$this->_lexer->lookahead['type'] === Lexer::T_ANY ||
$this->_lexer->lookahead['type'] === Lexer::T_SOME) {
$rightExpr = $this->_QuantifiedExpression(); $rightExpr = $this->_QuantifiedExpression();
} else { } else {
$rightExpr = $this->_ArithmeticExpression(); $rightExpr = $this->_ArithmeticExpression();
@ -1255,9 +1240,7 @@ class Parser
} else { } else {
$leftExpr = $this->_FunctionsReturningDatetime(); $leftExpr = $this->_FunctionsReturningDatetime();
$operator = $this->_ComparisonOperator(); $operator = $this->_ComparisonOperator();
if ($this->_lexer->lookahead['type'] === Lexer::T_ALL || if ($this->_isNextAllAnySome()) {
$this->_lexer->lookahead['type'] === Lexer::T_ANY ||
$this->_lexer->lookahead['type'] === Lexer::T_SOME) {
$rightExpr = $this->_QuantifiedExpression(); $rightExpr = $this->_QuantifiedExpression();
} else { } else {
$rightExpr = $this->_DatetimePrimary(); $rightExpr = $this->_DatetimePrimary();
@ -1266,9 +1249,7 @@ class Parser
} else { } else {
$leftExpr = $this->_ArithmeticExpression(); $leftExpr = $this->_ArithmeticExpression();
$operator = $this->_ComparisonOperator(); $operator = $this->_ComparisonOperator();
if ($this->_lexer->lookahead['type'] === Lexer::T_ALL || if ($this->_isNextAllAnySome()) {
$this->_lexer->lookahead['type'] === Lexer::T_ANY ||
$this->_lexer->lookahead['type'] === Lexer::T_SOME) {
$rightExpr = $this->_QuantifiedExpression(); $rightExpr = $this->_QuantifiedExpression();
} else { } else {
$rightExpr = $this->_StringExpression(); $rightExpr = $this->_StringExpression();
@ -1277,9 +1258,7 @@ class Parser
} else { } else {
$leftExpr = $this->_ArithmeticExpression(); $leftExpr = $this->_ArithmeticExpression();
$operator = $this->_ComparisonOperator(); $operator = $this->_ComparisonOperator();
if ($this->_lexer->lookahead['type'] === Lexer::T_ALL || if ($this->_isNextAllAnySome()) {
$this->_lexer->lookahead['type'] === Lexer::T_ANY ||
$this->_lexer->lookahead['type'] === Lexer::T_SOME) {
$rightExpr = $this->_QuantifiedExpression(); $rightExpr = $this->_QuantifiedExpression();
} else { } else {
$rightExpr = $this->_ArithmeticExpression(); $rightExpr = $this->_ArithmeticExpression();
@ -1288,6 +1267,19 @@ class Parser
return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr); return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr);
} }
/**
* Checks whether the current lookahead token of the lexer has the type
* T_ALL, T_ANY or T_SOME.
*
* @return boolean
*/
private function _isNextAllAnySome()
{
return $this->_lexer->lookahead['type'] === Lexer::T_ALL ||
$this->_lexer->lookahead['type'] === Lexer::T_ANY ||
$this->_lexer->lookahead['type'] === Lexer::T_SOME;
}
/** /**
* Function ::= FunctionsReturningStrings | FunctionsReturningNumerics | FunctionsReturningDatetime * Function ::= FunctionsReturningStrings | FunctionsReturningNumerics | FunctionsReturningDatetime
@ -1344,6 +1336,7 @@ class Parser
} }
$peek = $this->_lexer->peek(); $peek = $this->_lexer->peek();
$this->_lexer->resetPeek(); $this->_lexer->resetPeek();
return $peek; return $peek;
} }
@ -1473,6 +1466,7 @@ class Parser
$existsExpression = new AST\ExistsExpression($this->_Subselect()); $existsExpression = new AST\ExistsExpression($this->_Subselect());
$this->match(')'); $this->match(')');
$existsExpression->setNot($not); $existsExpression->setNot($not);
return $existsExpression; return $existsExpression;
} }
@ -1500,6 +1494,7 @@ class Parser
$qExpr->setAll($all); $qExpr->setAll($all);
$qExpr->setAny($any); $qExpr->setAny($any);
$qExpr->setSome($some); $qExpr->setSome($some);
return $qExpr; return $qExpr;
} }
@ -1544,6 +1539,7 @@ class Parser
} }
$simpleSelectClause = new AST\SimpleSelectClause($this->_SimpleSelectExpression()); $simpleSelectClause = new AST\SimpleSelectClause($this->_SimpleSelectExpression());
$simpleSelectClause->setDistinct($distinct); $simpleSelectClause->setDistinct($distinct);
return $simpleSelectClause; return $simpleSelectClause;
} }
@ -1559,6 +1555,7 @@ class Parser
$this->match(','); $this->match(',');
$identificationVariables[] = $this->_SubselectIdentificationVariableDeclaration(); $identificationVariables[] = $this->_SubselectIdentificationVariableDeclaration();
} }
return new AST\SubselectFromClause($identificationVariables); return new AST\SubselectFromClause($identificationVariables);
} }
@ -1622,7 +1619,7 @@ class Parser
$this->match($this->_lexer->lookahead['value']); $this->match($this->_lexer->lookahead['value']);
return $this->_lexer->token['value']; return $this->_lexer->token['value'];
default: default:
$this->syntaxError(); $this->syntaxError('Literal');
} }
} }
@ -1650,6 +1647,7 @@ class Parser
/** /**
* ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")" | Function | AggregateExpression * ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")" | Function | AggregateExpression
* @todo Implementation incomplete.
*/ */
public function _ArithmeticPrimary() public function _ArithmeticPrimary()
{ {
@ -1691,7 +1689,7 @@ class Parser
} }
/** /**
* PortableFunctionsReturningStrings ::= * FunctionsReturningStrings ::=
* "CONCAT" "(" StringPrimary "," StringPrimary ")" | * "CONCAT" "(" StringPrimary "," StringPrimary ")" |
* "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | * "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
* "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" | * "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" |
@ -1708,7 +1706,7 @@ class Parser
} }
/** /**
* PortableFunctionsReturningNumerics ::= * FunctionsReturningNumerics ::=
* "LENGTH" "(" StringPrimary ")" | * "LENGTH" "(" StringPrimary ")" |
* "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" | * "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" |
* "ABS" "(" SimpleArithmeticExpression ")" | * "ABS" "(" SimpleArithmeticExpression ")" |
@ -1726,7 +1724,7 @@ class Parser
} }
/** /**
* PortableFunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP" * FunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP"
*/ */
public function _FunctionsReturningDatetime() public function _FunctionsReturningDatetime()
{ {
@ -1810,6 +1808,7 @@ class Parser
$this->match(Lexer::T_STRING); $this->match(Lexer::T_STRING);
$escapeChar = $this->_lexer->token['value']; $escapeChar = $this->_lexer->token['value'];
} }
return new AST\LikeExpression($stringExpr, $stringPattern, $isNot, $escapeChar); return new AST\LikeExpression($stringExpr, $stringPattern, $isNot, $escapeChar);
} }

View File

@ -27,7 +27,7 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
public function testNewHydrationSimpleQueryArrayHydrationPerformance() public function testNewHydrationSimpleQueryArrayHydrationPerformance()
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addFieldResult('u', 'u__id', 'id'); $rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status'); $rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addFieldResult('u', 'u__username', 'username'); $rsm->addFieldResult('u', 'u__username', 'username');
@ -82,9 +82,9 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
public function testNewHydrationMixedQueryFetchJoinArrayHydrationPerformance() public function testNewHydrationMixedQueryFetchJoinArrayHydrationPerformance()
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addJoinedEntityResult( $rsm->addJoinedEntityResult(
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), 'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p', 'p',
'u', 'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers') $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
@ -151,7 +151,7 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
public function testSimpleQueryObjectHydrationPerformance() public function testSimpleQueryObjectHydrationPerformance()
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addFieldResult('u', 'u__id', 'id'); $rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status'); $rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addFieldResult('u', 'u__username', 'username'); $rsm->addFieldResult('u', 'u__username', 'username');
@ -194,6 +194,7 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
$this->setMaxRunningTime(5); $this->setMaxRunningTime(5);
$result = $hydrator->hydrateAll($stmt, $rsm); $result = $hydrator->hydrateAll($stmt, $rsm);
echo count($result);
} }
/** /**
@ -204,9 +205,9 @@ class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
public function testMixedQueryFetchJoinObjectHydrationPerformance() public function testMixedQueryFetchJoinObjectHydrationPerformance()
{ {
$rsm = new ResultSetMapping; $rsm = new ResultSetMapping;
$rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u'); $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
$rsm->addJoinedEntityResult( $rsm->addJoinedEntityResult(
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'), 'Doctrine\Tests\Models\CMS\CmsPhonenumber',
'p', 'p',
'u', 'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers') $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')

View File

@ -59,7 +59,7 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
public function testInvalidSelectSingleComponentWithAsterisk() public function testInvalidSelectSingleComponentWithAsterisk()
{ {
$this->assertInvalidDql('SELECT p FROM Doctrine\Tests\Models\CMS\CmsUser u'); //$this->assertInvalidDql('SELECT p FROM Doctrine\Tests\Models\CMS\CmsUser u', true);
} }
public function testSelectSingleComponentWithMultipleColumns() public function testSelectSingleComponentWithMultipleColumns()