1
0
mirror of synced 2024-12-12 22:36:02 +03:00

Fixes in unit tests.

Started refactoring in DQL parser to separate Production into Parser and AST classes.
Finished first tests. Currently only 4 are active in IdentifierRecognitionTest, and only 2 are passing.
This commit is contained in:
guilhermeblanco 2008-09-12 06:09:16 +00:00
parent 4b191a3141
commit ad4db34a87
51 changed files with 3089 additions and 849 deletions

View File

@ -104,7 +104,7 @@ class Doctrine_ConnectionFactory
// driver
if ( isset($params['driver']) && ! isset($this->_drivers[$params['driver']])) {
throw Doctrine_ConnectionFactory_Exception::unknownDriver($driverName);
throw Doctrine_ConnectionFactory_Exception::unknownDriver($params['driver']);
}
}
}

View File

@ -0,0 +1,49 @@
<?php
/*
* $Id: Exception.php 1080 2007-02-10 18:17:08Z romanb $
*
* 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>.
*/
/**
* Doctrine_ConnectionFactory_Exception
*
* @package Doctrine
* @subpackage Hydrate
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision: 1080 $
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
*/
class Doctrine_ConnectionFactory_Exception extends Doctrine_Exception
{
public static function invalidPDOInstance()
{
return new self("Invalid PDO instance provided on connection creation.");
}
public static function driverRequired()
{
return new self("Please provide a driver or a driverClass to be able to start a Connection.");
}
public static function unknownDriver($driver)
{
return new self("Unknown Connection driver '$driver'.");
}
}

View File

@ -944,7 +944,7 @@ abstract class Doctrine_DatabasePlatform
*
* @todo Throw exception by default?
*/
public function getDropIndexSql($index)
public function getDropIndexSql($index, $name)
{
return 'DROP INDEX ' . $index;
}
@ -982,7 +982,7 @@ abstract class Doctrine_DatabasePlatform
*
* @todo Throw exception by default?
*/
public function getCreateTableSql($table, array $columns, array $options)
public function getCreateTableSql($table, array $columns, array $options = array())
{
if ( ! $table) {
throw new Doctrine_Export_Exception('no valid table name specified');

View File

@ -347,10 +347,10 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
if ($this->_isIgnoredName($key)) continue;
// Cache general information like the column name <-> field name mapping
$e = explode(Doctrine_Query_Production::SQLALIAS_SEPARATOR, $key);
$e = explode(Doctrine_Query_ParserRule::SQLALIAS_SEPARATOR, $key);
$columnName = array_pop($e);
$cache[$key]['dqlAlias'] = $this->_tableAliases[
implode(Doctrine_Query_Production::SQLALIAS_SEPARATOR, $e)
implode(Doctrine_Query_ParserRule::SQLALIAS_SEPARATOR, $e)
];
$classMetadata = $this->_queryComponents[$cache[$key]['dqlAlias']]['metadata'];
// check whether it's an aggregate value or a regular field
@ -432,10 +432,10 @@ class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
if ($this->_isIgnoredName($key)) continue;
// cache general information like the column name <-> field name mapping
$e = explode(Doctrine_Query_Production::SQLALIAS_SEPARATOR, $key);
$e = explode(Doctrine_Query_ParserRule::SQLALIAS_SEPARATOR, $key);
$columnName = array_pop($e);
$cache[$key]['dqlAlias'] = $this->_tableAliases[
implode(Doctrine_Query_Production::SQLALIAS_SEPARATOR, $e)
implode(Doctrine_Query_ParserRule::SQLALIAS_SEPARATOR, $e)
];
$classMetadata = $this->_queryComponents[$cache[$key]['dqlAlias']]['metadata'];
// check whether it's an aggregate value or a regular field

View File

@ -0,0 +1,43 @@
<?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>.
*/
/**
* Abstract class of an AST node
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
abstract class Doctrine_Query_AST
{
protected $_parserResult = null;
public function __construct(Doctrine_Query_ParserResult $parserResult)
{
$this->_parserResult = $parserResult;
}
}

View File

@ -0,0 +1,50 @@
<?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>.
*/
/**
* AbstractSchemaName ::= identifier
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_AST_AbstractSchemaName extends Doctrine_Query_AST
{
protected $_componentName;
/* Setters */
public function setComponentName($componentName)
{
$this->_componentName = $componentName;
}
/* Getters */
public function getComponentName()
{
return $this->_componentName;
}
}

View File

@ -0,0 +1,50 @@
<?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>.
*/
/**
* AliasIdentificationVariable ::= identifier
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_AST_AliasIdentificationVariable extends Doctrine_Query_AST
{
protected $_componentAlias;
/* Setters */
public function setComponentAlias($componentAlias)
{
$this->_componentAlias = $componentAlias;
}
/* Getters */
public function getComponentAlias()
{
return $this->_componentAlias;
}
}

View File

@ -0,0 +1,75 @@
<?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>.
*/
/**
* DeleteStatement = DeleteClause [WhereClause]
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_AST_DeleteStatement extends Doctrine_Query_AST
{
protected $_deleteClause;
protected $_whereClause;
/* Setters */
public function setDeleteClause($deleteClause)
{
$this->_deleteClause = $deleteClause;
}
public function setWhereClause($whereClause)
{
$this->_whereClause = $whereClause;
}
/* Getters */
public function getDeleteClause()
{
return $this->_deleteClause;
}
public function getWhereClause()
{
return $this->_whereClause;
}
/* REMOVE ME LATER. COPIED METHODS FROM SPLIT OF PRODUCTION INTO "AST" AND "PARSER" */
public function buildSql()
{
// The 1=1 is needed to workaround the affected_rows in MySQL.
// Simple "DELETE FROM table_name" gives 0 affected rows.
return $this->_deleteClause->buildSql() . (($this->_whereClause !== null)
? ' ' . $this->_whereClause->buildSql() : ' WHERE 1 = 1');
}
}

View File

@ -0,0 +1,50 @@
<?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>.
*/
/**
* FieldIdentificationVariable ::= identifier
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_AST_FieldIdentificationVariable extends Doctrine_Query_AST
{
protected $_fieldName;
/* Setters */
public function setFieldName($fieldName)
{
$this->_fieldName = $fieldName;
}
/* Getters */
public function getFieldName()
{
return $this->_fieldName;
}
}

View File

@ -0,0 +1,87 @@
<?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>.
*/
/**
* FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_AST_FromClause extends Doctrine_Query_AST
{
protected $_identificationVariableDeclarations = array();
/* Setters */
public function addIdentificationVariableDeclaration($identificationVariableDeclaration)
{
$this->_identificationVariableDeclarations[] = $identificationVariableDeclaration;
}
public function setIdentificationVariableDeclarations($identificationVariableDeclarations, $append = false)
{
$this->_selectExpressions = ($append === true)
? array_merge($this->_identificationVariableDeclarations, $identificationVariableDeclarations)
: $identificationVariableDeclarations;
}
/* Getters */
public function getIdentificationVariableDeclarations()
{
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,62 @@
<?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>.
*/
/**
* IdentificationVariable ::= identifier
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_AST_IdentificationVariable extends Doctrine_Query_AST
{
protected $_componentAlias;
/* Setters */
public function setComponentAlias($componentAlias)
{
$this->_componentAlias = $componentAlias;
}
/* Getters */
public function getComponentAlias()
{
return $this->_componentAlias;
}
/* REMOVE ME LATER. COPIED METHODS FROM SPLIT OF PRODUCTION INTO "AST" AND "PARSER" */
public function buildSql()
{
$conn = $this->_parserResult->getEntityManager()->getConnection();
return $conn->quoteIdentifier(
$this->_parserResult->getTableAliasFromComponentAlias($this->_componentAlias)
);
}
}

View File

@ -0,0 +1,100 @@
<?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>.
*/
/**
* IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_AST_IdentificationVariableDeclaration extends Doctrine_Query_AST
{
protected $_rangeVariableDeclaration = null;
protected $_indexBy = null;
protected $_joinVariableDeclarations = array();
/* Setters */
public function setRangeVariableDeclaration($rangeVariableDeclaration)
{
$this->_rangeVariableDeclaration = $rangeVariableDeclaration;
}
public function setIndexBy($indexBy)
{
$this->_indexBy = $indexBy;
}
public function addJoinVariableDeclaration($joinVariableDeclaration)
{
$this->_joinVariableDeclarations[] = $joinVariableDeclaration;
}
public function setJoinVariableDeclarations($joinVariableDeclarations, $append = false)
{
$this->_joinVariableDeclarations = ($append === true)
? array_merge($this->_joinVariableDeclarations, $joinVariableDeclarations)
: $joinVariableDeclarations;
}
/* Getters */
public function getRangeVariableDeclaration()
{
return $this->_rangeVariableDeclaration;
}
public function getIndexBy()
{
return $this->_indexBy;
}
public function getJoinVariableDeclarations()
{
return $this->_joinVariableDeclarations;
}
/* REMOVE ME LATER. COPIED METHODS FROM SPLIT OF PRODUCTION INTO "AST" AND "PARSER" */
public function buildSql()
{
$str = $this->_rangeVariableDeclaration->buildSql();
for ($i = 0, $l = count($this->_joinVariableDeclarations); $i < $l; $i++) {
$str .= ' ' . $this->_joinVariableDeclarations[$i]->buildSql();
}
return $str;
}
}

View File

@ -0,0 +1,50 @@
<?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>.
*/
/**
* IndexBy ::= "INDEX" "BY" SimpleStateFieldPathExpression
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_AST_IndexBy extends Doctrine_Query_AST
{
protected $_simpleStateFieldPathExpression = null;
/* Setters */
public function setSimpleStateFieldPathExpression($simpleStateFieldPathExpression)
{
$this->_simpleStateFieldPathExpression = $simpleStateFieldPathExpression;
}
/* Getters */
public function getSimpleStateFieldPathExpression()
{
return $this->_simpleStateFieldPathExpression;
}
}

View File

@ -0,0 +1,89 @@
<?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>.
*/
/**
* RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_AST_RangeVariableDeclaration extends Doctrine_Query_AST
{
protected $_abstractSchemaName = null;
protected $_aliasIdentificationVariable = null;
/* Setters */
public function setAbstractSchemaName($abstractSchemaName)
{
$this->_abstractSchemaName = $abstractSchemaName;
}
public function setAliasIdentificationVariable($aliasIdentificationVariable)
{
$this->_aliasIdentificationVariable = $aliasIdentificationVariable;
}
/* Getters */
public function getAbstractSchemaName()
{
return $this->_abstractSchemaName;
}
public function getAliasIdentificationVariable()
{
return $this->_aliasIdentificationVariable;
}
/* REMOVE ME LATER. COPIED METHODS FROM SPLIT OF PRODUCTION INTO "AST" AND "PARSER" */
public function buildSql()
{
// Retrieving connection
$conn = $this->_parserResult->getEntityManager()->getConnection();
// Component alias
$componentAlias = $this->_aliasIdentificationVariable->getComponentAlias();
// Retrieving required information
try {
$queryComponent = $this->_parserResult->getQueryComponent($componentAlias);
$classMetadata = $queryComponent['metadata'];
} catch (Doctrine_Exception $e) {
$this->_parser->semanticalError($e->getMessage());
return;
}
return $conn->quoteIdentifier($classMetadata->getTableName()) . ' '
. $conn->quoteIdentifier($this->_parserResult->getTableAliasFromComponentAlias($componentAlias));
}
}

View File

@ -0,0 +1,93 @@
<?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>.
*/
/**
* SelectClause = "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression}
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_AST_SelectClause extends Doctrine_Query_AST
{
protected $_isDistinct;
protected $_selectExpressions = array();
/* Setters */
public function setIsDistinct($value)
{
$this->_isDistinct = $value;
}
public function addSelectExpression($expression)
{
$this->_selectExpressions[] = $expression;
}
public function setSelectExpressions($expressions, $append = false)
{
$this->_selectExpressions = ($append === true)
? array_merge($this->_selectExpressions, $expressions)
: $expressions;
}
/* Getters */
public function isDistinct()
{
return $this->_isDistinct;
}
public function getSelectExpressions()
{
return $this->_selectExpressions;
}
/* REMOVE ME LATER. COPIED METHODS FROM SPLIT OF PRODUCTION INTO "AST" AND "PARSER" */
public function buildSql()
{
return 'SELECT ' . (($this->_isDistinct) ? 'DISTINCT ' : '')
. implode(', ', $this->_mapSelectExpressions());
}
protected function _mapSelectExpressions()
{
return array_map(array(&$this, '_mapSelectExpression'), $this->_selectExpressions);
}
protected function _mapSelectExpression($value)
{
return $value->buildSql();
}
}

View File

@ -0,0 +1,132 @@
<?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>.
*/
/**
* SelectStatement = SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_AST_SelectStatement extends Doctrine_Query_AST
{
protected $_selectClause;
protected $_fromClause;
protected $_whereClause;
protected $_groupByClause;
protected $_havingClause;
protected $_orderByClause;
/* Setters */
public function setSelectClause($selectClause)
{
$this->_selectClause = $selectClause;
}
public function setFromClause($fromClause)
{
$this->_fromClause = $fromClause;
}
public function setWhereClause($whereClause)
{
$this->_whereClause = $whereClause;
}
public function setGroupByClause($groupByClause)
{
$this->_groupByClause = $groupByClause;
}
public function setHavingClause($havingClause)
{
$this->_havingClause = $havingClause;
}
public function setOrderByClause($orderByClause)
{
$this->_orderByClause = $orderByClause;
}
/* Getters */
public function getSelectClause()
{
return $this->_selectClause;
}
public function getFromClause()
{
return $this->_fromClause;
}
public function getWhereClause()
{
return $this->_whereClause;
}
public function getGroupByClause()
{
return $this->_groupByClause;
}
public function getHavingClause()
{
return $this->_havingClause;
}
public function getOrderByClause()
{
return $this->_orderByClause;
}
/* REMOVE ME LATER. COPIED METHODS FROM SPLIT OF PRODUCTION INTO "AST" AND "PARSER" */
public function buildSql()
{
return $this->_selectClause->buildSql() . ' ' . $this->_fromClause->buildSql()
. (($this->_whereClause !== null) ? ' ' . $this->_whereClause->buildSql() : ' WHERE 1 = 1')
. (($this->_groupByClause !== null) ? ' ' . $this->_groupByClause->buildSql() : '')
. (($this->_havingClause !== null) ? ' ' . $this->_havingClause->buildSql() : '')
. (($this->_orderByClause !== null) ? ' ' . $this->_orderByClause->buildSql() : '');
}
}

View File

@ -0,0 +1,64 @@
<?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>.
*/
/**
* SimpleStateFieldPathExpression ::= IdentificationVariable "." SimpleStateField
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_AST_SimpleStateFieldPathExpression extends Doctrine_Query_AST
{
protected $_identificationVariable = null;
protected $_simpleStateField = null;
/* Setters */
public function setIdentificationVariable($identificationVariable)
{
$this->_identificationVariable = $identificationVariable;
}
public function setSimpleStateField($simpleStateField)
{
$this->_simpleStateField = $simpleStateField;
}
/* Getters */
public function getIdentificationVariable()
{
return $this->_identificationVariable;
}
public function getSimpleStateField()
{
return $this->_simpleStateField;
}
}

View File

@ -0,0 +1,75 @@
<?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>.
*/
/**
* UpdateStatement = UpdateClause [WhereClause]
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_AST_UpdateStatement extends Doctrine_Query_AST
{
protected $_updateClause;
protected $_whereClause;
/* Setters */
public function setUpdateClause($updateClause)
{
$this->_updateClause = $updateClause;
}
public function setWhereClause($whereClause)
{
$this->_whereClause = $whereClause;
}
/* Getters */
public function getUpdateClause()
{
return $this->_updateClause;
}
public function getWhereClause()
{
return $this->_whereClause;
}
/* REMOVE ME LATER. COPIED METHODS FROM SPLIT OF PRODUCTION INTO "AST" AND "PARSER" */
public function buildSql()
{
// The 1=1 is needed to workaround the affected_rows in MySQL.
// Simple "UPDATE table_name SET column_name = value" gives 0 affected rows.
return $this->_updateClause->buildSql() . (($this->_whereClause !== null)
? ' ' . $this->_whereClause->buildSql() : ' WHERE 1 = 1');
}
}

View File

@ -1,355 +1,380 @@
<?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>.
*/
/**
* An LL(k) parser for the context-free grammar of Doctrine Query Language.
* Parses a DQL query, reports any errors in it, and generates the corresponding
* SQL.
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser
{
/**
* The minimum number of tokens read after last detected error before
* another error can be reported.
*
* @var int
*/
const MIN_ERROR_DISTANCE = 2;
/**
* The Sql Builder object.
*
* @var Doctrine_Query_SqlBuilder
*/
protected $_sqlbuilder;
/**
* A scanner object.
*
* @var Doctrine_Query_Scanner
*/
protected $_scanner;
/**
* The Parser Result object.
*
* @var Doctrine_Query_ParserResult
*/
protected $_parserResult;
/**
* Keyword symbol table
*
* @var Doctrine_Query_Token
*/
protected $_keywordTable;
// Scanner Stuff
/**
* @var array The next token in the query string.
*/
public $lookahead;
/**
* @var array The last matched token.
*/
public $token;
// End of Scanner Stuff
// Error management stuff
/**
* Array containing errors detected in the query string during parsing process.
*
* @var array
*/
protected $_errors;
/**
* @var int The number of tokens read since last error in the input string.
*/
protected $_errorDistance;
/**
* The EntityManager.
*
* @var EnityManager
*/
protected $_em;
// End of Error management stuff
/**
* Creates a new query parser object.
*
* @param string $dql DQL to be parsed.
* @param Doctrine_Connection $connection The connection to use
*/
public function __construct(Doctrine_Query $query)
{
$this->_em = $query->getEntityManager();
$this->_scanner = new Doctrine_Query_Scanner($query->getDql());
$this->_sqlBuilder = Doctrine_Query_SqlBuilder::fromConnection($this->_em);
$this->_keywordTable = new Doctrine_Query_Token();
$this->_parserResult = new Doctrine_Query_ParserResult(
'',
array( // queryComponent
'dctrn' => array(
'metadata' => null,
'parent' => null,
'relation' => null,
'map' => null,
'scalar' => null,
),
),
array( // tableAliasMap
'dctrn' => 'dctrn',
)
);
$this->free(true);
}
/**
* Attempts to match the given token with the current lookahead token.
*
* If they match, updates the lookahead token; otherwise raises a syntax
* error.
*
* @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) {
// No definition for value checking.
$this->syntaxError($this->_keywordTable->getLiteral($token));
}
$this->next();
return true;
}
/**
* Moves the parser scanner to next token
*
* @return void
*/
public function next()
{
$this->token = $this->lookahead;
$this->lookahead = $this->_scanner->next();
$this->_errorDistance++;
}
public function isA($value, $token)
{
return $this->_scanner->isA($value, $token);
}
/**
* Free this parser enabling it to be reused
*
* @param boolean $deep Whether to clean peek and reset errors
* @param integer $position Position to reset
* @return void
*/
public function free($deep = false, $position = 0)
{
// WARNING! Use this method with care. It resets the scanner!
$this->_scanner->resetPosition($position);
// Deep = true cleans peek and also any previously defined errors
if ($deep) {
$this->_scanner->resetPeek();
$this->_errors = array();
}
$this->token = null;
$this->lookahead = null;
$this->_errorDistance = self::MIN_ERROR_DISTANCE;
}
/**
* Parses a query string.
*/
public function parse()
{
$this->lookahead = $this->_scanner->next();
// Building the Abstract Syntax Tree
// We have to double the call of QueryLanguage to allow it to work correctly... =\
$AST = new Doctrine_Query_Production_QueryLanguage($this);
$AST = $AST->AST('QueryLanguage', Doctrine_Query_ProductionParamHolder::create());
// Check for end of string
if ($this->lookahead !== null) {
$this->syntaxError('end of string');
}
// Check for semantical errors
if (count($this->_errors) > 0) {
throw new Doctrine_Query_Parser_Exception(implode("\r\n", $this->_errors));
}
// Assign the executor in parser result
$this->_parserResult->setSqlExecutor(Doctrine_Query_SqlExecutor_Abstract::create($AST));
return $this->_parserResult;
}
/**
* Retrieves the assocated Doctrine_Query_SqlBuilder to this object.
*
* @return Doctrine_Query_SqlBuilder
*/
public function getSqlBuilder()
{
return $this->_sqlBuilder;
}
/**
* Returns the scanner object associated with this object.
*
* @return Doctrine_Query_Scanner
*/
public function getScanner()
{
return $this->_scanner;
}
/**
* Returns the parser result associated with this object.
*
* @return Doctrine_Query_ParserResult
*/
public function getParserResult()
{
return $this->_parserResult;
}
/**
* Generates a new syntax error.
*
* @param string $expected Optional expected string.
* @param array $token Optional token.
*/
public function syntaxError($expected = '', $token = null)
{
if ($token === null) {
$token = $this->lookahead;
}
// Formatting message
$message = 'line 0, col ' . (isset($token['position']) ? $token['position'] : '-1') . ': Error: ';
if ($expected !== '') {
$message .= "Expected '$expected', got ";
} else {
$message .= 'Unexpected ';
}
if ($this->lookahead === null) {
$message .= 'end of string.';
} else {
$message .= "'{$this->lookahead['value']}'";
}
throw new Doctrine_Query_Parser_Exception($message);
}
/**
* Generates a new semantical error.
*
* @param string $message Optional message.
* @param array $token Optional token.
*/
public function semanticalError($message = '', $token = null)
{
$this->_semanticalErrorCount++;
if ($token === null) {
$token = $this->token;
}
$this->_logError('Warning: ' . $message, $token);
}
/**
* Logs new error entry.
*
* @param string $message Message to log.
* @param array $token Token that it was processing.
*/
protected function _logError($message = '', $token)
{
if ($this->_errorDistance >= self::MIN_ERROR_DISTANCE) {
$message = 'line 0, col ' . $token['position'] . ': ' . $message;
$this->_errors[] = $message;
}
$this->_errorDistance = 0;
}
/**
* Gets the EntityManager used by the parser.
*
* @return EntityManager
*/
public function getEntityManager()
{
return $this->_em;
}
}
<?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>.
*/
/**
* An LL(k) parser for the context-free grammar of Doctrine Query Language.
* Parses a DQL query, reports any errors in it, and generates the corresponding
* SQL.
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser
{
/**
* The minimum number of tokens read after last detected error before
* another error can be reported.
*
* @var int
*/
const MIN_ERROR_DISTANCE = 2;
/**
* The Sql Builder object.
*
* @var Doctrine_Query_SqlBuilder
*/
protected $_sqlbuilder;
/**
* DQL string.
*
* @var string
*/
protected $_input;
/**
* A scanner object.
*
* @var Doctrine_Query_Scanner
*/
protected $_scanner;
/**
* The Parser Result object.
*
* @var Doctrine_Query_ParserResult
*/
protected $_parserResult;
/**
* Keyword symbol table
*
* @var Doctrine_Query_Token
*/
protected $_keywordTable;
// Scanner Stuff
/**
* @var array The next token in the query string.
*/
public $lookahead;
/**
* @var array The last matched token.
*/
public $token;
// End of Scanner Stuff
// Error management stuff
/**
* Array containing errors detected in the query string during parsing process.
*
* @var array
*/
protected $_errors;
/**
* @var int The number of tokens read since last error in the input string.
*/
protected $_errorDistance;
/**
* The EntityManager.
*
* @var EnityManager
*/
protected $_em;
// End of Error management stuff
/**
* Creates a new query parser object.
*
* @param string $dql DQL to be parsed.
* @param Doctrine_Connection $connection The connection to use
*/
public function __construct(Doctrine_Query $query)
{
$this->_em = $query->getEntityManager();
$this->_input = $query->getDql();
$this->_scanner = new Doctrine_Query_Scanner($this->_input);
$this->_sqlBuilder = Doctrine_Query_SqlBuilder::fromConnection($this->_em);
$this->_keywordTable = new Doctrine_Query_Token();
$this->_parserResult = new Doctrine_Query_ParserResult(
'',
array( // queryComponent
'dctrn' => array(
'metadata' => null,
'parent' => null,
'relation' => null,
'map' => null,
'scalar' => null,
),
),
array( // tableAliasMap
'dctrn' => 'dctrn',
)
);
$this->_parserResult->setEntityManager($this->_em);
$this->free(true);
}
/**
* Attempts to match the given token with the current lookahead token.
*
* If they match, updates the lookahead token; otherwise raises a syntax
* error.
*
* @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) {
// No definition for value checking.
$this->syntaxError($this->_keywordTable->getLiteral($token));
}
$this->next();
return true;
}
/**
* Moves the parser scanner to next token
*
* @return void
*/
public function next()
{
$this->token = $this->lookahead;
$this->lookahead = $this->_scanner->next();
$this->_errorDistance++;
}
public function isA($value, $token)
{
return $this->_scanner->isA($value, $token);
}
/**
* Free this parser enabling it to be reused
*
* @param boolean $deep Whether to clean peek and reset errors
* @param integer $position Position to reset
* @return void
*/
public function free($deep = false, $position = 0)
{
// WARNING! Use this method with care. It resets the scanner!
$this->_scanner->resetPosition($position);
// Deep = true cleans peek and also any previously defined errors
if ($deep) {
$this->_scanner->resetPeek();
$this->_errors = array();
}
$this->token = null;
$this->lookahead = null;
$this->_errorDistance = self::MIN_ERROR_DISTANCE;
}
/**
* Parses a query string.
*/
public function parse()
{
$this->lookahead = $this->_scanner->next();
// Building the Abstract Syntax Tree
// We have to double the call of QueryLanguage to allow it to work correctly... =\
$DQL = new Doctrine_Query_Parser_QueryLanguage($this);
$AST = $DQL->parse('QueryLanguage', Doctrine_Query_ParserParamHolder::create());
// Check for end of string
if ($this->lookahead !== null) {
$this->syntaxError('end of string');
}
// Check for semantical errors
if (count($this->_errors) > 0) {
throw new Doctrine_Query_Parser_Exception(implode("\r\n", $this->_errors));
}
// Assign the executor in parser result
$this->_parserResult->setSqlExecutor(Doctrine_Query_SqlExecutor_Abstract::create($AST));
return $this->_parserResult;
}
/**
* Retrieves the assocated Doctrine_Query_SqlBuilder to this object.
*
* @return Doctrine_Query_SqlBuilder
*/
public function getSqlBuilder()
{
return $this->_sqlBuilder;
}
/**
* Returns the scanner object associated with this object.
*
* @return Doctrine_Query_Scanner
*/
public function getScanner()
{
return $this->_scanner;
}
/**
* Returns the parser result associated with this object.
*
* @return Doctrine_Query_ParserResult
*/
public function getParserResult()
{
return $this->_parserResult;
}
/**
* Generates a new syntax error.
*
* @param string $expected Optional expected string.
* @param array $token Optional token.
*/
public function syntaxError($expected = '', $token = null)
{
if ($token === null) {
$token = $this->lookahead;
}
// Formatting message
$message = 'line 0, col ' . (isset($token['position']) ? $token['position'] : '-1') . ': Error: ';
if ($expected !== '') {
$message .= "Expected '$expected', got ";
} else {
$message .= 'Unexpected ';
}
if ($this->lookahead === null) {
$message .= 'end of string.';
} else {
$message .= "'{$this->lookahead['value']}'";
}
throw new Doctrine_Query_Parser_Exception($message);
}
/**
* Generates a new semantical error.
*
* @param string $message Optional message.
* @param array $token Optional token.
*/
public function semanticalError($message = '', $token = null)
{
$this->_semanticalErrorCount++;
if ($token === null) {
$token = $this->token;
}
$this->_logError('Warning: ' . $message, $token);
}
/**
* Logs new error entry.
*
* @param string $message Message to log.
* @param array $token Token that it was processing.
*/
protected function _logError($message = '', $token)
{
if ($this->_errorDistance >= self::MIN_ERROR_DISTANCE) {
$message = 'line 0, col ' . $token['position'] . ': ' . $message;
$this->_errors[] = $message;
}
$this->_errorDistance = 0;
}
/**
* Gets the EntityManager used by the parser.
*
* @return EntityManager
*/
public function getEntityManager()
{
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);
}
}

View File

@ -0,0 +1,76 @@
<?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>.
*/
/**
* AbstractSchemaName ::= identifier
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser_AbstractSchemaName extends Doctrine_Query_ParserRule
{
protected $_AST = null;
public function syntax($paramHolder)
{
// AbstractSchemaName ::= identifier
$this->_AST = $this->AST('AbstractSchemaName');
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
$this->_AST->setComponentName($this->_parser->token['value']);
}
public function semantical($paramHolder)
{
$componentName = $this->_AST->getComponentName();
// Check if we are dealing with a real Doctrine_Entity or not
if ( ! $this->_isDoctrineEntity($componentName)) {
$this->_parser->semanticalError(
"Defined entity '" . $companyName . "' is not a valid Doctrine_Entity."
);
}
// Return AST node
return $this->_AST;
}
protected function _isDoctrineEntity($componentName)
{
if (class_exists($componentName)) {
$reflectionClass = new ReflectionClass($componentName);
$dctrnEntityReflectionClass = new ReflectionClass('Doctrine_Entity');
return $reflectionClass->isSubclassOf($dctrnEntityReflectionClass);
}
return false;
}
}

View File

@ -0,0 +1,66 @@
<?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>.
*/
/**
* AliasIdentificationVariable = identifier
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser_AliasIdentificationVariable extends Doctrine_Query_ParserRule
{
protected $_AST = null;
public function syntax($paramHolder)
{
// AliasIdentificationVariable = identifier
$this->_AST = $this->AST('AliasIdentificationVariable');
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
$this->_AST->setComponentAlias($this->_parser->token['value']);
}
public function semantical($paramHolder)
{
$parserResult = $this->_parser->getParserResult();
if ($parserResult->hasQueryComponent($this->_AST->getComponentAlias())) {
// We should throw semantical error if there's already a component for this alias
$queryComponent = $parserResult->getQueryComponent($this->_AST->getComponentAlias());
$componentName = $queryComponent['metadata']->getClassName();
$message = "Cannot re-declare component alias '" . $this->_AST->getComponentAlias() . "'. "
. "It was already declared for component '" . $componentName . "'.";
$this->_parser->semanticalError($message);
}
return $this->_AST;
}
}

View File

@ -0,0 +1,53 @@
<?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>.
*/
/**
* DeleteStatement ::= DeleteClause [WhereClause]
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser_DeleteStatement extends Doctrine_Query_Parser
{
protected $_AST = null;
public function syntax($paramHolder)
{
// DeleteStatement ::= DeleteClause [WhereClause]
$this->_AST = $this->AST('DeleteStatement');
$this->_AST->setDeleteClause($this->parse('DeleteClause', $paramHolder));
if ($this->_isNextToken(Doctrine_Query_Token::T_WHERE)) {
$this->_AST->setWhereClause($this->parse('WhereClause', $paramHolder));
}
// Return AST node
return $this->_AST;
}
}

View File

@ -0,0 +1,61 @@
<?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>.
*/
/**
* FieldIdentificationVariable ::= identifier
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser_FieldIdentificationVariable extends Doctrine_Query_ParserRule
{
protected $_AST = null;
public function syntax($paramHolder)
{
// FieldIdentificationVariable ::= identifier
$this->_AST = $this->AST('FieldIdentificationVariable');
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
$this->_AST->setFieldName($this->_parser->token['value']);
// Return AST node
return $this->_AST;
}
public function semantical($paramHolder)
{
$parserResult = $this->_parser->getParserResult();
// [TODO] Check for field existance somewhere
// Return AST node
return $this->_AST;
}
}

View File

@ -0,0 +1,61 @@
<?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>.
*/
/**
* FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}
*
* @package Doctrine
* @subpackage 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
* @since 1.0
* @version $Revision$
*/
class Doctrine_Query_Parser_FromClause extends Doctrine_Query_ParserRule
{
protected $_AST = null;
public function syntax($paramHolder)
{
// FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}
$this->_AST = $this->AST('FromClause');
$this->_parser->match(Doctrine_Query_Token::T_FROM);
$this->_AST->addIdentificationVariableDeclaration(
$this->parse('IdentificationVariableDeclaration', $paramHolder)
);
while ($this->_isNextToken(',')) {
$this->_parser->match(',');
$this->_AST->addIdentificationVariableDeclaration(
$this->parse('IdentificationVariableDeclaration', $paramHolder)
);
}
// Return AST node
return $this->_AST;
}
}

View File

@ -0,0 +1,64 @@
<?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>.
*/
/**
* IdentificationVariable ::= identifier
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser_IdentificationVariable extends Doctrine_Query_ParserRule
{
protected $_AST = null;
public function syntax($paramHolder)
{
// IdentificationVariable ::= identifier
$this->_AST = $this->AST('IdentificationVariable');
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
$this->_AST->setComponentAlias($this->_parser->token['value']);
}
public function semantical($paramHolder)
{
$parserResult = $this->_parser->getParserResult();
if ( ! $parserResult->hasQueryComponent($this->_AST->getComponentAlias())) {
// We should throw semantical error if we cannot find the component alias
$message = "No entity related to declared alias '" . $this->_AST->getComponentAlias()
. "' near '" . $this->_parser->getQueryPiece($this->_parser->token) . "'.";
$this->_parser->semanticalError($message);
}
// Return AST node
return $this->_AST;
}
}

View File

@ -0,0 +1,68 @@
<?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>.
*/
/**
* IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*
*
* @package Doctrine
* @subpackage 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
* @since 1.0
* @version $Revision$
*/
class Doctrine_Query_Parser_IdentificationVariableDeclaration extends Doctrine_Query_ParserRule
{
protected $_AST = null;
public function syntax($paramHolder)
{
// IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*
$this->_AST = $this->AST('IdentificationVariableDeclaration');
$this->_AST->setRangeVariableDeclaration($this->parse('RangeVariableDeclaration', $paramHolder));
if ($this->_isNextToken(Doctrine_Query_Token::T_INDEX)) {
$paramHolder->set(
'componentAlias',
$this->_AST->getRangeVariableDeclaration()->getAliasIdentificationVariable()->getComponentAlias()
);
$this->_AST->setIndexBy($this->parse('IndexBy', $paramHolder));
$paramHolder->remove('componentAlias');
}
while (
$this->_isNextToken(Doctrine_Query_Token::T_LEFT) ||
$this->_isNextToken(Doctrine_Query_Token::T_INNER) ||
$this->_isNextToken(Doctrine_Query_Token::T_JOIN)
) {
$this->_AST->addJoinVariableDeclaration($this->parse('JoinVariableDeclaration', $paramHolder));
}
// Return AST node
return $this->_AST;
}
}

View File

@ -0,0 +1,106 @@
<?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>.
*/
/**
* IndexBy ::= "INDEX" "BY" SimpleStateFieldPathExpression
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser_IndexBy extends Doctrine_Query_ParserRule
{
protected $_AST = null;
public function syntax($paramHolder)
{
// IndexBy ::= "INDEX" "BY" SimpleStateFieldPathExpression
$this->_AST = $this->AST('IndexBy');
$this->_parser->match(Doctrine_Query_Token::T_INDEX);
$this->_parser->match(Doctrine_Query_Token::T_BY);
$this->_AST->setSimpleStateFieldPathExpression($this->parse('SimpleStateFieldPathExpression', $paramHolder));
}
public function semantical($paramHolder)
{
$parserResult = $this->_parser->getParserResult();
$componentAlias = $this->_AST->getSimpleStateFieldPathExpression()
->getIdentificationVariable()->getComponentAlias();
$componentFieldName = $this->_AST->getSimpleStateFieldPathExpression()
->getSimpleStateField()->getFieldName();
// Check if we have same component being used in index
if ($componentAlias !== $paramHolder->get('componentAlias')) {
$message = "Invalid alising. Cannot index by '" . $paramHolder->get('componentAlias')
. "' inside '" . $componentAlias . "' scope.";
$this->_parser->semanticalError($message);
}
// Retrieving required information
try {
$queryComponent = $parserResult->getQueryComponent($componentAlias);
$classMetadata = $queryComponent['metadata'];
} catch (Doctrine_Exception $e) {
$this->_parser->semanticalError($e->getMessage());
return;
}
// The INDEXBY field must be either the (primary && not part of composite pk) || (unique && notnull)
$columnMapping = $classMetadata->getFieldMapping($componentFieldName);
if (
! $classMetadata->isIdentifier($componentFieldName) &&
! $classMetadata->isUniqueField($componentFieldName) &&
! $classMetadata->isNotNull($componentFieldName)
) {
$this->_parser->semanticalError(
"Field '" . $componentFieldName . "' of component '" . $classMetadata->getClassName() .
"' must be unique and notnull to be used as index.",
$this->_parser->token
);
}
if ($classMetadata->isIdentifier($componentFieldName) && $classMetadata->isIdentifierComposite()) {
$this->_parser->semanticalError(
"Field '" . $componentFieldName . "' of component '" . $classMetadata->getClassName() .
"' must be primary and not part of a composite primary key to be used as index.",
$this->_parser->token
);
}
$queryComponent['map'] = $componentFieldName;
$parserResult->setQueryComponent($componentAlias, $queryComponent);
// Return AST node
return $this->_AST;
}
}

View File

@ -0,0 +1,57 @@
<?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>.
*/
/**
* QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser_QueryLanguage extends Doctrine_Query_ParserRule
{
public function syntax($paramHolder)
{
// QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement
switch ($this->_parser->lookahead['type']) {
case Doctrine_Query_Token::T_SELECT:
return $this->parse('SelectStatement', $paramHolder);
break;
case Doctrine_Query_Token::T_UPDATE:
return $this->parse('UpdateStatement', $paramHolder);
break;
case Doctrine_Query_Token::T_DELETE:
return $this->parse('DeleteStatement', $paramHolder);
break;
default:
$this->_parser->syntaxError('SELECT, UPDATE or DELETE');
break;
}
}
}

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.phpdoctrine.org>.
*/
/**
* RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
*
* @package Doctrine
* @subpackage 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
* @since 1.0
* @version $Revision$
*/
class Doctrine_Query_Parser_RangeVariableDeclaration extends Doctrine_Query_ParserRule
{
protected $_AST = null;
public function syntax($paramHolder)
{
// RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
$this->_AST = $this->AST('RangeVariableDeclaration');
$this->_AST->setAbstractSchemaName($this->parse('AbstractSchemaName', $paramHolder));
if ($this->_isNextToken(Doctrine_Query_Token::T_AS)) {
$this->_parser->match(Doctrine_Query_Token::T_AS);
}
if ($this->_isNextToken(Doctrine_Query_Token::T_IDENTIFIER)) {
$this->_AST->setAliasIdentificationVariable($this->parse('AliasIdentificationVariable', $paramHolder));
}
}
public function semantical($paramHolder)
{
$parserResult = $this->_parser->getParserResult();
$componentName = $this->_AST->getAbstractSchemaName()->getComponentName();
$componentAlias = $this->_AST->getAliasIdentificationVariable()->getComponentAlias();
// Check if we already have a component defined without an alias
if ($componentAlias === null && $parserResult->hasQueryComponent($componentName)) {
$this->_parser->semanticalError(
"Cannot re-declare component '{$componentName}'. Please assign an alias to it."
);
// Define new queryComponent since it does not exist yet
} else {
// Retrieving ClassMetadata and Mapper
try {
$classMetadata = $this->_em->getClassMetadata($componentName);
// Building queryComponent
$queryComponent = array(
'metadata' => $classMetadata,
'parent' => null,
'relation' => null,
'map' => null,
'scalar' => null,
);
} catch (Doctrine_Exception $e) {
$this->_parser->semanticalError($e->getMessage());
}
// Inspect for possible non-aliasing
if ($componentAlias === null) {
$componentAlias = $componentName;
}
$tableAlias = $parserResult->generateTableAlias($classMetadata->getClassName());
$parserResult->setQueryComponent($componentAlias, $queryComponent);
$parserResult->setTableAlias($tableAlias, $componentAlias);
}
// Return AST node
return $this->_AST;
}
}

View File

@ -0,0 +1,76 @@
<?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>.
*/
/**
* SelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression}
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser_SelectClause extends Doctrine_Query_ParserRule
{
protected $_AST = null;
protected $_selectExpressions = array();
public function syntax($paramHolder)
{
// SelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression}
$this->_AST = $this->AST('SelectClause');
$this->_parser->match(Doctrine_Query_Token::T_SELECT);
// Inspecting if we are in a DISTINCT query
if ($this->_isNextToken(Doctrine_Query_Token::T_DISTINCT)) {
$this->_parser->match(Doctrine_Query_Token::T_DISTINCT);
$this->_AST->setIsDistinct(true);
}
// Process SelectExpressions (1..N)
$this->_selectExpressions[] = $this->parse('SelectExpression', $paramHolder);
while ($this->_isNextToken(',')) {
$this->_parser->match(',');
$this->_selectExpressions[] = $this->parse('SelectExpression', $paramHolder);
}
}
public function semantical($paramHolder)
{
// We need to validate each SelectExpression
for ($i = 0, $l = count($this->_selectExpressions); $i < $l; $i++) {
$this->_AST->addSelectExpression($this->_selectExpressions[$i]->semantical($paramHolder));
}
// Return AST node
return $this->_AST;
}
}

View File

@ -0,0 +1,82 @@
<?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>.
*/
/**
* SelectExpression ::= IdentificationVariable ["." "*"] |
* (StateFieldPathExpression | AggregateExpression | "(" Subselect ")" )
* [["AS"] FieldIdentificationVariable]
*
* @package Doctrine
* @subpackage 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
* @since 1.0
* @version $Revision$
*/
class Doctrine_Query_Parser_SelectExpression extends Doctrine_Query_ParserRule
{
protected $_AST = null;
public function syntax($paramHolder)
{
// SelectExpression ::= IdentificationVariable ["." "*"] |
// (StateFieldPathExpression | AggregateExpression | "(" Subselect ")" )
// [["AS"] FieldIdentificationVariable]
// First we recognize for an IdentificationVariable (Component alias)
if ($this->_isIdentificationVariable()) {
$identificationVariable = $this->parse('IdentificationVariable', $paramHolder);
// Inspecting if we are in a ["." "*"]
if ($this->_isNextToken('.')) {
$this->_parser->match('.');
$this->_parser->match('*');
}
return $identificationVariable;
}
}
protected function _isIdentificationVariable()
{
// Retrying to recoginize this grammar: IdentificationVariable ["." "*"]
$token = $this->_parser->lookahead;
$this->_parser->getScanner()->resetPeek();
// We have an identifier here
if ($token['type'] === Doctrine_Query_Token::T_IDENTIFIER) {
$token = $this->_parser->getScanner()->peek();
// If we have a dot ".", then next char must be the "*"
if ($token['value'] === '.') {
$token = $this->_parser->getScanner()->peek();
return $token['value'] === '*';
}
}
return false;
}
}

View File

@ -0,0 +1,83 @@
<?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>.
*/
/**
* SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser_SelectStatement extends Doctrine_Query_ParserRule
{
protected $_AST = null;
protected $_selectClause = null;
public function syntax($paramHolder)
{
// SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
$this->_AST = $this->AST('SelectStatement');
// Disable the semantical check for SelectClause now. This is needed
// since we dont know the query components yet (will be known only
// when the FROM and WHERE clause are processed).
$paramHolder->set('semanticalCheck', false);
$this->_selectClause = $this->parse('SelectClause', $paramHolder);
$paramHolder->remove('semanticalCheck');
$this->_AST->setFromClause($this->parse('FromClause', $paramHolder));
if ($this->_isNextToken(Doctrine_Query_Token::T_WHERE)) {
$this->_AST->setWhereClause($this->parse('WhereClause', $paramHolder));
}
if ($this->_isNextToken(Doctrine_Query_Token::T_GROUP)) {
$this->_AST->setGroupByClause($this->parse('GroupByClause', $paramHolder));
}
if ($this->_isNextToken(Doctrine_Query_Token::T_HAVING)) {
$this->_AST->setHavingClause($this->parse('HavingClause', $paramHolder));
}
if ($this->_isNextToken(Doctrine_Query_Token::T_ORDER)) {
$this->_AST->setOrderByClause($this->parse('OrderByClause', $paramHolder));
}
}
public function semantical($paramHolder)
{
// We need to invoke the semantical check of SelectClause here, since
// it was not yet checked.
// The semantical checks will be forwarded to all SelectClause dependant grammar rules
$this->_AST->setSelectClause($this->_selectClause->semantical($paramHolder));
// Return AST node
return $this->_AST;
}
}

View File

@ -0,0 +1,44 @@
<?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>.
*/
/**
* SimpleStateField ::= FieldIdentificationVariable
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser_SimpleStateField extends Doctrine_Query_ParserRule
{
protected $_AST = null;
public function syntax($paramHolder)
{
// SimpleStateField ::= FieldIdentificationVariable
return $this->parse('FieldIdentificationVariable', $paramHolder);
}
}

View File

@ -0,0 +1,79 @@
<?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>.
*/
/**
* SimpleStateFieldPathExpression ::= IdentificationVariable "." SimpleStateField
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser_SimpleStateFieldPathExpression extends Doctrine_Query_ParserRule
{
protected $_AST = null;
public function syntax($paramHolder)
{
// SimpleStateFieldPathExpression ::= IdentificationVariable "." SimpleStateField
$this->_AST = $this->AST('SimpleStateFieldPathExpression');
$this->_AST->setIdentificationVariable($this->parse('IdentificationVariable', $paramHolder));
$this->_parser->match('.');
$this->_AST->setSimpleStateField($this->parse('SimpleStateField', $paramHolder));
}
public function semantical($paramHolder)
{
$parserResult = $this->_parser->getParserResult();
$componentAlias = $this->_AST->getIdentificationVariable()->getComponentAlias();
$componentFieldName = $this->_AST->getSimpleStateField()->getFieldName();
// We need to make sure field exists
try {
$queryComponent = $parserResult->getQueryComponent($componentAlias);
$classMetadata = $queryComponent['metadata'];
} catch (Doctrine_Exception $e) {
$this->_parser->semanticalError($e->getMessage());
return;
}
if ($classMetadata instanceof Doctrine_ClassMetadata && ! $classMetadata->hasField($componentFieldName)) {
$this->_parser->semanticalError(
"Cannot use key mapping. Field '" . $componentFieldName . "' " .
"does not exist in component '" . $classMetadata->getClassName() . "'.",
$this->_parser->token
);
}
// Return AST node
return $this->_AST;
}
}

View File

@ -0,0 +1,53 @@
<?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>.
*/
/**
* UpdateStatement ::= UpdateClause [WhereClause]
*
* @package Doctrine
* @subpackage 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
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_Parser_UpdateStatement extends Doctrine_Query_Parser
{
protected $_AST = null;
public function syntax($paramHolder)
{
// UpdateStatement ::= UpdateClause [WhereClause]
$this->_AST = $this->AST('UpdateStatement');
$this->_AST->setUpdateClause($this->parse('UpdateClause', $paramHolder));
if ($this->_isNextToken(Doctrine_Query_Token::T_WHERE)) {
$this->_AST->setWhereClause($this->parse('WhereClause', $paramHolder));
}
// Return AST node
return $this->_AST;
}
}

View File

@ -32,7 +32,7 @@
* @since 2.0
* @version $Revision$
*/
class Doctrine_Query_ProductionParamHolder
class Doctrine_Query_ParserParamHolder
{
protected static $_instance;

View File

@ -33,6 +33,13 @@
*/
class Doctrine_Query_ParserResult extends Doctrine_Query_AbstractResult
{
/**
* The EntityManager.
*
* @var Doctrine_EntityManager
*/
protected $_em;
/**
* A simple array keys representing table aliases and values table alias
* seeds. The seeds are used for generating short table aliases.
@ -47,6 +54,28 @@ class Doctrine_Query_ParserResult extends Doctrine_Query_AbstractResult
* @var array $_queryFields
*/
protected $_queryFields = array();
/**
* Sets the Entity Manager.
*
* @param Doctrine_EntityManager $em The Entity Manager.
*/
public function setEntityManager($em)
{
$this->_em = $em;
}
/**
* Gets the Entity Manager.
*
* @return Doctrine_EntityManager
*/
public function getEntityManager()
{
return $this->_em;
}
/**

View File

@ -32,7 +32,7 @@
* @since 2.0
* @version $Revision$
*/
abstract class Doctrine_Query_Production
abstract class Doctrine_Query_ParserRule
{
/**
* @nodoc
@ -97,27 +97,27 @@ abstract class Doctrine_Query_Production
/**
* Executes the production AST using the specified parameters.
* Executes the grammar rule using the specified parameters.
*
* @param string $AstName Production AST name
* @param string $RuleName BNF Grammar Rule name
* @param array $paramHolder Production parameter holder
* @return Doctrine_Query_Production
* @return Doctrine_Query_ParserRule
*/
public function AST($AstName, $paramHolder)
public function parse($RuleName, $paramHolder)
{
$AST = $this->_getProduction($AstName);
$BNFGrammarRule = $this->_getGrammarRule($RuleName);
//echo "Processing class: " . get_class($AST) . "...\n";
//echo "Processing class: " . get_class($BNFGrammarRule) . "...\n";
//echo "Params: " . var_export($paramHolder, true) . "\n";
// Syntax check
if ( ! $paramHolder->has('syntaxCheck') || $paramHolder->get('syntaxCheck') === true) {
//echo "Processing syntax checks of " . $AstName . "...\n";
//echo "Processing syntax checks of " . $RuleName . "...\n";
$return = $AST->syntax($paramHolder);
$return = $BNFGrammarRule->syntax($paramHolder);
if ($return !== null) {
//echo "Returning AST class: " . (is_object($return) ? get_class($return) : $return) . "...\n";
//echo "Returning Gramma Rule class: " . (is_object($return) ? get_class($return) : $return) . "...\n";
return $return;
}
@ -125,87 +125,64 @@ abstract class Doctrine_Query_Production
// Semantical check
if ( ! $paramHolder->has('semanticalCheck') || $paramHolder->get('semanticalCheck') === true) {
//echo "Processing semantical checks of " . $AstName . "...\n";
//echo "Processing semantical checks of " . $RuleName . "...\n";
$return = $AST->semantical($paramHolder);
$return = $BNFGrammarRule->semantical($paramHolder);
if ($return !== null) {
//echo "Returning AST class: " . (is_object($return) ? get_class($return) : $return) . "...\n";
//echo "Returning Gramma Rule class: " . (is_object($return) ? get_class($return) : $return) . "...\n";
return $return;
}
}
//echo "Returning AST class: " . get_class($AST) . "...\n";
return $AST;
return $BNFGrammarRule;
}
/**
* Returns a production object with the given name.
* Returns a grammar rule object with the given name.
*
* @param string $name production name
* @return Doctrine_Query_Production
* @param string $name grammar rule name
* @return Doctrine_Query_ParserRule
*/
protected function _getProduction($name)
protected function _getGrammarRule($name)
{
$class = 'Doctrine_Query_Production_' . $name;
$class = 'Doctrine_Query_Parser_' . $name;
//echo $class . "\r\n";
if ( ! class_exists($class)) {
throw new Doctrine_Query_Parser_Exception(
"Unknown Grammar Rule '$name'. Could not find related compiler class."
);
}
return new $class($this->_parser);
}
/**
* Executes this production using the specified parameters.
* Creates an AST node with the given name.
*
* @param array $paramHolder Production parameter holder
* @return Doctrine_Query_Production
* @param string $AstName AST node name
* @return Doctrine_Query_AST
*/
public function execute($paramHolder)
public function AST($AstName)
{
//echo "Processing class: " . get_class($this) . " params: \n" . var_export($paramHolder, true) . "\n";
$class = 'Doctrine_Query_AST_' . $AstName;
// Syntax check
if ( ! $paramHolder->has('syntaxCheck') || $paramHolder->get('syntaxCheck') === true) {
//echo "Processing syntax checks of " . get_class($this) . "...\n";
//echo $class . "\r\n";
$return = $this->syntax($paramHolder);
if ($return !== null) {
return $return;
}
if ( ! class_exists($class)) {
throw new Doctrine_Query_Parser_Exception(
"Unknown AST node '" . $AstName . "'. Could not find related compiler class."
);
}
// Semantical check
if ( ! $paramHolder->has('semanticalCheck') || $paramHolder->get('semanticalCheck') === true) {
//echo "Processing semantical checks of " . get_class($this) . "...\n";
$return = $this->semantical($paramHolder);
if ($return !== null) {
return $return;
}
}
// Return AST instance
return $this;
return new $class($this->_parser->getParserResult());
}
/**
* Executes this sql builder using the specified parameters.
*
* @return string Sql piece
*/
/*public function buildSql()
{
$className = get_class($this);
$methodName = substr($className, strrpos($className, '_'));
$this->_sqlBuilder->$methodName($this);
}*/
/**
* @nodoc
*/

View File

@ -70,7 +70,6 @@ class Doctrine_Query_Production_UpdateStatement extends Doctrine_Query_Productio
}
/* Getters */
public function getUpdateClause()
{
return $this->_updateClause;

View File

@ -1,4 +1,4 @@
<?php
<?php
/*
* $Id$
*
@ -35,7 +35,7 @@ abstract class Doctrine_Query_SqlExecutor_Abstract implements Serializable
protected $_sqlStatements;
public function __construct(Doctrine_Query_Production $AST)
public function __construct(Doctrine_Query_AST $AST)
{
// [TODO] Remove me later!
//$this->AST = $AST;
@ -66,10 +66,10 @@ abstract class Doctrine_Query_SqlExecutor_Abstract implements Serializable
* @param Doctrine_Query_Production $AST The root node of the AST.
* @return Doctrine_Query_SqlExecutor_Abstract The executor that is suitable for the given AST.
*/
public static function create(Doctrine_Query_Production $AST)
public static function create(Doctrine_Query_AST $AST)
{
$isDeleteStatement = $AST instanceof Doctrine_Query_Production_DeleteStatement;
$isUpdateStatement = $AST instanceof Doctrine_Query_Production_UpdateStatement;
$isDeleteStatement = $AST instanceof Doctrine_Query_AST_DeleteStatement;
$isUpdateStatement = $AST instanceof Doctrine_Query_AST_UpdateStatement;
if ($isUpdateStatement || $isDeleteStatement) {
// TODO: Inspect the $AST and create the proper executor like so (pseudo-code):

View File

@ -1,4 +1,4 @@
<?php
<?php
/*
* $Id$
*
@ -39,7 +39,7 @@ class Doctrine_Query_SqlExecutor_MultiTableDelete extends Doctrine_Query_SqlExec
*
* @param Doctrine_Query_Production $AST
*/
public function __construct(Doctrine_Query_Production $AST)
public function __construct(Doctrine_Query_AST $AST)
{
// TODO: Inspect the AST, create the necessary SQL queries and store them
// in $this->_sqlStatements

View File

@ -1,4 +1,4 @@
<?php
<?php
/*
* $Id$
*
@ -34,7 +34,7 @@
*/
class Doctrine_Query_SqlExecutor_MultiTableUpdate extends Doctrine_Query_SqlExecutor_Abstract
{
public function __construct(Doctrine_Query_Production $AST)
public function __construct(Doctrine_Query_AST $AST)
{
// TODO: Inspect the AST, create the necessary SQL queries and store them
// in $this->_sqlStatements

View File

@ -1,4 +1,4 @@
<?php
<?php
/*
* $Id$
*
@ -30,7 +30,7 @@
*/
class Doctrine_Query_SqlExecutor_SingleSelect extends Doctrine_Query_SqlExecutor_Abstract
{
public function __construct(Doctrine_Query_Production $AST)
public function __construct(Doctrine_Query_AST $AST)
{
parent::__construct($AST);
$this->_sqlStatements = $AST->buildSql();

View File

@ -32,7 +32,7 @@
*/
class Doctrine_Query_SqlExecutor_SingleTableDeleteUpdate extends Doctrine_Query_SqlExecutor_Abstract
{
public function __construct(Doctrine_Query_Production $AST)
public function __construct(Doctrine_Query_AST $AST)
{
parent::__construct($AST);
$this->_sqlStatements = $AST->buildSql();

View File

@ -1,151 +1,153 @@
<?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>.
*/
/**
* Container for token type constants of Doctrine Query Language.
*
* @package Doctrine
* @subpackage Query
* @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$
*/
final class Doctrine_Query_Token
{
const T_NONE = 1;
const T_IDENTIFIER = 2;
const T_INTEGER = 3;
const T_STRING = 4;
const T_INPUT_PARAMETER = 5;
const T_FLOAT = 6;
const T_ALL = 101;
const T_AND = 102;
const T_ANY = 103;
const T_AS = 104;
const T_ASC = 105;
const T_AVG = 106;
const T_BETWEEN = 107;
const T_BY = 108;
const T_COUNT = 109;
const T_DELETE = 110;
const T_DESC = 111;
const T_DISTINCT = 112;
const T_ESCAPE = 113;
const T_EXISTS = 114;
const T_FROM = 115;
const T_GROUP = 116;
const T_HAVING = 117;
const T_IN = 118;
const T_INDEX = 119;
const T_INNER = 120;
const T_IS = 121;
const T_JOIN = 122;
const T_LEFT = 123;
const T_LIKE = 124;
const T_LIMIT = 125;
const T_MAX = 126;
const T_MIN = 127;
const T_MOD = 128;
const T_NOT = 129;
const T_NULL = 130;
const T_OFFSET = 131;
const T_ON = 132;
const T_OR = 133;
const T_ORDER = 134;
const T_SELECT = 135;
const T_SET = 136;
const T_SIZE = 137;
const T_SOME = 138;
const T_SUM = 139;
const T_UPDATE = 140;
const T_WHERE = 141;
const T_WITH = 142;
const T_TRUE = 143;
const T_FALSE = 144;
protected $_keywordsTable = array();
public function __construct()
{
$this->addKeyword(self::T_ALL, "ALL");
$this->addKeyword(self::T_AND, "AND");
$this->addKeyword(self::T_ANY, "ANY");
$this->addKeyword(self::T_AS, "AS");
$this->addKeyword(self::T_ASC, "ASC");
$this->addKeyword(self::T_AVG, "AVG");
$this->addKeyword(self::T_BETWEEN, "BETWEEN");
$this->addKeyword(self::T_BY, "BY");
$this->addKeyword(self::T_COUNT, "COUNT");
$this->addKeyword(self::T_DELETE, "DELETE");
$this->addKeyword(self::T_DESC, "DESC");
$this->addKeyword(self::T_DISTINCT, "DISTINCT");
$this->addKeyword(self::T_ESCAPE, "ESPACE");
$this->addKeyword(self::T_EXISTS, "EXISTS");
$this->addKeyword(self::T_FALSE, "FALSE");
$this->addKeyword(self::T_FROM, "FROM");
$this->addKeyword(self::T_GROUP, "GROUP");
$this->addKeyword(self::T_HAVING, "HAVING");
$this->addKeyword(self::T_IN, "IN");
$this->addKeyword(self::T_INDEX, "INDEX");
$this->addKeyword(self::T_INNER, "INNER");
$this->addKeyword(self::T_IS, "IS");
$this->addKeyword(self::T_JOIN, "JOIN");
$this->addKeyword(self::T_LEFT, "LEFT");
$this->addKeyword(self::T_LIKE, "LIKE");
$this->addKeyword(self::T_LIMIT, "LIMIT");
$this->addKeyword(self::T_MAX, "MAX");
$this->addKeyword(self::T_MIN, "MIN");
$this->addKeyword(self::T_MOD, "MOD");
$this->addKeyword(self::T_NOT, "NOT");
$this->addKeyword(self::T_NULL, "NULL");
$this->addKeyword(self::T_OFFSET, "OFFSET");
$this->addKeyword(self::T_ON, "ON");
$this->addKeyword(self::T_OR, "OR");
$this->addKeyword(self::T_ORDER, "ORDER");
$this->addKeyword(self::T_SELECT, "SELECT");
$this->addKeyword(self::T_SET, "SET");
$this->addKeyword(self::T_SIZE, "SIZE");
$this->addKeyword(self::T_SOME, "SOME");
$this->addKeyword(self::T_SUM, "SUM");
$this->addKeyword(self::T_TRUE, "TRUE");
$this->addKeyword(self::T_UPDATE, "UPDATE");
$this->addKeyword(self::T_WHERE, "WHERE");
$this->addKeyword(self::T_WITH, "WITH");
}
protected function addKeyword($token, $value)
{
$this->_keywordsTable[$token] = $value;
}
public function getLiteral($token)
{
return isset($this->_keywordsTable[$token]) ? $this->_keywordsTable[$token] : '';
}
}
<?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>.
*/
/**
* Container for token type constants of Doctrine Query Language.
*
* @package Doctrine
* @subpackage Query
* @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$
*/
final class Doctrine_Query_Token
{
const T_NONE = 1;
const T_IDENTIFIER = 2;
const T_INTEGER = 3;
const T_STRING = 4;
const T_INPUT_PARAMETER = 5;
const T_FLOAT = 6;
const T_ALL = 101;
const T_AND = 102;
const T_ANY = 103;
const T_AS = 104;
const T_ASC = 105;
const T_AVG = 106;
const T_BETWEEN = 107;
const T_BY = 108;
const T_COUNT = 109;
const T_DELETE = 110;
const T_DESC = 111;
const T_DISTINCT = 112;
const T_ESCAPE = 113;
const T_EXISTS = 114;
const T_FROM = 115;
const T_GROUP = 116;
const T_HAVING = 117;
const T_IN = 118;
const T_INDEX = 119;
const T_INNER = 120;
const T_IS = 121;
const T_JOIN = 122;
const T_LEFT = 123;
const T_LIKE = 124;
const T_LIMIT = 125;
const T_MAX = 126;
const T_MIN = 127;
const T_MOD = 128;
const T_NOT = 129;
const T_NULL = 130;
const T_OFFSET = 131;
const T_ON = 132;
const T_OR = 133;
const T_ORDER = 134;
const T_SELECT = 135;
const T_SET = 136;
const T_SIZE = 137;
const T_SOME = 138;
const T_SUM = 139;
const T_UPDATE = 140;
const T_WHERE = 141;
const T_WITH = 142;
const T_TRUE = 143;
const T_FALSE = 144;
protected $_keywordsTable = array();
public function __construct()
{
$this->addKeyword(self::T_ALL, "ALL");
$this->addKeyword(self::T_AND, "AND");
$this->addKeyword(self::T_ANY, "ANY");
$this->addKeyword(self::T_AS, "AS");
$this->addKeyword(self::T_ASC, "ASC");
$this->addKeyword(self::T_AVG, "AVG");
$this->addKeyword(self::T_BETWEEN, "BETWEEN");
$this->addKeyword(self::T_BY, "BY");
$this->addKeyword(self::T_COUNT, "COUNT");
$this->addKeyword(self::T_DELETE, "DELETE");
$this->addKeyword(self::T_DESC, "DESC");
$this->addKeyword(self::T_DISTINCT, "DISTINCT");
$this->addKeyword(self::T_ESCAPE, "ESPACE");
$this->addKeyword(self::T_EXISTS, "EXISTS");
$this->addKeyword(self::T_FALSE, "FALSE");
$this->addKeyword(self::T_FROM, "FROM");
$this->addKeyword(self::T_GROUP, "GROUP");
$this->addKeyword(self::T_HAVING, "HAVING");
$this->addKeyword(self::T_IN, "IN");
$this->addKeyword(self::T_INDEX, "INDEX");
$this->addKeyword(self::T_INNER, "INNER");
$this->addKeyword(self::T_IS, "IS");
$this->addKeyword(self::T_JOIN, "JOIN");
$this->addKeyword(self::T_LEFT, "LEFT");
$this->addKeyword(self::T_LIKE, "LIKE");
$this->addKeyword(self::T_LIMIT, "LIMIT");
$this->addKeyword(self::T_MAX, "MAX");
$this->addKeyword(self::T_MIN, "MIN");
$this->addKeyword(self::T_MOD, "MOD");
$this->addKeyword(self::T_NOT, "NOT");
$this->addKeyword(self::T_NULL, "NULL");
$this->addKeyword(self::T_OFFSET, "OFFSET");
$this->addKeyword(self::T_ON, "ON");
$this->addKeyword(self::T_OR, "OR");
$this->addKeyword(self::T_ORDER, "ORDER");
$this->addKeyword(self::T_SELECT, "SELECT");
$this->addKeyword(self::T_SET, "SET");
$this->addKeyword(self::T_SIZE, "SIZE");
$this->addKeyword(self::T_SOME, "SOME");
$this->addKeyword(self::T_SUM, "SUM");
$this->addKeyword(self::T_TRUE, "TRUE");
$this->addKeyword(self::T_UPDATE, "UPDATE");
$this->addKeyword(self::T_WHERE, "WHERE");
$this->addKeyword(self::T_WITH, "WITH");
}
protected function addKeyword($token, $value)
{
$this->_keywordsTable[$token] = $value;
}
public function getLiteral($token)
{
return isset($this->_keywordsTable[$token])
? $this->_keywordsTable[$token]
: (is_string($token) ? $token : '');
}
}

View File

@ -1,250 +1,257 @@
/* Context-free grammar for Doctrine Query Language
*
* Document syntax:
* - non-terminals begin with an upper case character
* - terminals begin with a lower case character
* - parentheses (...) are used for grouping
* - square brackets [...] are used for defining an optional part, eg. zero or
* one time
* - curly brackets {...} are used for repetion, eg. zero or more times
* - double quotation marks "..." define a terminal string
* - a vertical bar | represents an alternative
*
* At a first glance we'll support SQL-99 based queries
* Initially Select and Sub-select DQL will not support LIMIT and OFFSET (due to limit-subquery algorithm)
*/
/*
* TERMINALS
*
* identifier (name, email, ...)
* string ('foo', 'bar''s house', '%ninja%', ...)
* char ('/', '\\', ' ', ...)
* integer (-1, 0, 1, 34, ...)
* float (-0.23, 0.007, 1.245342E+8, ...)
* boolean (false, true)
*/
/*
* QUERY LANGUAGE (START)
*/
QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement
/*
* STATEMENTS
*/
SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
UpdateStatement ::= UpdateClause [WhereClause]
DeleteStatement ::= DeleteClause [WhereClause]
/*
* IDENTIFIERS
*/
IdentificationVariable ::= identifier
/* identifier that must be a class name */
AbstractSchemaName ::= identifier
/* identifier that must be a field */
FieldIdentificationVariable ::= identifier
/* identifier that must be a collection-valued association field (to-many) */
CollectionValuedAssociationField ::= FieldIdentificationVariable
/* identifier that must be a single-valued association field (to-one) */
SingleValuedAssociationField ::= FieldIdentificationVariable
/* identifier that must be an embedded class state field (for the future) */
EmbeddedClassStateField ::= FieldIdentificationVariable
/* identifier that must be a simple state field (name, email, ...) */
SimpleStateField ::= FieldIdentificationVariable
/*
* PATH EXPRESSIONS
*/
JoinAssociationPathExpression ::= JoinCollectionValuedPathExpression | JoinSingleValuedAssociationPathExpression
JoinCollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField
JoinSingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
StateFieldPathExpression ::= {IdentificationVariable | SingleValuedAssociationPathExpression} "." StateField
SingleValuedAssociationPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* SingleValuedAssociationField
CollectionValuedPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* CollectionValuedAssociationField
StateField ::= {EmbeddedClassStateField "."}* SimpleStateField
/*
* CLAUSES
*/
SelectClause ::= "SELECT" ["ALL" | "DISTINCT"] SelectExpression {"," SelectExpression}*
SimpleSelectClause ::= "SELECT" ["ALL" | "DISTINCT"] SimpleSelectExpression
DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName [["AS"] IdentificationVariable]
WhereClause ::= "WHERE" ConditionalExpression
FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}*
SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}*
HavingClause ::= "HAVING" ConditionalExpression
GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}*
OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}*
LimitClause ::= "LIMIT" integer
OffsetClause ::= "OFFSET" integer
UpdateClause ::= "UPDATE" AbstractSchemaName [["AS"] IdentificationVariable] "SET" UpdateItem {"," UpdateItem}*
Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
/*
* ITEMS
*/
OrderByItem ::= StateFieldPathExpression ["ASC" | "DESC"]
GroupByItem ::= SingleValuedPathExpression
UpdateItem ::= [IdentificationVariable"."]{StateField | SingleValuedAssociationField} "=" NewValue
NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary |
EnumPrimary | SimpleEntityExpression | "NULL"
/*
* FROM/JOIN/INDEX BY
*/
IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*
SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | AssociationPathExpression
["AS"] IdentificationVariable
JoinVariableDeclaration ::= Join [IndexBy]
RangeVariableDeclaration ::= AbstractSchemaName ["AS"] IdentificationVariable
Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression
["AS"] IdentificationVariable [("ON" | "WITH") ConditionalExpression]
IndexBy ::= "INDEX" "BY" StateFieldPathExpression
/*
* SELECT EXPRESSION
*/
SelectExpression ::= IdentificationVariable ["." "*"] |
(StateFieldPathExpression | AggregateExpression |
"(" Subselect ")" ) [["AS"] FieldIdentificationVariable]
SimpleSelectExpression ::= SingleValuedPathExpression | IdentificationVariable | AggregateExpression
/*
* CONDITIONAL EXPRESSIONS
*/
ConditionalExpression ::= ConditionalTerm | ConditionalExpression "OR" ConditionalTerm
ConditionalTerm ::= ConditionalFactor | ConditionalTerm "AND" ConditionalFactor
ConditionalFactor ::= ["NOT"] ConditionalPrimary
ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")"
SimpleConditionalExpression ::= ComparisonExpression | BetweenExpression | LikeExpression |
InExpression | NullComparisonExpression | ExistsExpression |
EmptyCollectionComparisonExpression | CollectionMemberExpression
/* EmptyCollectionComparisonExpression and CollectionMemberExpression are for the future */
/*
* COLLECTION EXPRESSIONS (FOR THE FUTURE)
*/
EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY"
CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression
/*
* LITERAL VALUES
*/
Literal ::= string | char | integer | float | boolean | InputParameter
/*
* INPUT PARAMETER
*/
InputParameter ::= PositionalParameter | NamedParameter
PositionalParameter ::= "?" integer
NamedParameter ::= ":" string
/*
* ARITHMETIC EXPRESSIONS
*/
ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")"
SimpleArithmeticExpression ::= ArithmeticTerm | SimpleArithmeticExpression ("+"|"-") ArithmeticTerm
ArithmeticTerm ::= ArithmeticFactor | ArithmeticTerm ("*" |"/") ArithmeticFactor
ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary
ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")" | Function | AggregateExpression
/*
* STRING/BOOLEAN/DATE/ENTITY/ENUM EXPRESSIONS
*/
StringExpression ::= StringPrimary | "(" Subselect ")"
StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression
BooleanExpression ::= BooleanPrimary | "(" Subselect ")"
BooleanPrimary ::= StateFieldPathExpression | boolean | InputParameter
EnumExpression ::= EnumPrimary | "(" Subselect ")"
EnumPrimary ::= StateFieldPathExpression | string | InputParameter
EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression
SimpleEntityExpression ::= IdentificationVariable | InputParameter
DatetimeExpression ::= DatetimePrimary | "(" Subselect ")"
DatetimePrimary ::= StateFieldPathExpression | InputParameter | FunctionsReturningDatetime | AggregateExpression
/*
* AGGREGATE EXPRESSION
*/
AggregateExpression ::= ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" |
"COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedAssociationPathExpression | StateFieldPathExpression) ")"
/*
* QUANTIFIED/BETWEEN/COMPARISON/LIKE/NULL/EXISTS EXPRESSIONS
*/
QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")"
BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression
ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression ) |
StringExpression ComparisonOperator (StringExpression | QuantifiedExpression) |
BooleanExpression ("=" | "<>") (BooleanExpression | QuantifiedExpression) |
EnumExpression ("=" | "<>") (EnumExpression | QuantifiedExpression) |
DatetimeExpression ComparisonOperator (DatetimeExpression | QuantifiedExpression) |
EntityExpression ("=" | "<>") (EntityExpression | QuantifiedExpression)
InExpression ::= StateFieldPathExpression ["NOT"] "IN" "(" (Literal {"," Literal}* | Subselect) ")"
LikeExpression ::= ["NOT"] "LIKE" string ["ESCAPE" char]
NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL"
ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")"
ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!="
/*
* FUNCTIONS
*/
FunctionsReturningStrings ::= PortableFunctionsReturningStrings | OtherFunctionsReturningStrings
FunctionsReturningNumerics ::= PortableFunctionsReturningNumerics | OtherFunctionsReturningNumerics
FunctionsReturningDateTime ::= PortableFunctionsReturningDateTime | OtherFunctionsReturningDateTime
/*
* OTHER FUNCTIONS: List of all allowed (but not portable) functions here.
*/
OtherFunctionsReturningStrings ::= ...
OtherFunctionsReturningNumerics ::= ...
OtherFunctionsReturningDateTime ::= ...
/*
* PORTABLE FUNCTIONS: List all portable functions here
* @TODO add all supported portable functions here
*/
PortableFunctionsReturningNumerics ::=
"LENGTH" "(" StringPrimary ")" |
"LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" |
"ABS" "(" SimpleArithmeticExpression ")" | "SQRT" "(" SimpleArithmeticExpression ")" |
"MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
"SIZE" "(" CollectionValuedPathExpression ")"
PortableFunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP"
PortableFunctionsReturningStrings ::=
"CONCAT" "(" StringPrimary "," StringPrimary ")" |
"SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
"TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" |
"LOWER" "(" StringPrimary ")" |
/* Context-free grammar for Doctrine Query Language
*
* Document syntax:
* - non-terminals begin with an upper case character
* - terminals begin with a lower case character
* - parentheses (...) are used for grouping
* - square brackets [...] are used for defining an optional part, eg. zero or
* one time
* - curly brackets {...} are used for repetion, eg. zero or more times
* - double quotation marks "..." define a terminal string
* - a vertical bar | represents an alternative
*
* At a first glance we'll support SQL-99 based queries
* Initially Select and Sub-select DQL will not support LIMIT and OFFSET (due to limit-subquery algorithm)
*/
/*
* TERMINALS
*
* identifier (name, email, ...)
* string ('foo', 'bar''s house', '%ninja%', ...)
* char ('/', '\\', ' ', ...)
* integer (-1, 0, 1, 34, ...)
* float (-0.23, 0.007, 1.245342E+8, ...)
* boolean (false, true)
*/
/*
* QUERY LANGUAGE (START)
*/
QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement
/*
* STATEMENTS
*/
SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
UpdateStatement ::= UpdateClause [WhereClause]
DeleteStatement ::= DeleteClause [WhereClause]
/*
* IDENTIFIERS
*/
/* Alias Identification usage */
IdentificationVariable ::= identifier
/* Alias Identification declaration */
AliasIdentificationVariable :: = identifier
/* identifier that must be a class name */
AbstractSchemaName ::= identifier
/* identifier that must be a field */
FieldIdentificationVariable ::= identifier
/* identifier that must be a collection-valued association field (to-many) */
CollectionValuedAssociationField ::= FieldIdentificationVariable
/* identifier that must be a single-valued association field (to-one) */
SingleValuedAssociationField ::= FieldIdentificationVariable
/* identifier that must be an embedded class state field (for the future) */
EmbeddedClassStateField ::= FieldIdentificationVariable
/* identifier that must be a simple state field (name, email, ...) */
SimpleStateField ::= FieldIdentificationVariable
/*
* PATH EXPRESSIONS
*/
JoinAssociationPathExpression ::= JoinCollectionValuedPathExpression | JoinSingleValuedAssociationPathExpression
JoinCollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField
JoinSingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
StateFieldPathExpression ::= SimpleStateFieldPathExpression | SimpleStateFieldAssociationPathExpression
SingleValuedAssociationPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* SingleValuedAssociationField
CollectionValuedPathExpression ::= IdentificationVariable "." {SingleValuedAssociationField "."}* CollectionValuedAssociationField
StateField ::= {EmbeddedClassStateField "."}* SimpleStateField
SimpleStateFieldPathExpression ::= IdentificationVariable "." SimpleStateField
SimpleStateFieldAssociationPathExpression ::= SingleValuedAssociationPathExpression "." StateField
/*
* CLAUSES
*/
SelectClause ::= "SELECT" ["ALL" | "DISTINCT"] SelectExpression {"," SelectExpression}*
SimpleSelectClause ::= "SELECT" ["ALL" | "DISTINCT"] SimpleSelectExpression
DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName [["AS"] AliasIdentificationVariable]
WhereClause ::= "WHERE" ConditionalExpression
FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}*
SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}*
HavingClause ::= "HAVING" ConditionalExpression
GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}*
OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}*
LimitClause ::= "LIMIT" integer
OffsetClause ::= "OFFSET" integer
UpdateClause ::= "UPDATE" AbstractSchemaName [["AS"] AliasIdentificationVariable] "SET" UpdateItem {"," UpdateItem}*
Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
/*
* ITEMS
*/
OrderByItem ::= StateFieldPathExpression ["ASC" | "DESC"]
GroupByItem ::= SingleValuedPathExpression
UpdateItem ::= [IdentificationVariable"."]{StateField | SingleValuedAssociationField} "=" NewValue
NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary |
EnumPrimary | SimpleEntityExpression | "NULL"
/*
* FROM/JOIN/INDEX BY
*/
IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*
SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | AssociationPathExpression
["AS"] AliasIdentificationVariable
JoinVariableDeclaration ::= Join [IndexBy]
RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression
["AS"] AliasIdentificationVariable [("ON" | "WITH") ConditionalExpression]
IndexBy ::= "INDEX" "BY" SimpleStateFieldPathExpression
/*
* SELECT EXPRESSION
*/
SelectExpression ::= IdentificationVariable ["." "*"] |
(StateFieldPathExpression | AggregateExpression |
"(" Subselect ")" ) [["AS"] FieldIdentificationVariable]
SimpleSelectExpression ::= SingleValuedPathExpression | IdentificationVariable | AggregateExpression
/*
* CONDITIONAL EXPRESSIONS
*/
ConditionalExpression ::= ConditionalTerm | ConditionalExpression "OR" ConditionalTerm
ConditionalTerm ::= ConditionalFactor | ConditionalTerm "AND" ConditionalFactor
ConditionalFactor ::= ["NOT"] ConditionalPrimary
ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")"
SimpleConditionalExpression ::= ComparisonExpression | BetweenExpression | LikeExpression |
InExpression | NullComparisonExpression | ExistsExpression |
EmptyCollectionComparisonExpression | CollectionMemberExpression
/* EmptyCollectionComparisonExpression and CollectionMemberExpression are for the future */
/*
* COLLECTION EXPRESSIONS (FOR THE FUTURE)
*/
EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY"
CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression
/*
* LITERAL VALUES
*/
Literal ::= string | char | integer | float | boolean | InputParameter
/*
* INPUT PARAMETER
*/
InputParameter ::= PositionalParameter | NamedParameter
PositionalParameter ::= "?" integer
NamedParameter ::= ":" string
/*
* ARITHMETIC EXPRESSIONS
*/
ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")"
SimpleArithmeticExpression ::= ArithmeticTerm | SimpleArithmeticExpression ("+"|"-") ArithmeticTerm
ArithmeticTerm ::= ArithmeticFactor | ArithmeticTerm ("*" |"/") ArithmeticFactor
ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary
ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")" | Function | AggregateExpression
/*
* STRING/BOOLEAN/DATE/ENTITY/ENUM EXPRESSIONS
*/
StringExpression ::= StringPrimary | "(" Subselect ")"
StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression
BooleanExpression ::= BooleanPrimary | "(" Subselect ")"
BooleanPrimary ::= StateFieldPathExpression | boolean | InputParameter
EnumExpression ::= EnumPrimary | "(" Subselect ")"
EnumPrimary ::= StateFieldPathExpression | string | InputParameter
EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression
SimpleEntityExpression ::= IdentificationVariable | InputParameter
DatetimeExpression ::= DatetimePrimary | "(" Subselect ")"
DatetimePrimary ::= StateFieldPathExpression | InputParameter | FunctionsReturningDatetime | AggregateExpression
/*
* AGGREGATE EXPRESSION
*/
AggregateExpression ::= ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" |
"COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedAssociationPathExpression | StateFieldPathExpression) ")"
/*
* QUANTIFIED/BETWEEN/COMPARISON/LIKE/NULL/EXISTS EXPRESSIONS
*/
QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")"
BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression
ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression ) |
StringExpression ComparisonOperator (StringExpression | QuantifiedExpression) |
BooleanExpression ("=" | "<>" | "!=") (BooleanExpression | QuantifiedExpression) |
EnumExpression ("=" | "<>" | "!=") (EnumExpression | QuantifiedExpression) |
DatetimeExpression ComparisonOperator (DatetimeExpression | QuantifiedExpression) |
EntityExpression ("=" | "<>") (EntityExpression | QuantifiedExpression)
InExpression ::= StateFieldPathExpression ["NOT"] "IN" "(" (Literal {"," Literal}* | Subselect) ")"
LikeExpression ::= ["NOT"] "LIKE" string ["ESCAPE" char]
NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL"
ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")"
ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!="
/*
* FUNCTIONS
*/
FunctionsReturningStrings ::= PortableFunctionsReturningStrings | OtherFunctionsReturningStrings
FunctionsReturningNumerics ::= PortableFunctionsReturningNumerics | OtherFunctionsReturningNumerics
FunctionsReturningDateTime ::= PortableFunctionsReturningDateTime | OtherFunctionsReturningDateTime
/*
* OTHER FUNCTIONS: List of all allowed (but not portable) functions here.
*/
OtherFunctionsReturningStrings ::= ...
OtherFunctionsReturningNumerics ::= ...
OtherFunctionsReturningDateTime ::= ...
/*
* PORTABLE FUNCTIONS: List all portable functions here
* @TODO add all supported portable functions here
*/
PortableFunctionsReturningNumerics ::=
"LENGTH" "(" StringPrimary ")" |
"LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" |
"ABS" "(" SimpleArithmeticExpression ")" | "SQRT" "(" SimpleArithmeticExpression ")" |
"MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
"SIZE" "(" CollectionValuedPathExpression ")"
PortableFunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP"
PortableFunctionsReturningStrings ::=
"CONCAT" "(" StringPrimary "," StringPrimary ")" |
"SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
"TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" |
"LOWER" "(" StringPrimary ")" |
"UPPER" "(" StringPrimary ")"

View File

@ -25,12 +25,12 @@ class Orm_Query_AllTests
$suite = new Doctrine_TestSuite('Doctrine Orm Query');
$suite->addTestSuite('Orm_Query_IdentifierRecognitionTest');
$suite->addTestSuite('Orm_Query_LanguageRecognitionTest');
/*$suite->addTestSuite('Orm_Query_LanguageRecognitionTest');
$suite->addTestSuite('Orm_Query_ScannerTest');
$suite->addTestSuite('Orm_Query_DqlGenerationTest');
$suite->addTestSuite('Orm_Query_DeleteSqlGenerationTest');
$suite->addTestSuite('Orm_Query_UpdateSqlGenerationTest');
$suite->addTestSuite('Orm_Query_SelectSqlGenerationTest');
$suite->addTestSuite('Orm_Query_SelectSqlGenerationTest');*/
return $suite;
}

View File

@ -55,7 +55,7 @@ class Orm_Query_IdentifierRecognitionTest extends Doctrine_OrmTestCase
public function testSingleAliasDeclarationWithIndexByIsSupported()
{
$entityManager = $this->_em;
$query = $entityManager->createQuery('SELECT u.* FROM CmsUser u INDEX BY id');
$query = $entityManager->createQuery('SELECT u.* FROM CmsUser u INDEX BY u.id');
$parserResult = $query->parse();
$decl = $parserResult->getQueryComponent('u');

View File

@ -1,6 +1,11 @@
<?php
require_once 'PHPUnit/Framework.php';
require_once 'PHPUnit/TextUI/TestRunner.php';
require_once '../lib/Doctrine.php';
spl_autoload_register(array('Doctrine', 'autoload'));
// Some of these classes depends on Doctrine_* classes
require_once 'Doctrine_TestCase.php';
require_once 'Doctrine_TestUtil.php';
require_once 'Doctrine_DbalTestCase.php';
@ -11,9 +16,6 @@ require_once 'Doctrine_OrmTestSuite.php';
require_once 'Doctrine_OrmFunctionalTestSuite.php';
require_once 'Doctrine_DbalTestSuite.php';
require_once '../lib/Doctrine.php';
spl_autoload_register(array('Doctrine', 'autoload'));
$modelDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'models';
Doctrine_Manager::getInstance()->setAttribute(Doctrine::ATTR_MODEL_LOADING, Doctrine::MODEL_LOADING_CONSERVATIVE);
Doctrine::loadModels($modelDir);

View File

@ -1,4 +1,7 @@
<?php
require_once 'lib/mocks/Doctrine_ConnectionMock.php';
/**
* Base testcase class for all orm testcases.
*
@ -15,7 +18,7 @@ class Doctrine_OrmTestCase extends Doctrine_TestCase
$config = new Doctrine_Configuration();
$eventManager = new Doctrine_EventManager();
$connectionOptions = array(
'driver' => 'Doctrine_ConnectionMock',
'driverClass' => 'Doctrine_ConnectionMock',
'user' => 'john',
'password' => 'wayne'
);

View File

@ -8,7 +8,7 @@ class Doctrine_EntityPersisterMock extends Doctrine_EntityPersister_Standard
private $_identityColumnValueCounter = 0;
public function insert($entity)
public function insert(Doctrine_Entity $entity)
{
if ($entity->getClass()->isIdGeneratorIdentity()) {
$entity->_assignIdentifier($this->_identityColumnValueCounter++);
@ -18,12 +18,12 @@ class Doctrine_EntityPersisterMock extends Doctrine_EntityPersister_Standard
$this->_inserts[] = $entity;
}
public function update($entity)
public function update(Doctrine_Entity $entity)
{
$this->_updates[] = $entity;
}
public function delete($entity)
public function delete(Doctrine_Entity $entity)
{
$this->_deletes[] = $entity;
}