[2.0] Parser work.
This commit is contained in:
parent
98076e0b0d
commit
618c1281e4
@ -194,10 +194,10 @@ abstract class AbstractHydrator
|
||||
if ($this->_isIgnoredName($key)) continue;
|
||||
|
||||
// Cache general information like the column name <-> field name mapping
|
||||
$e = explode(\Doctrine\ORM\Query\ParserRule::SQLALIAS_SEPARATOR, $key);
|
||||
$e = explode(\Doctrine\ORM\Query\SqlWalker::SQLALIAS_SEPARATOR, $key);
|
||||
$columnName = array_pop($e);
|
||||
$cache[$key]['dqlAlias'] = $this->_tableAliases[
|
||||
implode(\Doctrine\ORM\Query\ParserRule::SQLALIAS_SEPARATOR, $e)
|
||||
implode(\Doctrine\ORM\Query\SqlWalker::SQLALIAS_SEPARATOR, $e)
|
||||
];
|
||||
$classMetadata = $this->_queryComponents[$cache[$key]['dqlAlias']]['metadata'];
|
||||
// check whether it's an aggregate value or a regular field
|
||||
@ -264,10 +264,10 @@ abstract class AbstractHydrator
|
||||
if ($this->_isIgnoredName($key)) continue;
|
||||
|
||||
// cache general information like the column name <-> field name mapping
|
||||
$e = explode(\Doctrine\ORM\Query\ParserRule::SQLALIAS_SEPARATOR, $key);
|
||||
$e = explode(\Doctrine\ORM\Query\SqlWalker::SQLALIAS_SEPARATOR, $key);
|
||||
$columnName = array_pop($e);
|
||||
$cache[$key]['dqlAlias'] = $this->_tableAliases[
|
||||
implode(\Doctrine\ORM\Query\ParserRule::SQLALIAS_SEPARATOR, $e)
|
||||
implode(\Doctrine\ORM\Query\SqlWalker::SQLALIAS_SEPARATOR, $e)
|
||||
];
|
||||
$classMetadata = $this->_queryComponents[$cache[$key]['dqlAlias']]['metadata'];
|
||||
// check whether it's an aggregate value or a regular field
|
||||
|
@ -19,6 +19,10 @@ class InputParameter extends Node
|
||||
|
||||
public function __construct($value)
|
||||
{
|
||||
if (strlen($value) == 1) {
|
||||
throw new \InvalidArgumentException("Invalid parameter format.");
|
||||
}
|
||||
|
||||
$param = substr($value, 1);
|
||||
$this->_isNamed = ! is_numeric($param);
|
||||
if ($this->_isNamed) {
|
||||
|
@ -62,6 +62,8 @@ abstract class AbstractResult
|
||||
*/
|
||||
protected $_enumParams;
|
||||
|
||||
protected $_defaultQueryComponentAlias;
|
||||
|
||||
/**
|
||||
* Cannot be called directly, factory methods handle this job.
|
||||
*
|
||||
@ -110,6 +112,24 @@ abstract class AbstractResult
|
||||
return $this->_queryComponents;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function getDefaultQueryComponentAlias()
|
||||
{
|
||||
return $this->_defaultQueryComponentAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param <type> $alias
|
||||
*/
|
||||
public function setDefaultQueryComponentAlias($alias)
|
||||
{
|
||||
$this->_defaultQueryComponentAlias = $alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the declaration for given component alias.
|
||||
*
|
||||
|
@ -222,7 +222,7 @@ class Lexer
|
||||
'[a-z_][a-z0-9_\\\]*',
|
||||
'(?:[0-9]+(?:[,\.][0-9]+)*)(?:e[+-]?[0-9]+)?',
|
||||
"'(?:[^']|'')*'",
|
||||
'\?[0-9]+|:[a-z][a-z0-9_]+'
|
||||
'\?[1-9]+|:[a-z][a-z0-9_]+'
|
||||
);
|
||||
$regex = '/(' . implode(')|(', $patterns) . ')|\s+|(.)/i';
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ use Doctrine\ORM\Query\Exec;
|
||||
*/
|
||||
class Parser
|
||||
{
|
||||
const SCALAR_QUERYCOMPONENT_ALIAS = 'dctrn';
|
||||
|
||||
/**
|
||||
* The minimum number of tokens read after last detected error before
|
||||
* another error can be reported.
|
||||
@ -86,12 +88,10 @@ class Parser
|
||||
$this->_em = $query->getEntityManager();
|
||||
$this->_lexer = new Lexer($query->getDql());
|
||||
|
||||
$defaultQueryComponent = ParserRule::DEFAULT_QUERYCOMPONENT;
|
||||
|
||||
$this->_parserResult = new ParserResult(
|
||||
'',
|
||||
array( // queryComponent
|
||||
$defaultQueryComponent => array(
|
||||
self::SCALAR_QUERYCOMPONENT_ALIAS => array(
|
||||
'metadata' => null,
|
||||
'parent' => null,
|
||||
'relation' => null,
|
||||
@ -100,7 +100,7 @@ class Parser
|
||||
),
|
||||
),
|
||||
array( // tableAliasMap
|
||||
$defaultQueryComponent => $defaultQueryComponent,
|
||||
self::SCALAR_QUERYCOMPONENT_ALIAS => self::SCALAR_QUERYCOMPONENT_ALIAS,
|
||||
)
|
||||
);
|
||||
|
||||
@ -215,7 +215,6 @@ class Parser
|
||||
$token = $this->_lexer->lookahead;
|
||||
}
|
||||
|
||||
// Formatting message
|
||||
$message = 'line 0, col ' . (isset($token['position']) ? $token['position'] : '-1') . ': Error: ';
|
||||
|
||||
if ($expected !== '') {
|
||||
@ -274,20 +273,6 @@ class Parser
|
||||
return $this->_em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the piece of DQL string given the token position
|
||||
*
|
||||
* @param array $token Token that it was processing.
|
||||
* @return string Piece of DQL string.
|
||||
*/
|
||||
/*public function getQueryPiece($token, $previousChars = 10, $nextChars = 10)
|
||||
{
|
||||
$start = max(0, $token['position'] - $previousChars);
|
||||
$end = max($token['position'] + $nextChars, strlen($this->_input));
|
||||
|
||||
return substr($this->_input, $start, $end);
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Checks if the next-next (after lookahead) token start a function.
|
||||
*
|
||||
@ -296,7 +281,7 @@ class Parser
|
||||
private function _isFunction()
|
||||
{
|
||||
$next = $this->_lexer->glimpse();
|
||||
return ($next['value'] === '(');
|
||||
return $next['value'] === '(';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -360,7 +345,7 @@ class Parser
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Begins a new stack of deferred path expressions.
|
||||
*/
|
||||
private function _beginDeferredPathExpressionStack()
|
||||
{
|
||||
@ -368,8 +353,8 @@ class Parser
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes pending path expressions that were encountered while parsing
|
||||
* select expressions. These will be validated to make sure they are indeed
|
||||
* Processes the topmost stack of deferred path expressions.
|
||||
* These will be validated to make sure they are indeed
|
||||
* valid <tt>StateFieldPathExpression</tt>s and additional information
|
||||
* is attached to their AST nodes.
|
||||
*/
|
||||
@ -451,6 +436,8 @@ class Parser
|
||||
if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$aliasIdentificationVariable = $this->_lexer->token['value'];
|
||||
} else {
|
||||
$aliasIdentificationVariable = $abstractSchemaName;
|
||||
}
|
||||
$this->match(Lexer::T_SET);
|
||||
$updateItems = array();
|
||||
@ -460,18 +447,17 @@ class Parser
|
||||
$updateItems[] = $this->_UpdateItem();
|
||||
}
|
||||
|
||||
if ($aliasIdentificationVariable) {
|
||||
$classMetadata = $this->_em->getClassMetadata($abstractSchemaName);
|
||||
// Building queryComponent
|
||||
$queryComponent = array(
|
||||
'metadata' => $classMetadata,
|
||||
'parent' => null,
|
||||
'relation' => null,
|
||||
'map' => null,
|
||||
'scalar' => null,
|
||||
);
|
||||
$this->_parserResult->setQueryComponent($aliasIdentificationVariable, $queryComponent);
|
||||
}
|
||||
$classMetadata = $this->_em->getClassMetadata($abstractSchemaName);
|
||||
// Building queryComponent
|
||||
$queryComponent = array(
|
||||
'metadata' => $classMetadata,
|
||||
'parent' => null,
|
||||
'relation' => null,
|
||||
'map' => null,
|
||||
'scalar' => null,
|
||||
);
|
||||
$this->_parserResult->setQueryComponent($aliasIdentificationVariable, $queryComponent);
|
||||
$this->_parserResult->setDefaultQueryComponentAlias($aliasIdentificationVariable);
|
||||
|
||||
$updateClause = new AST\UpdateClause($abstractSchemaName, $updateItems);
|
||||
$updateClause->setAliasIdentificationVariable($aliasIdentificationVariable);
|
||||
@ -490,6 +476,8 @@ class Parser
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$identVariable = $this->_lexer->token['value'];
|
||||
$this->match('.');
|
||||
} else {
|
||||
$identVariable = $this->_parserResult->getDefaultQueryComponentAlias();
|
||||
}
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$field = $this->_lexer->token['value'];
|
||||
@ -551,18 +539,22 @@ class Parser
|
||||
if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$deleteClause->setAliasIdentificationVariable($this->_lexer->token['value']);
|
||||
|
||||
$classMetadata = $this->_em->getClassMetadata($deleteClause->getAbstractSchemaName());
|
||||
// Building queryComponent
|
||||
$queryComponent = array(
|
||||
'metadata' => $classMetadata,
|
||||
'parent' => null,
|
||||
'relation' => null,
|
||||
'map' => null,
|
||||
'scalar' => null,
|
||||
);
|
||||
$this->_parserResult->setQueryComponent($this->_lexer->token['value'], $queryComponent);
|
||||
} else {
|
||||
$deleteClause->setAliasIdentificationVariable($deleteClause->getAbstractSchemaName());
|
||||
}
|
||||
|
||||
$classMetadata = $this->_em->getClassMetadata($deleteClause->getAbstractSchemaName());
|
||||
$queryComponent = array(
|
||||
'metadata' => $classMetadata,
|
||||
'parent' => null,
|
||||
'relation' => null,
|
||||
'map' => null,
|
||||
'scalar' => null,
|
||||
);
|
||||
$this->_parserResult->setQueryComponent($deleteClause->getAliasIdentificationVariable(),
|
||||
$queryComponent);
|
||||
$this->_parserResult->setDefaultQueryComponentAlias($deleteClause->getAliasIdentificationVariable());
|
||||
|
||||
return $deleteClause;
|
||||
}
|
||||
|
||||
@ -599,6 +591,9 @@ class Parser
|
||||
$this->match(Lexer::T_FROM);
|
||||
$identificationVariableDeclarations = array();
|
||||
$identificationVariableDeclarations[] = $this->_IdentificationVariableDeclaration();
|
||||
$this->_parserResult->setDefaultQueryComponentAlias(
|
||||
$identificationVariableDeclarations[0]->getRangeVariableDeclaration()->getAbstractSchemaName()
|
||||
);
|
||||
while ($this->_lexer->isNextToken(',')) {
|
||||
$this->match(',');
|
||||
$identificationVariableDeclarations[] = $this->_IdentificationVariableDeclaration();
|
||||
@ -1345,6 +1340,7 @@ class Parser
|
||||
$this->match(',');
|
||||
$literals[] = $this->_Literal();
|
||||
}
|
||||
$inExpression->setLiterals($literals);
|
||||
}
|
||||
$this->match(')');
|
||||
|
||||
|
@ -1,79 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Production variables holder
|
||||
*
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_ORM_Query_ParserDataHolder
|
||||
{
|
||||
protected static $_instance;
|
||||
protected $_data;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
$this->free();
|
||||
}
|
||||
|
||||
public static function create()
|
||||
{
|
||||
if ( ! isset(self::$_instance)) {
|
||||
self::$_instance = new self;
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
public function free()
|
||||
{
|
||||
$this->_data = array();
|
||||
}
|
||||
|
||||
public function set($offset, $value)
|
||||
{
|
||||
$this->_data[$offset] = $value;
|
||||
}
|
||||
|
||||
public function get($offset)
|
||||
{
|
||||
return isset($this->_data[$offset]) ? $this->_data[$offset] : null;
|
||||
}
|
||||
|
||||
public function has($offset)
|
||||
{
|
||||
return isset($this->_data[$offset]);
|
||||
}
|
||||
|
||||
public function remove($offset)
|
||||
{
|
||||
if ($this->has($offset)) {
|
||||
$this->_data[$offset] = null;
|
||||
unset($this->_data[$offset]);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query;
|
||||
@ -27,7 +27,7 @@ namespace Doctrine\ORM\Query;
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @link http://www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
|
@ -1,193 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query;
|
||||
|
||||
/**
|
||||
* An abstract base class for the productions of the Doctrine Query Language
|
||||
* context-free grammar.
|
||||
*
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
abstract class ParserRule
|
||||
{
|
||||
/**
|
||||
* @nodoc
|
||||
*/
|
||||
const SQLALIAS_SEPARATOR = '__';
|
||||
|
||||
/**
|
||||
* @nodoc
|
||||
*/
|
||||
const DEFAULT_QUERYCOMPONENT = 'dctrn';
|
||||
|
||||
/**
|
||||
* Parser object
|
||||
*
|
||||
* @var Doctrine_ORM_Query_Parser
|
||||
*/
|
||||
protected $_parser;
|
||||
|
||||
/**
|
||||
* The EntityManager.
|
||||
*
|
||||
* @var EntityManager
|
||||
*/
|
||||
protected $_em;
|
||||
|
||||
/**
|
||||
* The Parser Data Holder.
|
||||
*
|
||||
* @var ParserDataHolder
|
||||
*/
|
||||
protected $_dataHolder;
|
||||
|
||||
/**
|
||||
* Creates a new production object.
|
||||
*
|
||||
* @param Doctrine_ORM_Query_Parser $parser a parser object
|
||||
*/
|
||||
public function __construct(Doctrine_ORM_Query_Parser $parser)
|
||||
{
|
||||
$this->_parser = $parser;
|
||||
$this->_em = $this->_parser->getEntityManager();
|
||||
$this->_dataHolder = Doctrine_ORM_Query_ParserDataHolder::create();
|
||||
}
|
||||
|
||||
protected function _isNextToken($token)
|
||||
{
|
||||
$la = $this->_parser->lookahead;
|
||||
return ($la['type'] === $token || $la['value'] === $token);
|
||||
}
|
||||
|
||||
protected function _isFunction()
|
||||
{
|
||||
$la = $this->_parser->lookahead;
|
||||
$next = $this->_parser->getScanner()->peek();
|
||||
return ($la['type'] === Doctrine_ORM_Query_Token::T_IDENTIFIER && $next['value'] === '(');
|
||||
}
|
||||
|
||||
protected function _isSubselect()
|
||||
{
|
||||
$la = $this->_parser->lookahead;
|
||||
$next = $this->_parser->getScanner()->peek();
|
||||
return ($la['value'] === '(' && $next['type'] === Doctrine_ORM_Query_Token::T_SELECT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the grammar rule using the specified parameters.
|
||||
*
|
||||
* @param string $RuleName BNF Grammar Rule name
|
||||
* @param array $paramHolder Production parameter holder
|
||||
* @return Doctrine_ORM_Query_AST The constructed subtree during parsing.
|
||||
*/
|
||||
public function parse($ruleName)
|
||||
{
|
||||
echo $ruleName . PHP_EOL;
|
||||
return $this->_getGrammarRule($ruleName)->syntax();
|
||||
|
||||
// Syntax check
|
||||
/*if ( ! $this->_dataHolder->has('syntaxCheck') || $this->_dataHolder->get('syntaxCheck') === true) {
|
||||
//echo "Processing syntax checks of " . $RuleName . "...\n";
|
||||
$ASTNode = $BNFGrammarRule->syntax();
|
||||
if ($ASTNode !== null) {
|
||||
//echo "Returning Grammar Rule class: " . (is_object($ASTNode) ? get_class($ASTNode) : $ASTNode) . "...\n";
|
||||
return $ASTNode;
|
||||
}
|
||||
}*/
|
||||
|
||||
// Semantical check
|
||||
/*if ( ! $this->_dataHolder->has('semanticalCheck') || $this->_dataHolder->get('semanticalCheck') === true) {
|
||||
echo "Processing semantical checks of " . $RuleName . "...\n";
|
||||
|
||||
$return = $BNFGrammarRule->semantical();
|
||||
|
||||
if ($return !== null) {
|
||||
echo "Returning Grammar Rule class: " . (is_object($return) ? get_class($return) : $return) . "...\n";
|
||||
|
||||
return $return;
|
||||
}
|
||||
}*/
|
||||
|
||||
return $BNFGrammarRule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a grammar rule object with the given name.
|
||||
*
|
||||
* @param string $name grammar rule name
|
||||
* @return Doctrine_ORM_Query_ParserRule
|
||||
*/
|
||||
protected function _getGrammarRule($name)
|
||||
{
|
||||
$class = 'Doctrine_ORM_Query_Parser_' . $name;
|
||||
|
||||
//echo $class . "\r\n";
|
||||
//TODO: This expensive check is not necessary. Should be removed at the end.
|
||||
// "new $class" will throw an error anyway if the class is not found.
|
||||
if ( ! class_exists($class)) {
|
||||
throw \Doctrine\Common\DoctrineException::updateMe(
|
||||
"Unknown Grammar Rule '$name'. Could not find related compiler class."
|
||||
);
|
||||
}
|
||||
|
||||
return new $class($this->_parser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AST node with the given name.
|
||||
*
|
||||
* @param string $AstName AST node name
|
||||
* @return Doctrine_ORM_Query_AST
|
||||
*/
|
||||
public function AST($AstName)
|
||||
{
|
||||
$class = 'Doctrine_ORM_Query_AST_' . $AstName;
|
||||
return new $class($this->_parser->getParserResult());
|
||||
}
|
||||
|
||||
/**
|
||||
* @nodoc
|
||||
*/
|
||||
abstract public function syntax();
|
||||
|
||||
/**
|
||||
* @nodoc
|
||||
*/
|
||||
public function semantical()
|
||||
{
|
||||
}
|
||||
|
||||
public function getParser()
|
||||
{
|
||||
return $this->_parser;
|
||||
}
|
||||
|
||||
public function getDataHolder()
|
||||
{
|
||||
return $this->_dataHolder;
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query;
|
||||
@ -27,7 +27,7 @@ namespace Doctrine\ORM\Query;
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @link http://www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
namespace Doctrine\ORM\Query;
|
||||
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\AST;
|
||||
use Doctrine\Common\DoctrineException;
|
||||
|
||||
@ -35,6 +36,8 @@ use Doctrine\Common\DoctrineException;
|
||||
*/
|
||||
class SqlWalker
|
||||
{
|
||||
const SQLALIAS_SEPARATOR = '__';
|
||||
|
||||
private $_tableAliasCounter = 0;
|
||||
private $_parserResult;
|
||||
private $_em;
|
||||
@ -50,7 +53,7 @@ class SqlWalker
|
||||
$this->_parserResult = $parserResult;
|
||||
$sqlToDqlAliasMap = array();
|
||||
foreach ($parserResult->getQueryComponents() as $dqlAlias => $qComp) {
|
||||
if ($dqlAlias != 'dctrn') {
|
||||
if ($dqlAlias != Parser::SCALAR_QUERYCOMPONENT_ALIAS) {
|
||||
$sqlAlias = $this->generateSqlTableAlias($qComp['metadata']->getTableName());
|
||||
$sqlToDqlAliasMap[$sqlAlias] = $dqlAlias;
|
||||
}
|
||||
@ -302,7 +305,9 @@ class SqlWalker
|
||||
|
||||
public function walkUpdateStatement(AST\UpdateStatement $AST)
|
||||
{
|
||||
|
||||
$sql = $this->walkUpdateClause($AST->getUpdateClause());
|
||||
$sql .= $AST->getWhereClause() ? $this->walkWhereClause($AST->getWhereClause()) : '';
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function walkDeleteStatement(AST\DeleteStatement $AST)
|
||||
@ -323,6 +328,40 @@ class SqlWalker
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function walkUpdateClause($updateClause)
|
||||
{
|
||||
$sql = 'UPDATE ';
|
||||
$class = $this->_em->getClassMetadata($updateClause->getAbstractSchemaName());
|
||||
$sql .= $class->getTableName();
|
||||
if ($updateClause->getAliasIdentificationVariable()) {
|
||||
$sql .= ' ' . $this->_dqlToSqlAliasMap[$updateClause->getAliasIdentificationVariable()];
|
||||
}
|
||||
$sql .= ' SET ' . implode(', ', array_map(array($this, 'walkUpdateItem'),
|
||||
$updateClause->getUpdateItems()));
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function walkUpdateItem($updateItem)
|
||||
{
|
||||
$sql = '';
|
||||
$dqlAlias = $updateItem->getIdentificationVariable() ?
|
||||
$updateItem->getIdentificationVariable() :
|
||||
$this->_parserResult->getDefaultQueryComponentAlias();
|
||||
$qComp = $this->_parserResult->getQueryComponent($dqlAlias);
|
||||
|
||||
$sql .= $this->_dqlToSqlAliasMap[$dqlAlias] . '.'
|
||||
. $qComp['metadata']->getColumnName($updateItem->getField())
|
||||
. ' = ';
|
||||
|
||||
$newValue = $updateItem->getNewValue();
|
||||
if ($newValue instanceof AST\InputParameter) {
|
||||
$sql .= $newValue->isNamed() ? ':' . $newValue->getName() : '?';
|
||||
} // TODO: else if ...
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function walkWhereClause($whereClause)
|
||||
{
|
||||
$sql = ' WHERE ';
|
||||
@ -388,12 +427,21 @@ class SqlWalker
|
||||
if ($inExpr->getSubselect()) {
|
||||
$sql .= $this->walkSubselect($inExpr->getSubselect());
|
||||
} else {
|
||||
//$sql .= implode(', ', array_map(array($this, 'walkLiteral'), $inExpr->getLiterals()));
|
||||
$sql .= implode(', ', array_map(array($this, 'walkLiteral'), $inExpr->getLiterals()));
|
||||
}
|
||||
$sql .= ')';
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function walkLiteral($literal)
|
||||
{
|
||||
if ($literal instanceof AST\InputParameter) {
|
||||
return ($literal->isNamed() ? ':' . $literal->getName() : '?');
|
||||
} else {
|
||||
return $literal;
|
||||
}
|
||||
}
|
||||
|
||||
public function walkBetweenExpression($betweenExpr)
|
||||
{
|
||||
$sql = $this->walkArithmeticExpression($betweenExpr->getBaseExpression());
|
||||
@ -433,7 +481,7 @@ class SqlWalker
|
||||
$sql .= ' ' . $compExpr->getOperator() . ' ';
|
||||
if ($compExpr->getRightExpression() instanceof AST\ArithmeticExpression) {
|
||||
$sql .= $this->walkArithmeticExpression($compExpr->getRightExpression());
|
||||
}
|
||||
} // else...
|
||||
return $sql;
|
||||
}
|
||||
|
||||
|
@ -24,9 +24,7 @@ class AllTests
|
||||
$suite->addTestSuite('Doctrine\Tests\ORM\Query\LanguageRecognitionTest');
|
||||
$suite->addTestSuite('Doctrine\Tests\ORM\Query\LexerTest');
|
||||
$suite->addTestSuite('Doctrine\Tests\ORM\Query\DeleteSqlGenerationTest');
|
||||
|
||||
/*
|
||||
$suite->addTestSuite('Orm_Query_UpdateSqlGenerationTest');*/
|
||||
$suite->addTestSuite('Doctrine\Tests\ORM\Query\UpdateSqlGenerationTest');
|
||||
|
||||
return $suite;
|
||||
}
|
||||
|
@ -218,19 +218,17 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
public function testWithExprAndIn()
|
||||
{
|
||||
// "WHERE" Expression InExpression
|
||||
$this->assertSqlGeneration(
|
||||
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN ( ?, ?, ?, ? )',
|
||||
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN ( ?1, ?2, ?3, ?4 )',
|
||||
'DELETE FROM cms_users c0 WHERE c0.id IN (?, ?, ?, ?)'
|
||||
);
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN ( ?, ? )',
|
||||
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN ( ?1, ?2 )',
|
||||
'DELETE FROM cms_users c0 WHERE c0.id NOT IN (?, ?)'
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
@ -181,13 +181,12 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
||||
|
||||
public function testSubselectInSelectPart()
|
||||
{
|
||||
// Semantical error: Unknown query component u (probably in subselect)
|
||||
$this->assertValidDql("SELECT u.name, (SELECT COUNT(p.phonenumber) FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234) pcount FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = 'jon'");
|
||||
}
|
||||
|
||||
public function testPositionalInputParameter()
|
||||
{
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?');
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?1');
|
||||
}
|
||||
|
||||
public function testNamedInputParameter()
|
||||
|
@ -16,14 +16,16 @@
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Tests\ORM\Query;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
/**
|
||||
* Test case for testing the saving and referencing of query identifiers.
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
@ -35,34 +37,36 @@
|
||||
* testcases later since we'll have a lot of them and we might want to have special SQL
|
||||
* generation tests for some dbms specific SQL syntaxes.
|
||||
*/
|
||||
class Orm_Query_UpdateSqlGenerationTest extends Doctrine_OrmTestCase
|
||||
class UpdateSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
private $_em;
|
||||
|
||||
protected function setUp() {
|
||||
$this->_em = $this->_getTestEntityManager();
|
||||
}
|
||||
|
||||
public function assertSqlGeneration($dqlToBeTested, $sqlToBeConfirmed)
|
||||
{
|
||||
try {
|
||||
$entityManager = $this->_em;
|
||||
$query = $entityManager->createQuery($dqlToBeTested);
|
||||
|
||||
$query = $this->_em->createQuery($dqlToBeTested);
|
||||
parent::assertEquals($sqlToBeConfirmed, $query->getSql());
|
||||
|
||||
$query->free();
|
||||
} catch (Doctrine_Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
$this->fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function testWithoutWhere()
|
||||
{
|
||||
// NO WhereClause
|
||||
$this->assertSqlGeneration(
|
||||
'UPDATE CmsUser u SET name = ?',
|
||||
'UPDATE cms_user cu SET cu.name = ? WHERE 1 = 1'
|
||||
'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = ?1',
|
||||
'UPDATE cms_users c0 SET c0.name = ?'
|
||||
);
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
'UPDATE CmsUser u SET name = ?, username = ?',
|
||||
'UPDATE cms_user cu SET cu.name = ?, cu.username = ? WHERE 1 = 1'
|
||||
'UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = ?1, u.username = ?2',
|
||||
'UPDATE cms_users c0 SET c0.name = ?, c0.username = ?'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user