[2.0] Parser work.
This commit is contained in:
parent
bc379103c3
commit
bffd76d704
34
lib/Doctrine/ORM/Query/AST/ExistsExpression.php
Normal file
34
lib/Doctrine/ORM/Query/AST/ExistsExpression.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")"
|
||||
*
|
||||
* @author robo
|
||||
*/
|
||||
class ExistsExpression extends Node
|
||||
{
|
||||
private $_not = false;
|
||||
private $_subselect;
|
||||
|
||||
public function __construct($subselect)
|
||||
{
|
||||
$this->_subselect = $subselect;
|
||||
}
|
||||
|
||||
public function setNot($bool)
|
||||
{
|
||||
$this->_not = $bool;
|
||||
}
|
||||
|
||||
public function getNot()
|
||||
{
|
||||
return $this->_not;
|
||||
}
|
||||
}
|
||||
|
@ -44,29 +44,4 @@ class FromClause extends Node
|
||||
{
|
||||
return $this->_identificationVariableDeclarations;
|
||||
}
|
||||
|
||||
/* REMOVE ME LATER. COPIED METHODS FROM SPLIT OF PRODUCTION INTO "AST" AND "PARSER" */
|
||||
public function buildSql()
|
||||
{
|
||||
//echo "FromClause:\n";
|
||||
//for ($i = 0; $i < count($this->_identificationVariableDeclaration);$i++) {
|
||||
// echo (($this->_identificationVariableDeclaration[$i] instanceof IdentificationVariableDeclaration)
|
||||
// ? get_class($this->_identificationVariableDeclaration[$i])
|
||||
// : get_class($this->_identificationVariableDeclaration[$i])) . "\n";
|
||||
//}
|
||||
|
||||
return 'FROM ' . implode(', ', $this->_mapIdentificationVariableDeclarations());
|
||||
}
|
||||
|
||||
protected function _mapIdentificationVariableDeclarations()
|
||||
{
|
||||
return array_map(
|
||||
array(&$this, '_mapIdentificationVariableDeclaration'), $this->_identificationVariableDeclarations
|
||||
);
|
||||
}
|
||||
|
||||
protected function _mapIdentificationVariableDeclaration($value)
|
||||
{
|
||||
return $value->buildSql();
|
||||
}
|
||||
}
|
58
lib/Doctrine/ORM/Query/AST/SimpleSelectClause.php
Normal file
58
lib/Doctrine/ORM/Query/AST/SimpleSelectClause.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?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.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SimpleSelectClause ::= "SELECT" [DISTINCT"] SimpleSelectExpression
|
||||
*
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class SimpleSelectClause extends Node
|
||||
{
|
||||
private $_isDistinct = false;
|
||||
private $_simpleSelectExpression;
|
||||
|
||||
public function __construct($simpleSelectExpression)
|
||||
{
|
||||
$this->_simpleSelectExpression = $simpleSelectExpression;
|
||||
}
|
||||
|
||||
/* Getters */
|
||||
public function isDistinct()
|
||||
{
|
||||
return $this->_isDistinct;
|
||||
}
|
||||
|
||||
public function setDistinct($bool)
|
||||
{
|
||||
$this->_isDistinct = $bool;
|
||||
}
|
||||
|
||||
public function getSimpleSelectExpression()
|
||||
{
|
||||
return $this->_simpleSelectExpression;
|
||||
}
|
||||
}
|
98
lib/Doctrine/ORM/Query/AST/Subselect.php
Normal file
98
lib/Doctrine/ORM/Query/AST/Subselect.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?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.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
|
||||
*
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Subselect extends Node
|
||||
{
|
||||
private $_simpleSelectClause;
|
||||
private $_subselectFromClause;
|
||||
private $_whereClause;
|
||||
private $_groupByClause;
|
||||
private $_havingClause;
|
||||
private $_orderByClause;
|
||||
|
||||
public function __construct($simpleSelectClause, $subselectFromClause)
|
||||
{
|
||||
$this->_simpleSelectClause = $simpleSelectClause;
|
||||
$this->_subselectFromClause = $subselectFromClause;
|
||||
}
|
||||
|
||||
/* Getters */
|
||||
public function getSimpleSelectClause()
|
||||
{
|
||||
return $this->_simpleSelectClause;
|
||||
}
|
||||
|
||||
public function getSubselectFromClause()
|
||||
{
|
||||
return $this->_subselectFromClause;
|
||||
}
|
||||
|
||||
public function getWhereClause()
|
||||
{
|
||||
return $this->_whereClause;
|
||||
}
|
||||
|
||||
public function setWhereClause($whereClause)
|
||||
{
|
||||
$this->_whereClause = $whereClause;
|
||||
}
|
||||
|
||||
public function getGroupByClause()
|
||||
{
|
||||
return $this->_groupByClause;
|
||||
}
|
||||
|
||||
public function setGroupByClause($groupByClause)
|
||||
{
|
||||
$this->_groupByClause = $groupByClause;
|
||||
}
|
||||
|
||||
public function getHavingClause()
|
||||
{
|
||||
return $this->_havingClause;
|
||||
}
|
||||
|
||||
public function setHavingClause($havingClause)
|
||||
{
|
||||
$this->_havingClause = $havingClause;
|
||||
}
|
||||
|
||||
public function getOrderByClause()
|
||||
{
|
||||
return $this->_orderByClause;
|
||||
}
|
||||
|
||||
public function setOrderByClause($orderByClause)
|
||||
{
|
||||
$this->_orderByClause = $orderByClause;
|
||||
}
|
||||
}
|
47
lib/Doctrine/ORM/Query/AST/SubselectFromClause.php
Normal file
47
lib/Doctrine/ORM/Query/AST/SubselectFromClause.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?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.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}*
|
||||
*
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class SubselectFromClause extends Node
|
||||
{
|
||||
private $_identificationVariableDeclarations = array();
|
||||
|
||||
public function __construct(array $identificationVariableDeclarations)
|
||||
{
|
||||
$this->_identificationVariableDeclarations = $identificationVariableDeclarations;
|
||||
}
|
||||
|
||||
/* Getters */
|
||||
public function geSubselectIdentificationVariableDeclarations()
|
||||
{
|
||||
return $this->_identificationVariableDeclarations;
|
||||
}
|
||||
}
|
@ -384,7 +384,8 @@ class Parser
|
||||
if (count($parts) == 2) {
|
||||
$expr->setIsSimpleStateFieldPathExpression(true);
|
||||
if ( ! $qComps[$dqlAlias]['metadata']->hasField($parts[1])) {
|
||||
$this->syntaxError();
|
||||
$this->semanticalError('The class ' . $qComps[$dqlAlias]['metadata']->getClassName()
|
||||
. ' has no simple state field named ' . $parts[1]);
|
||||
}
|
||||
} else {
|
||||
$embeddedClassFieldSeen = false;
|
||||
@ -417,7 +418,8 @@ class Parser
|
||||
}
|
||||
// Last part MUST be a simple state field
|
||||
if ( ! $qComps[$dqlAlias]['metadata']->hasField($parts[$numParts-1])) {
|
||||
$this->syntaxError();
|
||||
$this->semanticalError('The class ' . $qComps[$dqlAlias]['metadata']->getClassName()
|
||||
. ' has no simple state field named ' . $parts[$numParts-1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -796,7 +798,8 @@ class Parser
|
||||
$class = $this->_em->getClassMetadata($assoc->getTargetEntityName());
|
||||
$assocSeen = true;
|
||||
} else {
|
||||
$this->syntaxError();
|
||||
$this->semanticalError('The class ' . $class->getClassName() .
|
||||
' has no field or association named ' . $part);
|
||||
}
|
||||
$parts[] = $part;
|
||||
}
|
||||
@ -1129,6 +1132,118 @@ class Parser
|
||||
return $inExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")"
|
||||
*/
|
||||
private function _ExistsExpression()
|
||||
{
|
||||
$not = false;
|
||||
if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
|
||||
$this->match(Lexer::T_NOT);
|
||||
$not = true;
|
||||
}
|
||||
$this->match(Lexer::T_EXISTS);
|
||||
$this->match('(');
|
||||
$existsExpression = new AST\ExistsExpression($this->_Subselect());
|
||||
$this->match(')');
|
||||
$existsExpression->setNot($not);
|
||||
return $existsExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
|
||||
*/
|
||||
private function _Subselect()
|
||||
{
|
||||
$subselect = new AST\Subselect($this->_SimpleSelectClause(), $this->_SubselectFromClause());
|
||||
|
||||
$subselect->setWhereClause(
|
||||
$this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->_WhereClause() : null
|
||||
);
|
||||
|
||||
$subselect->setGroupByClause(
|
||||
$this->_lexer->isNextToken(Lexer::T_GROUP) ? $this->_GroupByClause() : null
|
||||
);
|
||||
|
||||
$subselect->setHavingClause(
|
||||
$this->_lexer->isNextToken(Lexer::T_HAVING) ? $this->_HavingClause() : null
|
||||
);
|
||||
|
||||
$subselect->setOrderByClause(
|
||||
$this->_lexer->isNextToken(Lexer::T_ORDER) ? $this->_OrderByClause() : null
|
||||
);
|
||||
|
||||
return $subselect;
|
||||
}
|
||||
|
||||
/**
|
||||
* SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression
|
||||
*/
|
||||
private function _SimpleSelectClause()
|
||||
{
|
||||
$distinct = false;
|
||||
$this->match(Lexer::T_SELECT);
|
||||
if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
|
||||
$this->match(Lexer::T_DISTINCT);
|
||||
$distinct = true;
|
||||
}
|
||||
$simpleSelectClause = new AST\SimpleSelectClause($this->_SimpleSelectExpression());
|
||||
$simpleSelectClause->setDistinct($distinct);
|
||||
return $simpleSelectClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}*
|
||||
*/
|
||||
private function _SubselectFromClause()
|
||||
{
|
||||
$this->match(Lexer::T_FROM);
|
||||
$identificationVariables = array();
|
||||
$identificationVariables[] = $this->_SubselectIdentificationVariableDeclaration();
|
||||
while ($this->_lexer->isNextToken(',')) {
|
||||
$this->match(',');
|
||||
$identificationVariables[] = $this->_SubselectIdentificationVariableDeclaration();
|
||||
}
|
||||
return new AST\SubselectFromClause($identificationVariables);
|
||||
}
|
||||
|
||||
/**
|
||||
* SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | (AssociationPathExpression ["AS"] AliasIdentificationVariable)
|
||||
*/
|
||||
private function _SubselectIdentificationVariableDeclaration()
|
||||
{
|
||||
$peek = $this->_lexer->glimpse();
|
||||
if ($peek['value'] == '.') {
|
||||
$subselectIdentificationVarDecl = new AST\SubselectIdentificationVariableDeclaration;
|
||||
$subselectIdentificationVarDecl->setAssociationPathExpression($this->_AssociationPathExpression());
|
||||
$this->match(Lexer::T_AS);
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$subselectIdentificationVarDecl->setAliasIdentificationVariable($this->_lexer->token['value']);
|
||||
return $subselectIdentificationVarDecl;
|
||||
} else {
|
||||
return $this->_IdentificationVariableDeclaration();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SimpleSelectExpression ::= SingleValuedPathExpression | IdentificationVariable | AggregateExpression
|
||||
*/
|
||||
private function _SimpleSelectExpression()
|
||||
{
|
||||
if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
// SingleValuedPathExpression | IdentificationVariable
|
||||
$peek = $this->_lexer->glimpse();
|
||||
if ($peek['value'] == '.') {
|
||||
return $this->_PathExpressionInSelect();
|
||||
} else {
|
||||
$this->match($this->_lexer->lookahead['value']);
|
||||
return $this->_lexer->token['value'];
|
||||
}
|
||||
} else {
|
||||
return $this->_AggregateExpression();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Literal ::= string | char | integer | float | boolean | InputParameter
|
||||
*/
|
||||
|
@ -107,12 +107,12 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN (1)');
|
||||
}
|
||||
/*
|
||||
|
||||
public function testExistsExpressionSupportedInWherePart()
|
||||
{
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE EXISTS (SELECT p.user_id FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.user_id = u.id)');
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE EXISTS (SELECT p.id FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234)');
|
||||
}
|
||||
|
||||
/*
|
||||
public function testNotExistsExpressionSupportedInWherePart()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.* FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE NOT EXISTS (SELECT p.user_id FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.user_id = u.id)');
|
||||
|
Loading…
Reference in New Issue
Block a user