1
0
mirror of synced 2024-12-13 14:56:01 +03:00

[2.0] Parser work.

This commit is contained in:
romanb 2009-03-16 22:12:38 +00:00
parent bc379103c3
commit bffd76d704
7 changed files with 358 additions and 31 deletions

View 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;
}
}

View File

@ -44,29 +44,4 @@ class FromClause extends Node
{ {
return $this->_identificationVariableDeclarations; 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();
}
} }

View 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;
}
}

View 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;
}
}

View 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;
}
}

View File

@ -384,7 +384,8 @@ class Parser
if (count($parts) == 2) { if (count($parts) == 2) {
$expr->setIsSimpleStateFieldPathExpression(true); $expr->setIsSimpleStateFieldPathExpression(true);
if ( ! $qComps[$dqlAlias]['metadata']->hasField($parts[1])) { 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 { } else {
$embeddedClassFieldSeen = false; $embeddedClassFieldSeen = false;
@ -417,7 +418,8 @@ class Parser
} }
// Last part MUST be a simple state field // Last part MUST be a simple state field
if ( ! $qComps[$dqlAlias]['metadata']->hasField($parts[$numParts-1])) { 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()); $class = $this->_em->getClassMetadata($assoc->getTargetEntityName());
$assocSeen = true; $assocSeen = true;
} else { } else {
$this->syntaxError(); $this->semanticalError('The class ' . $class->getClassName() .
' has no field or association named ' . $part);
} }
$parts[] = $part; $parts[] = $part;
} }
@ -1129,6 +1132,118 @@ class Parser
return $inExpression; 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 * Literal ::= string | char | integer | float | boolean | InputParameter
*/ */

View File

@ -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)'); $this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN (1)');
} }
/*
public function testExistsExpressionSupportedInWherePart() 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() 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)'); $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)');