Merged DQL parser branch to trunk.
This commit is contained in:
parent
f8017c9c73
commit
0ad6aee389
@ -303,7 +303,8 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
|
||||
*/
|
||||
public function getDbh()
|
||||
{
|
||||
$this->connect();
|
||||
//$this->connect();
|
||||
|
||||
|
||||
return $this->dbh;
|
||||
}
|
||||
@ -319,8 +320,8 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
|
||||
return false;
|
||||
}
|
||||
|
||||
$event = new Doctrine_Event($this, Doctrine_Event::CONN_CONNECT);
|
||||
$this->getListener()->preConnect($event);
|
||||
//$event = new Doctrine_Event($this, Doctrine_Event::CONN_CONNECT);
|
||||
//$this->getListener()->preConnect($event);
|
||||
|
||||
$e = explode(':', $this->options['dsn']);
|
||||
if (extension_loaded('pdo')) {
|
||||
@ -346,7 +347,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
|
||||
|
||||
$this->isConnected = true;
|
||||
|
||||
$this->getListener()->postConnect($event);
|
||||
//$this->getListener()->postConnect($event);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ class Doctrine_Connection_Mock extends Doctrine_Connection_Common
|
||||
/**
|
||||
* @var string $driverName the name of this connection driver
|
||||
*/
|
||||
protected $driverName = 'Mock';
|
||||
protected $driverName = 'MySql';
|
||||
|
||||
/**
|
||||
* the constructor
|
||||
|
@ -106,7 +106,7 @@ class Doctrine_Connection_Pgsql extends Doctrine_Connection_Common
|
||||
{
|
||||
if (is_array($item)) {
|
||||
foreach ($item as $key => $value) {
|
||||
if (is_bool($value)) {
|
||||
if (is_bool($value) || is_numeric($item)) {
|
||||
$item[$key] = ($value) ? 'true' : 'false';
|
||||
}
|
||||
}
|
||||
|
@ -168,8 +168,6 @@ class Doctrine_Formatter extends Doctrine_Connection_Module
|
||||
case 'gzip':
|
||||
case 'blob':
|
||||
case 'clob':
|
||||
$this->conn->connect();
|
||||
|
||||
return $this->conn->getDbh()->quote($input);
|
||||
}
|
||||
}
|
||||
|
@ -33,10 +33,9 @@
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
*/
|
||||
class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
{
|
||||
{
|
||||
/**
|
||||
* hydrateResultSet
|
||||
* parses the data returned by statement object
|
||||
*
|
||||
* This is method defines the core of Doctrine's object population algorithm.
|
||||
*
|
||||
@ -46,7 +45,6 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
* @todo: Detailed documentation. Refactor (too long & nesting level).
|
||||
*
|
||||
* @param mixed $stmt
|
||||
* @param array $tableAliases Array that maps table aliases (SQL alias => DQL alias)
|
||||
* @param array $aliasMap Array that maps DQL aliases to their components
|
||||
* (DQL alias => array(
|
||||
* 'table' => Table object,
|
||||
@ -71,7 +69,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
if ($hydrationMode == Doctrine::HYDRATE_NONE) {
|
||||
return $stmt->fetchAll(PDO::FETCH_NUM);
|
||||
}
|
||||
|
||||
|
||||
$this->_tableAliases = $parserResult->getTableToClassAliasMap();
|
||||
$this->_queryComponents = $parserResult->getQueryComponents();
|
||||
|
||||
@ -87,24 +85,29 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
|
||||
// Used variables during hydration
|
||||
reset($this->_queryComponents);
|
||||
|
||||
$rootAlias = key($this->_queryComponents);
|
||||
$rootComponentName = $this->_queryComponents[$rootAlias]['table']->getComponentName();
|
||||
// if only one component is involved we can make our lives easier
|
||||
$isSimpleQuery = count($this->_queryComponents) <= 1;
|
||||
|
||||
// Holds hydration listeners that get called during hydration
|
||||
$listeners = array();
|
||||
|
||||
// Lookup map to quickly discover/lookup existing records in the result
|
||||
// It's the identifier "memory"
|
||||
$identifierMap = array();
|
||||
|
||||
// Holds for each component the last previously seen element in the result set
|
||||
$prev = array();
|
||||
// holds the values of the identifier/primary key fields of components,
|
||||
|
||||
// Holds the values of the identifier/primary key fields of components,
|
||||
// separated by a pipe '|' and grouped by component alias (r, u, i, ... whatever)
|
||||
// the $idTemplate is a prepared template. $id is set to a fresh template when
|
||||
// starting to process a row.
|
||||
$id = array();
|
||||
$idTemplate = array();
|
||||
|
||||
|
||||
// Holds the resulting hydrated data structure
|
||||
$result = $driver->getElementCollection($rootComponentName);
|
||||
|
||||
@ -122,9 +125,10 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
$prev[$dqlAlias] = array();
|
||||
$idTemplate[$dqlAlias] = '';
|
||||
}
|
||||
|
||||
|
||||
// Process result set
|
||||
$cache = array();
|
||||
|
||||
while ($data = $stmt->fetch(Doctrine::FETCH_ASSOC)) {
|
||||
$id = $idTemplate; // initialize the id-memory
|
||||
$nonemptyComponents = array();
|
||||
@ -138,16 +142,16 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
|
||||
// just event stuff
|
||||
$event->set('data', $rowData[$rootAlias]);
|
||||
|
||||
$listeners[$componentName]->preHydrate($event);
|
||||
//--
|
||||
|
||||
// Check for an existing element
|
||||
|
||||
$index = false;
|
||||
if ($isSimpleQuery || ! isset($identifierMap[$rootAlias][$id[$rootAlias]])) {
|
||||
$element = $driver->getElement($rowData[$rootAlias], $componentName);
|
||||
|
||||
// just event stuff
|
||||
$event->set('data', $element);
|
||||
|
||||
$listeners[$componentName]->postHydrate($event);
|
||||
//--
|
||||
|
||||
@ -158,6 +162,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
} else if ( ! isset($element[$field])) {
|
||||
throw new Doctrine_Hydrator_Exception("Couldn't hydrate. Found a non-existent key.");
|
||||
}
|
||||
|
||||
$result[$element[$field]] = $element;
|
||||
} else {
|
||||
$result[] = $element;
|
||||
@ -170,10 +175,8 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
|
||||
$this->_setLastElement($prev, $result, $index, $rootAlias, false);
|
||||
unset($rowData[$rootAlias]);
|
||||
|
||||
// end hydrate data of the root component for the current row
|
||||
|
||||
|
||||
// End hydrate data of the root component for the current row
|
||||
|
||||
// $prev[$rootAlias] now points to the last element in $result.
|
||||
// now hydrate the rest of the data found in the current row, that belongs to other
|
||||
// (related) components.
|
||||
@ -184,6 +187,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
|
||||
// just event stuff
|
||||
$event->set('data', $data);
|
||||
|
||||
$listeners[$componentName]->preHydrate($event);
|
||||
//--
|
||||
|
||||
@ -219,6 +223,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
} else if ( ! isset($element[$field])) {
|
||||
throw Doctrine_Hydrator_Exception::nonExistantFieldUsedAsIndex($field);
|
||||
}
|
||||
|
||||
$prev[$parent][$relationAlias][$element[$field]] = $element;
|
||||
} else {
|
||||
$prev[$parent][$relationAlias][] = $element;
|
||||
@ -236,6 +241,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
} else {
|
||||
// 1-1 relation
|
||||
$oneToOne = true;
|
||||
|
||||
if ( ! isset($nonemptyComponents[$dqlAlias])) {
|
||||
$prev[$parent][$relationAlias] = $driver->getNullPointer();
|
||||
} else if ( ! isset($prev[$parent][$relationAlias])) {
|
||||
@ -251,14 +257,13 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
}
|
||||
|
||||
$stmt->closeCursor();
|
||||
|
||||
$driver->flush();
|
||||
|
||||
// re-enable lazy loading
|
||||
|
||||
// Re-enable lazy loading
|
||||
foreach ($this->_queryComponents as $dqlAlias => $data) {
|
||||
$data['table']->setAttribute(Doctrine::ATTR_LOAD_REFERENCES, true);
|
||||
}
|
||||
|
||||
|
||||
//$e = microtime(true);
|
||||
//echo 'Hydration took: ' . ($e - $s) . ' for '.count($result).' records<br />';
|
||||
|
||||
@ -284,14 +289,14 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
if ($coll === $this->_nullObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if ($index !== false) {
|
||||
// Link element at $index to previous element for the component
|
||||
// identified by the DQL alias $alias
|
||||
$prev[$dqlAlias] =& $coll[$index];
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (is_array($coll) && $coll) {
|
||||
if ($oneToOne) {
|
||||
$prev[$dqlAlias] =& $coll;
|
||||
@ -307,19 +312,22 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
unset($prev[$dqlAlias]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* _gatherRowData
|
||||
*
|
||||
* Puts the fields of a data row into a new array, grouped by the component
|
||||
* they belong to. The column names in the result set are mapped to their
|
||||
* they belong to. The column names in the result set are mapped to their
|
||||
* field names during this procedure.
|
||||
*
|
||||
* @return array An array with all the fields (name => value) of the data row,
|
||||
* @return array An array with all the fields (name => value) of the data row,
|
||||
* grouped by their component (alias).
|
||||
*/
|
||||
protected function _gatherRowData(&$data, &$cache, &$id, &$nonemptyComponents)
|
||||
{
|
||||
$rowData = array();
|
||||
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
// Parse each column name only once. Cache the results.
|
||||
if ( ! isset($cache[$key])) {
|
||||
@ -374,13 +382,16 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
$nonemptyComponents[$dqlAlias] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $rowData;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
|
||||
/**
|
||||
* _getCustomIndexField
|
||||
*
|
||||
* Gets the custom field used for indexing for the specified component alias.
|
||||
*
|
||||
*
|
||||
* @return string The field name of the field used for indexing or NULL
|
||||
* if the component does not use any custom field indices.
|
||||
*/
|
||||
@ -388,5 +399,5 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
|
||||
{
|
||||
return isset($this->_queryComponents[$alias]['map']) ? $this->_queryComponents[$alias]['map'] : null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -33,22 +33,23 @@
|
||||
abstract class Doctrine_Hydrator_Abstract
|
||||
{
|
||||
/**
|
||||
* @var array $_aliasMap two dimensional array containing the map for query aliases
|
||||
* Main keys are component aliases
|
||||
* @var array $_queryComponents
|
||||
*
|
||||
* table table object associated with given alias
|
||||
* Two dimensional array containing the map for query aliases. Main keys are component aliases.
|
||||
*
|
||||
* relation the relation object owned by the parent
|
||||
*
|
||||
* parent the alias of the parent
|
||||
*
|
||||
* agg the aggregates of this component
|
||||
*
|
||||
* map the name of the column / aggregate value this
|
||||
* component is mapped to a collection
|
||||
* table Table object associated with given alias.
|
||||
* relation Relation object owned by the parent.
|
||||
* parent Alias of the parent.
|
||||
* agg Aggregates of this component.
|
||||
* map Name of the column / aggregate value this component is mapped to a collection.
|
||||
*/
|
||||
protected $_queryComponents = array();
|
||||
|
||||
/**
|
||||
* @var array Table alias map. Keys are SQL aliases and values DQL aliases.
|
||||
*/
|
||||
protected $_tableAliasMap = array();
|
||||
|
||||
/**
|
||||
* The current hydration mode.
|
||||
*/
|
||||
@ -58,6 +59,7 @@ abstract class Doctrine_Hydrator_Abstract
|
||||
|
||||
protected $_em;
|
||||
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
@ -69,96 +71,88 @@ abstract class Doctrine_Hydrator_Abstract
|
||||
$this->_nullObject = Doctrine_Null::$INSTANCE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the fetchmode.
|
||||
* setHydrationMode
|
||||
*
|
||||
* @param integer $fetchmode One of the Doctrine::HYDRATE_* constants.
|
||||
* Defines the hydration process mode.
|
||||
*
|
||||
* @param integer $hydrationMode Doctrine processing mode to be used during hydration process.
|
||||
* One of the Doctrine::HYDRATE_* constants.
|
||||
*/
|
||||
public function setHydrationMode($hydrationMode)
|
||||
{
|
||||
$this->_hydrationMode = $hydrationMode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* setAliasMap
|
||||
* sets the whole component alias map
|
||||
* setQueryComponents
|
||||
*
|
||||
* @param array $map alias map
|
||||
* @return Doctrine_Hydrate this object
|
||||
* Defines the mapping components.
|
||||
*
|
||||
* @param array $queryComponents Query components.
|
||||
*/
|
||||
public function setQueryComponents(array $queryComponents)
|
||||
{
|
||||
$this->_queryComponents = $queryComponents;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getAliasMap
|
||||
* returns the component alias map
|
||||
* getQueryComponents
|
||||
*
|
||||
* @return array component alias map
|
||||
* Gets the mapping components.
|
||||
*
|
||||
* @return array Query components.
|
||||
*/
|
||||
public function getQueryComponents()
|
||||
{
|
||||
return $this->_queryComponents;
|
||||
}
|
||||
|
||||
/**
|
||||
* hasAliasDeclaration
|
||||
* whether or not this object has a declaration for given component alias
|
||||
*
|
||||
* @param string $componentAlias the component alias the retrieve the declaration from
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasAliasDeclaration($componentAlias)
|
||||
{
|
||||
return isset($this->_queryComponents[$componentAlias]);
|
||||
}
|
||||
|
||||
/**
|
||||
* getAliasDeclaration
|
||||
* get the declaration for given component alias
|
||||
*
|
||||
* @param string $componentAlias the component alias the retrieve the declaration from
|
||||
* @return array the alias declaration
|
||||
* @deprecated
|
||||
*/
|
||||
public function getAliasDeclaration($componentAlias)
|
||||
{
|
||||
return $this->getQueryComponent($componentAlias);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getQueryComponent
|
||||
* get the declaration for given component alias
|
||||
* setTableAliasMap
|
||||
*
|
||||
* @param string $componentAlias the component alias the retrieve the declaration from
|
||||
* @return array the alias declaration
|
||||
* Defines the table aliases.
|
||||
*
|
||||
* @param array $tableAliasMap Table aliases.
|
||||
*/
|
||||
public function getQueryComponent($componentAlias)
|
||||
public function setTableAliasMap(array $tableAliasMap)
|
||||
{
|
||||
if ( ! isset($this->_queryComponents[$componentAlias])) {
|
||||
throw new Doctrine_Query_Exception('Unknown component alias ' . $componentAlias);
|
||||
}
|
||||
|
||||
return $this->_queryComponents[$componentAlias];
|
||||
$this->_tableAliasMap = $tableAliasMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* parseData
|
||||
* parses the data returned by statement object
|
||||
* getTableAliasMap
|
||||
*
|
||||
* Returns all table aliases.
|
||||
*
|
||||
* @return array Table aliases as an array.
|
||||
*/
|
||||
public function getTableAliasMap()
|
||||
{
|
||||
return $this->_tableAliasMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hydrateResultSet
|
||||
*
|
||||
* Processes data returned by statement object.
|
||||
*
|
||||
* This is method defines the core of Doctrine object population algorithm
|
||||
* hence this method strives to be as fast as possible
|
||||
* hence this method strives to be as fast as possible.
|
||||
*
|
||||
* The key idea is the loop over the rowset only once doing all the needed operations
|
||||
* within this massive loop.
|
||||
*
|
||||
* @todo: Can we refactor this function so that it is not so long and
|
||||
* nested?
|
||||
*
|
||||
* @param mixed $stmt
|
||||
* @return array
|
||||
* @param mixed $stmt PDOStatement
|
||||
* @param integer $hydrationMode Doctrine processing mode to be used during hydration process.
|
||||
* One of the Doctrine::HYDRATE_* constants.
|
||||
* @return mixed Doctrine_Collection|array
|
||||
*/
|
||||
abstract public function hydrateResultSet($parserResult);
|
||||
|
||||
}
|
||||
|
1948
lib/Doctrine/Query.php
Normal file → Executable file
1948
lib/Doctrine/Query.php
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
2173
lib/Doctrine/Query/Abstract.php
Normal file → Executable file
2173
lib/Doctrine/Query/Abstract.php
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
266
lib/Doctrine/Query/AbstractResult.php
Executable file
266
lib/Doctrine/Query/AbstractResult.php
Executable file
@ -0,0 +1,266 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* $Id: Cache.php 3938 2008-03-06 19:36:50Z 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_Query_AbstractResult
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.com
|
||||
* @since 1.0
|
||||
* @version $Revision: 1393 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*/
|
||||
abstract class Doctrine_Query_AbstractResult
|
||||
{
|
||||
/**
|
||||
* @var mixed $_data The actual data to be stored. Can be an array, a string or an integer.
|
||||
*/
|
||||
protected $_data;
|
||||
|
||||
/**
|
||||
* @var array $_queryComponents
|
||||
*
|
||||
* Two dimensional array containing the map for query aliases. Main keys are component aliases.
|
||||
*
|
||||
* table Table object associated with given alias.
|
||||
* relation Relation object owned by the parent.
|
||||
* parent Alias of the parent.
|
||||
* agg Aggregates of this component.
|
||||
* map Name of the column / aggregate value this component is mapped to a collection.
|
||||
*/
|
||||
protected $_queryComponents;
|
||||
|
||||
/**
|
||||
* @var array Table alias map. Keys are SQL aliases and values DQL aliases.
|
||||
*/
|
||||
protected $_tableAliasMap;
|
||||
|
||||
/**
|
||||
* @var array Enum params.
|
||||
*/
|
||||
protected $_enumParams;
|
||||
|
||||
|
||||
/**
|
||||
* Cannot be called directly, factory methods handle this job.
|
||||
*
|
||||
* @param mixed $data Data to be stored.
|
||||
* @param array $queryComponents Query components.
|
||||
* @param array $tableAliasMap Table aliases.
|
||||
* @param array $enumParams Enum params.
|
||||
* @return Doctrine_Query_CacheHandler
|
||||
*/
|
||||
public function __construct($data = '', $queryComponents = array(), $tableAliasMap = array(), $enumParams = array())
|
||||
{
|
||||
$this->_data = $data;
|
||||
$this->_queryComponents = $queryComponents;
|
||||
$this->_tableAliasMap = $tableAliasMap;
|
||||
$this->_enumParams = $enumParams;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defines the mapping components.
|
||||
*
|
||||
* @param array $queryComponents Query components.
|
||||
*/
|
||||
public function setQueryComponents(array $queryComponents)
|
||||
{
|
||||
$this->_queryComponents = $queryComponents;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the declaration for given component alias.
|
||||
*
|
||||
* @param string $componentAlias The component alias to set the declaration to.
|
||||
* @param string $queryComponent Alias declaration.
|
||||
*/
|
||||
public function setQueryComponent($componentAlias, array $queryComponent)
|
||||
{
|
||||
$this->_queryComponents[$componentAlias] = $queryComponent;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the mapping components.
|
||||
*
|
||||
* @return array Query components.
|
||||
*/
|
||||
public function getQueryComponents()
|
||||
{
|
||||
return $this->_queryComponents;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the declaration for given component alias.
|
||||
*
|
||||
* @param string $componentAlias The component alias the retrieve the declaration from.
|
||||
* @return array Alias declaration.
|
||||
*/
|
||||
public function getQueryComponent($componentAlias)
|
||||
{
|
||||
if ( ! isset($this->_queryComponents[$componentAlias])) {
|
||||
throw new Doctrine_Query_Exception('Unknown query component ' . $componentAlias);
|
||||
}
|
||||
|
||||
return $this->_queryComponents[$componentAlias];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Whether or not this object has a declaration for given component alias.
|
||||
*
|
||||
* @param string $componentAlias Component alias the retrieve the declaration from.
|
||||
* @return boolean True if this object has given alias, otherwise false.
|
||||
*/
|
||||
public function hasQueryComponent($componentAlias)
|
||||
{
|
||||
return isset($this->_queryComponents[$componentAlias]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defines the table aliases.
|
||||
*
|
||||
* @param array $tableAliasMap Table aliases.
|
||||
*/
|
||||
public function setTableAliasMap(array $tableAliasMap)
|
||||
{
|
||||
$this->_tableAliasMap = $tableAliasMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds an SQL table alias and associates it a component alias
|
||||
*
|
||||
* @param string $tableAlias Table alias to be added.
|
||||
* @param string $componentAlias Alias for the query component associated with given tableAlias.
|
||||
*/
|
||||
public function setTableAlias($tableAlias, $componentAlias)
|
||||
{
|
||||
$this->_tableAliasMap[$tableAlias] = $componentAlias;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all table aliases.
|
||||
*
|
||||
* @return array Table aliases as an array.
|
||||
*/
|
||||
public function getTableAliasMap()
|
||||
{
|
||||
return $this->_tableAliasMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get component alias associated with given table alias.
|
||||
*
|
||||
* @param string $tableAlias SQL table alias that identifies the component alias
|
||||
* @return string Component alias
|
||||
*/
|
||||
public function getTableAlias($tableAlias)
|
||||
{
|
||||
if ( ! isset($this->_tableAliasMap[$tableAlias])) {
|
||||
throw new Doctrine_Query_Exception('Unknown table alias ' . $tableAlias);
|
||||
}
|
||||
|
||||
return $this->_tableAliasMap[$tableAlias];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get table alias associated with given component alias.
|
||||
*
|
||||
* @param string $componentAlias Component alias that identifies the table alias
|
||||
* @return string Component alias
|
||||
*/
|
||||
public function getTableAliasFromComponentAlias($componentAlias)
|
||||
{
|
||||
return array_search($componentAlias, $this->_tableAliasMap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Whether or not this object has given tableAlias.
|
||||
*
|
||||
* @param string $tableAlias Table alias to be checked.
|
||||
* @return boolean True if this object has given alias, otherwise false.
|
||||
*/
|
||||
public function hasTableAlias($tableAlias)
|
||||
{
|
||||
return (isset($this->_tableAliasMap[$tableAlias]));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the enum parameters.
|
||||
*
|
||||
* @return mixed Enum parameters.
|
||||
*/
|
||||
public function getEnumParams()
|
||||
{
|
||||
return $this->_enumParams;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets input parameter as an enumerated parameter
|
||||
*
|
||||
* @param string $key The key of the input parameter
|
||||
* @return Doctrine_Query_AbstractResult
|
||||
*/
|
||||
public function addEnumParam($key, $table = null, $column = null)
|
||||
{
|
||||
$array = (isset($table) || isset($column)) ? array($table, $column) : array();
|
||||
|
||||
if ($key === '?') {
|
||||
$this->_enumParams[] = $array;
|
||||
} else {
|
||||
$this->_enumParams[$key] = $array;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns this object in serialized format, revertable using fromCached*.
|
||||
*
|
||||
* @return string Serialized cached item.
|
||||
*/
|
||||
public function toCachedForm()
|
||||
{
|
||||
return serialize(array(
|
||||
$this->_data,
|
||||
$this->getQueryComponents(),
|
||||
$this->getTableAliasMap(),
|
||||
$this->getEnumParams()
|
||||
));
|
||||
}
|
||||
|
||||
}
|
1805
lib/Doctrine/Query/Abstract_old.php
Normal file
1805
lib/Doctrine/Query/Abstract_old.php
Normal file
File diff suppressed because it is too large
Load Diff
156
lib/Doctrine/Query/CacheHandler.php
Executable file
156
lib/Doctrine/Query/CacheHandler.php
Executable file
@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* $Id: Cache.php 3938 2008-03-06 19:36:50Z 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::autoload('Doctrine_Query_AbstractResult');
|
||||
Doctrine::autoload('Doctrine_Query_ParserResult');
|
||||
Doctrine::autoload('Doctrine_Query_QueryResult');
|
||||
|
||||
/**
|
||||
* Doctrine_Query_CacheHandler
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.com
|
||||
* @since 1.0
|
||||
* @version $Revision: 1393 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*
|
||||
* @todo Re-document this class
|
||||
*/
|
||||
abstract class Doctrine_Query_CacheHandler
|
||||
{
|
||||
/**
|
||||
* Static factory method. Receives a Doctrine_Query object and generates
|
||||
* the object after processing queryComponents. Table aliases are retrieved
|
||||
* directly from Doctrine_Query_Parser.
|
||||
*
|
||||
* @param mixed $result Data to be stored.
|
||||
* @param Doctrine_Query_ParserResult $parserResult Parser results that enables to have important data retrieved.
|
||||
*/
|
||||
public static function fromResultSet($result, $parserResult)
|
||||
{
|
||||
$queryComponents = array();
|
||||
|
||||
foreach ($parserResult->getQueryComponents() as $alias => $components) {
|
||||
if ( ! isset($components['parent'])) {
|
||||
$queryComponents[$alias][] = $components['mapper']->getComponentName();
|
||||
//$queryComponents[$alias][] = $components['mapper']->getComponentName();
|
||||
} else {
|
||||
$queryComponents[$alias][] = $components['parent'] . '.' . $components['relation']->getAlias();
|
||||
}
|
||||
|
||||
if (isset($components['agg'])) {
|
||||
$queryComponents[$alias][] = $components['agg'];
|
||||
}
|
||||
|
||||
if (isset($components['map'])) {
|
||||
$queryComponents[$alias][] = $components['map'];
|
||||
}
|
||||
}
|
||||
|
||||
return new Doctrine_Query_QueryResult(
|
||||
$result,
|
||||
$queryComponents,
|
||||
$parserResult->getTableAliasMap(),
|
||||
$parserResult->getEnumParams()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Static factory method. Receives a Doctrine_Query object and a cached data.
|
||||
* It handles the cache and generates the object after processing queryComponents.
|
||||
* Table aliases are retrieved from cache.
|
||||
*
|
||||
* @param Doctrine_Query $query Doctrine_Query_Object related to this cache item.
|
||||
* @param mixed $cached Cached data.
|
||||
*/
|
||||
public static function fromCachedResult($query, $cached = false)
|
||||
{
|
||||
$cached = unserialize($cached);
|
||||
|
||||
return new Doctrine_Query_QueryResult(
|
||||
$cached[0],
|
||||
self::_getQueryComponents($cached[1]),
|
||||
$cached[2],
|
||||
$cached[3]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Static factory method. Receives a Doctrine_Query object and a cached data.
|
||||
* It handles the cache and generates the object after processing queryComponents.
|
||||
* Table aliases are retrieved from cache.
|
||||
*
|
||||
* @param Doctrine_Query $query Doctrine_Query_Object related to this cache item.
|
||||
* @param mixed $cached Cached data.
|
||||
*/
|
||||
public static function fromCachedQuery($query, $cached = false)
|
||||
{
|
||||
$cached = unserialize($cached);
|
||||
|
||||
return new Doctrine_Query_ParserResult(
|
||||
$cached[0],
|
||||
self::_getQueryComponents($cached[1]),
|
||||
$cached[2],
|
||||
$cached[3]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @nodoc
|
||||
*/
|
||||
protected static function _getQueryComponents($query, $cachedQueryComponents)
|
||||
{
|
||||
$queryComponents = array();
|
||||
|
||||
foreach ($cachedQueryComponents as $alias => $components) {
|
||||
$e = explode('.', $components[0]);
|
||||
|
||||
if (count($e) === 1) {
|
||||
$queryComponents[$alias]['mapper'] = $query->getConnection()->getMapper($e[0]);
|
||||
$queryComponents[$alias]['table'] = $queryComponents[$alias]['mapper']->getTable();
|
||||
} else {
|
||||
$queryComponents[$alias]['parent'] = $e[0];
|
||||
$queryComponents[$alias]['relation'] = $queryComponents[$e[0]]['table']->getRelation($e[1]);
|
||||
$queryComponents[$alias]['mapper'] = $query->getConnection()->getMapper($queryComponents[$alias]['relation']->getForeignComponentName());
|
||||
$queryComponents[$alias]['table'] = $queryComponents[$alias]['mapper']->getTable();
|
||||
}
|
||||
|
||||
if (isset($v[1])) {
|
||||
$queryComponents[$alias]['agg'] = $components[1];
|
||||
}
|
||||
|
||||
if (isset($v[2])) {
|
||||
$queryComponents[$alias]['map'] = $components[2];
|
||||
}
|
||||
}
|
||||
|
||||
return $queryComponents;
|
||||
}
|
||||
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id: From.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_Query_Check
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @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_Query_Check
|
||||
{
|
||||
/**
|
||||
* @var Doctrine_Table $table Doctrine_Table object
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* @var string $sql database specific sql CHECK constraint definition
|
||||
* parsed from the given dql CHECK definition
|
||||
*/
|
||||
protected $sql;
|
||||
|
||||
protected $_tokenizer;
|
||||
|
||||
/**
|
||||
* @param Doctrine_Table|string $table Doctrine_Table object
|
||||
*/
|
||||
public function __construct($table)
|
||||
{
|
||||
if ( ! ($table instanceof Doctrine_Table)) {
|
||||
$table = Doctrine_Manager::getInstance()
|
||||
->getCurrentConnection()
|
||||
->getClassMetadata($table);
|
||||
}
|
||||
$this->table = $table;
|
||||
$this->_tokenizer = new Doctrine_Query_Tokenizer();
|
||||
}
|
||||
|
||||
/**
|
||||
* getTable
|
||||
* returns the table object associated with this object
|
||||
*
|
||||
* @return Doctrine_Connection
|
||||
*/
|
||||
public function getTable()
|
||||
{
|
||||
return $this->table;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse
|
||||
*
|
||||
* @param string $dql DQL CHECK constraint definition
|
||||
* @return string
|
||||
*/
|
||||
public function parse($dql)
|
||||
{
|
||||
$this->sql = $this->parseClause($dql);
|
||||
}
|
||||
|
||||
/**
|
||||
* parseClause
|
||||
*
|
||||
* @param string $alias component alias
|
||||
* @param string $field the field name
|
||||
* @param mixed $value the value of the field
|
||||
* @return void
|
||||
*/
|
||||
public function parseClause($dql)
|
||||
{
|
||||
$parts = $this->_tokenizer->sqlExplode($dql, ' AND ');
|
||||
|
||||
if (count($parts) > 1) {
|
||||
$ret = array();
|
||||
foreach ($parts as $part) {
|
||||
$ret[] = $this->parseSingle($part);
|
||||
}
|
||||
|
||||
$r = implode(' AND ', $ret);
|
||||
} else {
|
||||
$parts = $this->_tokenizer->quoteExplode($dql, ' OR ');
|
||||
if (count($parts) > 1) {
|
||||
$ret = array();
|
||||
foreach ($parts as $part) {
|
||||
$ret[] = $this->parseClause($part);
|
||||
}
|
||||
|
||||
$r = implode(' OR ', $ret);
|
||||
} else {
|
||||
$ret = $this->parseSingle($dql);
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
return '(' . $r . ')';
|
||||
}
|
||||
|
||||
public function parseSingle($part)
|
||||
{
|
||||
$e = explode(' ', $part);
|
||||
|
||||
$e[0] = $this->parseFunction($e[0]);
|
||||
|
||||
switch ($e[1]) {
|
||||
case '>':
|
||||
case '<':
|
||||
case '=':
|
||||
case '!=':
|
||||
case '<>':
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new Doctrine_Query_Exception('Unknown operator ' . $e[1]);
|
||||
}
|
||||
|
||||
return implode(' ', $e);
|
||||
}
|
||||
public function parseFunction($dql)
|
||||
{
|
||||
if (($pos = strpos($dql, '(')) !== false) {
|
||||
$func = substr($dql, 0, $pos);
|
||||
$value = substr($dql, ($pos + 1), -1);
|
||||
|
||||
$expr = $this->table->getConnection()->expression;
|
||||
|
||||
if ( ! method_exists($expr, $func)) {
|
||||
throw new Doctrine_Query_Exception('Unknown function ' . $func);
|
||||
}
|
||||
|
||||
$func = $expr->$func($value);
|
||||
}
|
||||
return $func;
|
||||
}
|
||||
|
||||
/**
|
||||
* getSql
|
||||
*
|
||||
* returns database specific sql CHECK constraint definition
|
||||
* parsed from the given dql CHECK definition
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSql()
|
||||
{
|
||||
return $this->sql;
|
||||
}
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
Doctrine::autoload('Doctrine_Query_Part');
|
||||
/**
|
||||
* Doctrine_Query_Condition
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*/
|
||||
abstract class Doctrine_Query_Condition extends Doctrine_Query_Part
|
||||
{
|
||||
/**
|
||||
* DQL CONDITION PARSER
|
||||
* parses the join condition/where/having part of the query string
|
||||
*
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
public function parse($str)
|
||||
{
|
||||
$tmp = trim($str);
|
||||
|
||||
$parts = $this->_tokenizer->bracketExplode($str, array(' \&\& ', ' AND '), '(', ')');
|
||||
|
||||
if (count($parts) > 1) {
|
||||
$ret = array();
|
||||
foreach ($parts as $part) {
|
||||
$part = $this->_tokenizer->bracketTrim($part, '(', ')');
|
||||
$ret[] = $this->parse($part);
|
||||
}
|
||||
$r = implode(' AND ', $ret);
|
||||
} else {
|
||||
|
||||
$parts = $this->_tokenizer->bracketExplode($str, array(' \|\| ', ' OR '), '(', ')');
|
||||
if (count($parts) > 1) {
|
||||
$ret = array();
|
||||
foreach ($parts as $part) {
|
||||
$part = $this->_tokenizer->bracketTrim($part, '(', ')');
|
||||
$ret[] = $this->parse($part);
|
||||
}
|
||||
$r = implode(' OR ', $ret);
|
||||
} else {
|
||||
// Fix for #710
|
||||
if (substr($parts[0],0,1) == '(' && substr($parts[0], -1) == ')') {
|
||||
return $this->parse(substr($parts[0], 1, -1));
|
||||
} else {
|
||||
// Processing NOT here
|
||||
if (strtoupper(substr($parts[0], 0, 4)) === 'NOT ') {
|
||||
$r = 'NOT ('.$this->parse(substr($parts[0], 4)).')';
|
||||
} else {
|
||||
return $this->load($parts[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '(' . $r . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* parses a literal value and returns the parsed value
|
||||
*
|
||||
* boolean literals are parsed to integers
|
||||
* components are parsed to associated table aliases
|
||||
*
|
||||
* @param string $value literal value to be parsed
|
||||
* @return string
|
||||
*/
|
||||
public function parseLiteralValue($value)
|
||||
{
|
||||
// check that value isn't a string
|
||||
if (strpos($value, '\'') === false) {
|
||||
// parse booleans
|
||||
$value = $this->query->getConnection()
|
||||
->dataDict->parseBoolean($value);
|
||||
|
||||
$a = explode('.', $value);
|
||||
|
||||
if (count($a) > 1) {
|
||||
// either a float or a component..
|
||||
|
||||
if ( ! is_numeric($a[0])) {
|
||||
// a component found
|
||||
$field = array_pop($a);
|
||||
$reference = implode('.', $a);
|
||||
$value = $this->query->getTableAlias($reference). '.' . $field;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// string literal found
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
Doctrine::autoload("Doctrine_Query_Part");
|
||||
/**
|
||||
* Doctrine_Query_From
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*/
|
||||
class Doctrine_Query_From extends Doctrine_Query_Part
|
||||
{
|
||||
/**
|
||||
* DQL FROM PARSER
|
||||
* parses the FROM part of the query string
|
||||
*
|
||||
* @param string $str
|
||||
* @return void
|
||||
*/
|
||||
public function parse($str)
|
||||
{
|
||||
$str = trim($str);
|
||||
$parts = $this->_tokenizer->bracketExplode($str, 'JOIN');
|
||||
|
||||
$operator = false;
|
||||
|
||||
switch (trim($parts[0])) {
|
||||
case 'INNER':
|
||||
$operator = ':';
|
||||
case 'LEFT':
|
||||
array_shift($parts);
|
||||
break;
|
||||
}
|
||||
|
||||
$last = '';
|
||||
|
||||
foreach ($parts as $k => $part) {
|
||||
$part = trim($part);
|
||||
|
||||
if (empty($part)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$e = explode(' ', $part);
|
||||
|
||||
if (end($e) == 'INNER' || end($e) == 'LEFT') {
|
||||
$last = array_pop($e);
|
||||
}
|
||||
$part = implode(' ', $e);
|
||||
|
||||
foreach ($this->_tokenizer->bracketExplode($part, ',') as $reference) {
|
||||
$reference = trim($reference);
|
||||
$e = explode(' ', $reference);
|
||||
$e2 = explode('.', $e[0]);
|
||||
|
||||
if ($operator) {
|
||||
$e[0] = array_shift($e2) . $operator . implode('.', $e2);
|
||||
}
|
||||
$table = $this->query->load(implode(' ', $e));
|
||||
}
|
||||
|
||||
$operator = ($last == 'INNER') ? ':' : '.';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
Doctrine::autoload('Doctrine_Query_Condition');
|
||||
/**
|
||||
* Doctrine_Query_Having
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*/
|
||||
class Doctrine_Query_Having extends Doctrine_Query_Condition
|
||||
{
|
||||
/**
|
||||
* DQL Aggregate Function parser
|
||||
*
|
||||
* @param string $func
|
||||
* @return mixed
|
||||
*/
|
||||
private function parseAggregateFunction($func)
|
||||
{
|
||||
$pos = strpos($func, '(');
|
||||
|
||||
if ($pos !== false) {
|
||||
$funcs = array();
|
||||
|
||||
$name = substr($func, 0, $pos);
|
||||
$func = substr($func, ($pos + 1), -1);
|
||||
$params = $this->_tokenizer->bracketExplode($func, ',', '(', ')');
|
||||
|
||||
foreach ($params as $k => $param) {
|
||||
$params[$k] = $this->parseAggregateFunction($param);
|
||||
}
|
||||
|
||||
$funcs = $name . '(' . implode(', ', $params) . ')';
|
||||
|
||||
return $funcs;
|
||||
|
||||
} else {
|
||||
if ( ! is_numeric($func)) {
|
||||
$a = explode('.', $func);
|
||||
|
||||
if (count($a) > 1) {
|
||||
$field = array_pop($a);
|
||||
$reference = implode('.', $a);
|
||||
$map = $this->query->load($reference, false);
|
||||
$field = $map['table']->getColumnName($field);
|
||||
$func = $this->query->getTableAlias($reference) . '.' . $field;
|
||||
} else {
|
||||
$field = end($a);
|
||||
$func = $this->query->getAggregateAlias($field);
|
||||
}
|
||||
return $func;
|
||||
} else {
|
||||
return $func;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* load
|
||||
* returns the parsed query part
|
||||
*
|
||||
* @param string $having
|
||||
* @return string
|
||||
*/
|
||||
final public function load($having)
|
||||
{
|
||||
$tokens = $this->_tokenizer->bracketExplode($having, ' ', '(', ')');
|
||||
$part = $this->parseAggregateFunction(array_shift($tokens));
|
||||
$operator = array_shift($tokens);
|
||||
$value = implode(' ', $tokens);
|
||||
$part .= ' ' . $operator . ' ' . $value;
|
||||
// check the RHS for aggregate functions
|
||||
if (strpos($value, '(') !== false) {
|
||||
$value = $this->parseAggregateFunction($value);
|
||||
}
|
||||
return $part;
|
||||
}
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
Doctrine::autoload('Doctrine_Query_Part');
|
||||
/**
|
||||
* Doctrine_Query_JoinCondition
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*/
|
||||
class Doctrine_Query_JoinCondition extends Doctrine_Query_Condition
|
||||
{
|
||||
public function load($condition)
|
||||
{
|
||||
$condition = trim($condition);
|
||||
|
||||
$e = $this->_tokenizer->sqlExplode($condition);
|
||||
|
||||
if (count($e) > 2) {
|
||||
$a = explode('.', $e[0]);
|
||||
$field = array_pop($a);
|
||||
$reference = implode('.', $a);
|
||||
$operator = $e[1];
|
||||
$value = $e[2];
|
||||
|
||||
$conn = $this->query->getConnection();
|
||||
$alias = $this->query->getTableAlias($reference);
|
||||
$map = $this->query->getAliasDeclaration($reference);
|
||||
$table = $map['table'];
|
||||
// check if value is enumerated value
|
||||
$enumIndex = $table->enumIndex($field, trim($value, "'"));
|
||||
|
||||
if (false !== $enumIndex && $conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)) {
|
||||
$enumIndex = $conn->quote($enumIndex, 'text');
|
||||
}
|
||||
|
||||
if (substr($value, 0, 1) == '(') {
|
||||
// trim brackets
|
||||
$trimmed = $this->_tokenizer->bracketTrim($value);
|
||||
|
||||
if (substr($trimmed, 0, 4) == 'FROM' || substr($trimmed, 0, 6) == 'SELECT') {
|
||||
// subquery found
|
||||
$q = $this->query->createSubquery();
|
||||
$value = '(' . $q->parseQuery($trimmed)->getQuery() . ')';
|
||||
} elseif (substr($trimmed, 0, 4) == 'SQL:') {
|
||||
$value = '(' . substr($trimmed, 4) . ')';
|
||||
} else {
|
||||
// simple in expression found
|
||||
$e = $this->_tokenizer->sqlExplode($trimmed, ',');
|
||||
|
||||
$value = array();
|
||||
foreach ($e as $part) {
|
||||
$index = $table->enumIndex($field, trim($part, "'"));
|
||||
|
||||
if (false !== $index && $conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)) {
|
||||
$index = $conn->quote($index, 'text');
|
||||
}
|
||||
|
||||
if ($index !== false) {
|
||||
$value[] = $index;
|
||||
} else {
|
||||
$value[] = $this->parseLiteralValue($part);
|
||||
}
|
||||
}
|
||||
$value = '(' . implode(', ', $value) . ')';
|
||||
}
|
||||
} else {
|
||||
if ($enumIndex !== false) {
|
||||
$value = $enumIndex;
|
||||
} else {
|
||||
$value = $this->parseLiteralValue($value);
|
||||
}
|
||||
}
|
||||
|
||||
switch ($operator) {
|
||||
case '<':
|
||||
case '>':
|
||||
case '=':
|
||||
case '!=':
|
||||
if ($enumIndex !== false) {
|
||||
$value = $enumIndex;
|
||||
}
|
||||
default:
|
||||
$condition = $alias . '.' . $field . ' '
|
||||
. $operator . ' ' . $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $condition;
|
||||
}
|
||||
}
|
@ -1,35 +1,323 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Doctrine_Query_Parser
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Parser
|
||||
{
|
||||
|
||||
}
|
||||
<?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 1.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;
|
||||
|
||||
// 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($dql, Doctrine_Connection $connection = null)
|
||||
{
|
||||
$this->_scanner = new Doctrine_Query_Scanner($dql);
|
||||
$this->_parserResult = new Doctrine_Query_ParserResult();
|
||||
$this->_sqlBuilder = Doctrine_Query_SqlBuilder::fromConnection($connection);
|
||||
$this->_keywordTable = new Doctrine_Query_Token();
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo [TODO] Document these!
|
||||
*/
|
||||
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 SQL 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,39 +1,35 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id: Where.php 1352 2007-05-15 10:07:05Z zYne $
|
||||
*
|
||||
* 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_Query_Offset
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision: 1352 $
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*/
|
||||
class Doctrine_Query_Offset extends Doctrine_Query_Part
|
||||
{
|
||||
public function parse($offset)
|
||||
{
|
||||
return (int) $offset;
|
||||
}
|
||||
}
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Doctrine_Query_Parser_Exception
|
||||
*
|
||||
* @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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Parser_Exception extends Doctrine_Exception
|
||||
{
|
||||
}
|
86
lib/Doctrine/Query/ParserResult.php
Executable file
86
lib/Doctrine/Query/ParserResult.php
Executable file
@ -0,0 +1,86 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
Doctrine::autoload('Doctrine_Query_AbstractResult');
|
||||
|
||||
/**
|
||||
* Doctrine_Query_ParserResult
|
||||
*
|
||||
* @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_ParserResult extends Doctrine_Query_AbstractResult
|
||||
{
|
||||
/**
|
||||
* A simple array keys representing table aliases and values table alias
|
||||
* seeds. The seeds are used for generating short table aliases.
|
||||
*
|
||||
* @var array $_tableAliasSeeds
|
||||
*/
|
||||
protected $_tableAliasSeeds = array();
|
||||
|
||||
|
||||
/**
|
||||
* @nodoc
|
||||
*/
|
||||
public function setSqlExecutor(Doctrine_Query_SqlExecutor_Abstract $executor)
|
||||
{
|
||||
$this->_data = $executor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @nodoc
|
||||
*/
|
||||
public function getSqlExecutor()
|
||||
{
|
||||
return $this->_data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a table alias from given table name and associates
|
||||
* it with given component alias
|
||||
*
|
||||
* @param string $componentName Component name to be associated with generated table alias
|
||||
* @return string Generated table alias
|
||||
*/
|
||||
public function generateTableAlias($componentName)
|
||||
{
|
||||
$baseAlias = strtolower(preg_replace('/[^A-Z]/', '\\1', $componentName));
|
||||
|
||||
$alias = $baseAlias;
|
||||
|
||||
if ( ! isset($this->_tableAliasSeeds[$baseAlias])) {
|
||||
$this->_tableAliasSeeds[$baseAlias] = 1;
|
||||
} else {
|
||||
$alias .= $this->_tableAliasSeeds[$baseAlias]++;
|
||||
}
|
||||
|
||||
return $alias;
|
||||
}
|
||||
}
|
95
lib/Doctrine/Query/Printer.php
Normal file
95
lib/Doctrine/Query/Printer.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A parse tree printer for Doctrine Query Language parser.
|
||||
*
|
||||
* @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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Printer
|
||||
{
|
||||
/**
|
||||
* Current indentation level
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_indent = 0;
|
||||
|
||||
/**
|
||||
* Defines whether parse tree is printed (default, false) or not (true).
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_silent;
|
||||
|
||||
/**
|
||||
* Constructs a new parse tree printer.
|
||||
*
|
||||
* @param bool $silent Parse tree will not be printed if true.
|
||||
*/
|
||||
public function __construct($silent = false)
|
||||
{
|
||||
$this->_silent = $silent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints an opening parenthesis followed by production name and increases
|
||||
* indentation level by one.
|
||||
*
|
||||
* This method is called before executing a production.
|
||||
*
|
||||
* @param string $name production name
|
||||
*/
|
||||
public function startProduction($name)
|
||||
{
|
||||
$this->println('(' . $name);
|
||||
$this->_indent++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decreases indentation level by one and prints a closing parenthesis.
|
||||
*
|
||||
* This method is called after executing a production.
|
||||
*/
|
||||
public function endProduction()
|
||||
{
|
||||
$this->_indent--;
|
||||
$this->println(')');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints text indented with spaces depending on current indentation level.
|
||||
*
|
||||
* @param string $str text
|
||||
*/
|
||||
public function println($str)
|
||||
{
|
||||
if ( ! $this->_silent) {
|
||||
echo str_repeat(' ', $this->_indent), $str, "\n";
|
||||
}
|
||||
}
|
||||
}
|
224
lib/Doctrine/Query/Production.php
Normal file
224
lib/Doctrine/Query/Production.php
Normal file
@ -0,0 +1,224 @@
|
||||
<?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 abstract base class for the productions of the Doctrine Query Language
|
||||
* context-free grammar.
|
||||
*
|
||||
* @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$
|
||||
*/
|
||||
abstract class Doctrine_Query_Production
|
||||
{
|
||||
/**
|
||||
* Parser object
|
||||
*
|
||||
* @var Doctrine_Query_Parser
|
||||
*/
|
||||
protected $_parser;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new production object.
|
||||
*
|
||||
* @param Doctrine_Query_Parser $parser a parser object
|
||||
*/
|
||||
public function __construct(Doctrine_Query_Parser $parser)
|
||||
{
|
||||
$this->_parser = $parser;
|
||||
}
|
||||
|
||||
|
||||
protected function _isNextToken($token)
|
||||
{
|
||||
$la = $this->_parser->lookahead;
|
||||
return ($la['type'] === $token || $la['value'] === $token);
|
||||
}
|
||||
|
||||
|
||||
protected function _isFunction()
|
||||
{
|
||||
$la = $this->_parser->lookahead;
|
||||
$next = $this->_parser->getScanner()->peek();
|
||||
return ($la['type'] === Doctrine_Query_Token::T_IDENTIFIER && $next['value'] === '(');
|
||||
}
|
||||
|
||||
|
||||
protected function _isSubselect()
|
||||
{
|
||||
$la = $this->_parser->lookahead;
|
||||
$next = $this->_parser->getScanner()->peek();
|
||||
return ($la['value'] === '(' && $next['type'] === Doctrine_Query_Token::T_SELECT);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes the production AST using the specified parameters.
|
||||
*
|
||||
* @param string $AstName Production AST name
|
||||
* @param array $paramHolder Production parameter holder
|
||||
* @return Doctrine_Query_Production
|
||||
*/
|
||||
public function AST($AstName, $paramHolder)
|
||||
{
|
||||
$AST = $this->_getProduction($AstName);
|
||||
|
||||
//echo "Processing class: " . get_class($AST) . "...\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";
|
||||
|
||||
$return = $AST->syntax($paramHolder);
|
||||
|
||||
if ($return !== null) {
|
||||
//echo "Returning AST class: " . (is_object($return) ? get_class($return) : $return) . "...\n";
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
||||
// Semantical check
|
||||
if ( ! $paramHolder->has('semanticalCheck') || $paramHolder->get('semanticalCheck') === true) {
|
||||
//echo "Processing semantical checks of " . $AstName . "...\n";
|
||||
|
||||
$return = $AST->semantical($paramHolder);
|
||||
|
||||
if ($return !== null) {
|
||||
//echo "Returning AST class: " . (is_object($return) ? get_class($return) : $return) . "...\n";
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
||||
//echo "Returning AST class: " . get_class($AST) . "...\n";
|
||||
|
||||
return $AST;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a production object with the given name.
|
||||
*
|
||||
* @param string $name production name
|
||||
* @return Doctrine_Query_Production
|
||||
*/
|
||||
protected function _getProduction($name)
|
||||
{
|
||||
$class = 'Doctrine_Query_Production_' . $name;
|
||||
|
||||
return new $class($this->_parser);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes a production with specified name and parameters.
|
||||
*
|
||||
* @param string $name production name
|
||||
* @param array $params an associative array containing parameter names and
|
||||
* their values
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if (substr($method, 0, 3) === 'get') {
|
||||
$var = '_' . substr($method, 3);
|
||||
$var[1] = strtolower($var[1]);
|
||||
|
||||
return $this->$var;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes this production using the specified parameters.
|
||||
*
|
||||
* @param array $paramHolder Production parameter holder
|
||||
* @return Doctrine_Query_Production
|
||||
*/
|
||||
public function execute($paramHolder)
|
||||
{
|
||||
//echo "Processing class: " . get_class($this) . " params: \n" . var_export($paramHolder, true) . "\n";
|
||||
|
||||
// Syntax check
|
||||
if ( ! $paramHolder->has('syntaxCheck') || $paramHolder->get('syntaxCheck') === true) {
|
||||
//echo "Processing syntax checks of " . get_class($this) . "...\n";
|
||||
|
||||
$return = $this->syntax($paramHolder);
|
||||
|
||||
if ($return !== null) {
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
abstract public function syntax($paramHolder);
|
||||
|
||||
|
||||
/**
|
||||
* @nodoc
|
||||
*/
|
||||
public function semantical($paramHolder)
|
||||
{
|
||||
}
|
||||
}
|
84
lib/Doctrine/Query/Production/AggregateExpression.php
Normal file
84
lib/Doctrine/Query/Production/AggregateExpression.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* AggregateExpression = ("AVG" | "MAX" | "MIN" | "SUM" | "COUNT") "(" ["DISTINCT"] Expression ")"
|
||||
*
|
||||
* @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_Production_AggregateExpression extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_functionName;
|
||||
|
||||
protected $_isDistinct;
|
||||
|
||||
protected $_expression;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// AggregateExpression = ("AVG" | "MAX" | "MIN" | "SUM" | "COUNT") "(" ["DISTINCT"] Expression ")"
|
||||
$this->_isDistinct = false;
|
||||
$token = $this->_parser->lookahead;
|
||||
|
||||
switch ($token['type']) {
|
||||
case Doctrine_Query_Token::T_AVG:
|
||||
case Doctrine_Query_Token::T_MAX:
|
||||
case Doctrine_Query_Token::T_MIN:
|
||||
case Doctrine_Query_Token::T_SUM:
|
||||
case Doctrine_Query_Token::T_COUNT:
|
||||
$this->_parser->match($token['type']);
|
||||
$this->_functionName = strtoupper($token['value']);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->_parser->logError('AVG, MAX, MIN, SUM or COUNT');
|
||||
break;
|
||||
}
|
||||
|
||||
$this->_parser->match('(');
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_DISTINCT)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_DISTINCT);
|
||||
$this->_isDistinct = true;
|
||||
}
|
||||
|
||||
$this->_expression = $this->AST('Expression', $paramHolder);
|
||||
|
||||
$this->_parser->match(')');
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return $this->_functionName
|
||||
. '(' . (($this->_isDistinct) ? 'DISTINCT ' : '')
|
||||
. $this->_expression->buildSql()
|
||||
. ')';
|
||||
}
|
||||
}
|
95
lib/Doctrine/Query/Production/Atom.php
Normal file
95
lib/Doctrine/Query/Production/Atom.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Atom = string | integer | float | input_parameter
|
||||
*
|
||||
* @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_Production_Atom extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_type;
|
||||
|
||||
protected $_value;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// Atom = string | integer | float | input_parameter
|
||||
switch ($this->_parser->lookahead['type']) {
|
||||
case Doctrine_Query_Token::T_STRING:
|
||||
$this->_parser->match(Doctrine_Query_Token::T_STRING);
|
||||
$this->_type = 'string';
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_INTEGER:
|
||||
$this->_parser->match(Doctrine_Query_Token::T_INTEGER);
|
||||
$this->_type = 'integer';
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_FLOAT:
|
||||
$this->_parser->match(Doctrine_Query_Token::T_FLOAT);
|
||||
$this->_type = 'float';
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_INPUT_PARAMETER:
|
||||
$this->_parser->match(Doctrine_Query_Token::T_INPUT_PARAMETER);
|
||||
$this->_type = 'param';
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->_parser->syntaxError('string, number or parameter (? or :)');
|
||||
break;
|
||||
}
|
||||
|
||||
$this->_value = $this->_parser->token['value'];
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
$conn = $this->_parser->getSqlBuilder()->getConnection();
|
||||
|
||||
switch ($this->_type) {
|
||||
case 'param':
|
||||
return $this->_value;
|
||||
break;
|
||||
|
||||
case 'integer':
|
||||
case 'float':
|
||||
return $conn->quote($this->_value, $this->_type);
|
||||
break;
|
||||
|
||||
default:
|
||||
return $conn->string_quoting['start']
|
||||
. $conn->quote($this->_value, $this->_type)
|
||||
. $conn->string_quoting['end'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
68
lib/Doctrine/Query/Production/BetweenExpression.php
Normal file
68
lib/Doctrine/Query/Production/BetweenExpression.php
Normal 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* BetweenExpression = ["NOT"] "BETWEEN" Expression "AND" Expression
|
||||
*
|
||||
* @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_Production_BetweenExpression extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_not;
|
||||
|
||||
protected $_fromExpression;
|
||||
|
||||
protected $_toExpression;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// BetweenExpression = ["NOT"] "BETWEEN" Expression "AND" Expression
|
||||
$this->_not = false;
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_NOT)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_NOT);
|
||||
$this->_not = true;
|
||||
}
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_BETWEEN);
|
||||
|
||||
$this->_fromExpression = $this->AST('Expression', $paramHolder);
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_AND);
|
||||
|
||||
$this->_toExpression = $this->AST('Expression', $paramHolder);
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return (($this->_not) ? 'NOT ' : '') . 'BETWEEN '
|
||||
. $this->_fromExpression->buildSql() . ' AND ' . $this->_toExpression->buildSql();
|
||||
}
|
||||
}
|
75
lib/Doctrine/Query/Production/ComparisonExpression.php
Normal file
75
lib/Doctrine/Query/Production/ComparisonExpression.php
Normal 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ComparisonExpression = ComparisonOperator ( QuantifiedExpression | Expression | "(" Subselect ")" )
|
||||
*
|
||||
* @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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_ComparisonExpression extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_operator;
|
||||
|
||||
protected $_expression;
|
||||
|
||||
protected $_isSubselect;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// ComparisonExpression = ComparisonOperator ( QuantifiedExpression | Expression | "(" Subselect ")" )
|
||||
$this->_operator = $this->AST('ComparisonOperator', $paramHolder);
|
||||
|
||||
if (($this->_isSubselect = $this->_isSubselect()) === true) {
|
||||
$this->_parser->match('(');
|
||||
$this->_expression = $this->AST('Subselect', $paramHolder);
|
||||
$this->_parser->match(')');
|
||||
|
||||
$this->_isSubselect = true;
|
||||
} else {
|
||||
switch ($this->_parser->lookahead['type']) {
|
||||
case Doctrine_Query_Token::T_ALL:
|
||||
case Doctrine_Query_Token::T_ANY:
|
||||
case Doctrine_Query_Token::T_SOME:
|
||||
$this->_expression = $this->AST('QuantifiedExpression', $paramHolder);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->_expression = $this->AST('Expression', $paramHolder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return $this->_operator . ' ' . (($this->_isSubselect) ?
|
||||
'(' . $this->_expression->buildSql() . ')' : $this->_expression->buildSql()
|
||||
);
|
||||
}
|
||||
}
|
81
lib/Doctrine/Query/Production/ComparisonOperator.php
Normal file
81
lib/Doctrine/Query/Production/ComparisonOperator.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ComparisonOperator = "=" | "<" | "<=" | "<>" | ">" | ">=" | "!="
|
||||
*
|
||||
* @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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_ComparisonOperator extends Doctrine_Query_Production
|
||||
{
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
switch ($this->_parser->lookahead['value']) {
|
||||
case '=':
|
||||
$this->_parser->match('=');
|
||||
return '=';
|
||||
break;
|
||||
|
||||
case '<':
|
||||
$this->_parser->match('<');
|
||||
$operator = '<';
|
||||
|
||||
if ($this->_isNextToken('=')) {
|
||||
$this->_parser->match('=');
|
||||
$operator .= '=';
|
||||
} elseif ($this->_isNextToken('>')) {
|
||||
$this->_parser->match('>');
|
||||
$operator .= '>';
|
||||
}
|
||||
|
||||
return $operator;
|
||||
break;
|
||||
|
||||
case '>':
|
||||
$this->_parser->match('>');
|
||||
$operator = '>';
|
||||
|
||||
if ($this->_isNextToken('=')) {
|
||||
$this->_parser->match('=');
|
||||
$operator .= '=';
|
||||
}
|
||||
|
||||
return $operator;
|
||||
break;
|
||||
|
||||
case '!':
|
||||
$this->_parser->match('!');
|
||||
$this->_parser->match('=');
|
||||
return '<>';
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->_parser->syntaxError('=, <, <=, <>, >, >=, !=');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
72
lib/Doctrine/Query/Production/ConditionalExpression.php
Normal file
72
lib/Doctrine/Query/Production/ConditionalExpression.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ConditionalExpression = ConditionalTerm {"OR" ConditionalTerm}
|
||||
*
|
||||
* @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_Production_ConditionalExpression extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_conditionalTerms = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// ConditionalExpression = ConditionalTerm {"OR" ConditionalTerm}
|
||||
$this->_conditionalTerms[] = $this->AST('ConditionalTerm', $paramHolder);
|
||||
|
||||
while ($this->_isNextToken(Doctrine_Query_Token::T_OR)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_OR);
|
||||
$this->_conditionalTerms[] = $this->AST('ConditionalTerm', $paramHolder);
|
||||
}
|
||||
|
||||
// Optimize depth instances in AST
|
||||
if (count($this->_conditionalTerms) == 1) {
|
||||
return $this->_conditionalTerms[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return implode(' OR ', $this->_mapConditionalTerms());
|
||||
}
|
||||
|
||||
|
||||
protected function _mapConditionalTerms()
|
||||
{
|
||||
return array_map(array(&$this, '_mapConditionalTerm'), $this->_conditionalTerms);
|
||||
}
|
||||
|
||||
|
||||
protected function _mapConditionalTerm($value)
|
||||
{
|
||||
return $value->buildSql();
|
||||
}
|
||||
}
|
63
lib/Doctrine/Query/Production/ConditionalFactor.php
Normal file
63
lib/Doctrine/Query/Production/ConditionalFactor.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ConditionalFactor = ["NOT"] ConditionalPrimary
|
||||
*
|
||||
* @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_Production_ConditionalFactor extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_conditionalPrimary;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// ConditionalFactor = ["NOT"] ConditionalPrimary
|
||||
$notFactor = false;
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_NOT)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_NOT);
|
||||
$notFactor = true;
|
||||
}
|
||||
|
||||
$this->_conditionalPrimary = $this->AST('ConditionalPrimary', $paramHolder);
|
||||
|
||||
// Optimize depth instances in AST
|
||||
if ( ! $notFactor) {
|
||||
return $this->_conditionalPrimary;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
// Do not need to check $notFactor. It'll be always present if we have this instance.
|
||||
return 'NOT ' . $this->_conditionalPrimary->buildSql();
|
||||
}
|
||||
}
|
101
lib/Doctrine/Query/Production/ConditionalPrimary.php
Normal file
101
lib/Doctrine/Query/Production/ConditionalPrimary.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ConditionalPrimary = SimpleConditionalExpression | "(" ConditionalExpression ")"
|
||||
*
|
||||
* @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_Production_ConditionalPrimary extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_conditionalExpression;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// ConditionalPrimary = SimpleConditionalExpression | "(" ConditionalExpression ")"
|
||||
if ( ! $this->_isConditionalExpression()) {
|
||||
return $this->AST('SimpleConditionalExpression', $paramHolder);
|
||||
}
|
||||
|
||||
$this->_parser->match('(');
|
||||
$this->_conditionalExpression = $this->AST('ConditionalExpression', $paramHolder);
|
||||
$this->_parser->match(')');
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return '(' . $this->_conditionalExpression->buildSql() . ')';
|
||||
}
|
||||
|
||||
|
||||
protected function _isConditionalExpression()
|
||||
{
|
||||
$token = $this->_parser->lookahead;
|
||||
$parenthesis = 0;
|
||||
|
||||
if ($token['value'] === '(') {
|
||||
$parenthesis++;
|
||||
}
|
||||
|
||||
while ($parenthesis > 0) {
|
||||
$token = $this->_parser->getScanner()->peek();
|
||||
|
||||
if ($token['value'] === '(') {
|
||||
$parenthesis++;
|
||||
} elseif ($token['value'] === ')') {
|
||||
$parenthesis--;
|
||||
} else {
|
||||
switch ($token['type']) {
|
||||
case Doctrine_Query_Token::T_NOT:
|
||||
case Doctrine_Query_Token::T_AND:
|
||||
case Doctrine_Query_Token::T_OR:
|
||||
case Doctrine_Query_Token::T_BETWEEN:
|
||||
case Doctrine_Query_Token::T_LIKE:
|
||||
case Doctrine_Query_Token::T_IN:
|
||||
case Doctrine_Query_Token::T_IS:
|
||||
case Doctrine_Query_Token::T_EXISTS:
|
||||
return true;
|
||||
|
||||
case Doctrine_Query_Token::T_NONE:
|
||||
switch ($token['value']) {
|
||||
case '=':
|
||||
case '<':
|
||||
case '>':
|
||||
case '!':
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
72
lib/Doctrine/Query/Production/ConditionalTerm.php
Normal file
72
lib/Doctrine/Query/Production/ConditionalTerm.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ConditionalTerm = ConditionalFactor {"AND" ConditionalFactor}
|
||||
*
|
||||
* @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_Production_ConditionalTerm extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_conditionalFactors = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// ConditionalTerm = ConditionalFactor {"AND" ConditionalFactor}
|
||||
$this->_conditionalFactors[] = $this->AST('ConditionalFactor', $paramHolder);
|
||||
|
||||
while ($this->_isNextToken(Doctrine_Query_Token::T_AND)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_AND);
|
||||
$this->_conditionalFactors[] = $this->AST('ConditionalFactor', $paramHolder);
|
||||
}
|
||||
|
||||
// Optimize depth instances in AST
|
||||
if (count($this->_conditionalFactors) == 1) {
|
||||
return $this->_conditionalFactors[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return implode(' AND ', $this->_mapConditionalFactors());
|
||||
}
|
||||
|
||||
|
||||
protected function _mapConditionalFactors()
|
||||
{
|
||||
return array_map(array(&$this, '_mapConditionalFactor'), $this->_conditionalFactors);
|
||||
}
|
||||
|
||||
|
||||
protected function _mapConditionalFactor($value)
|
||||
{
|
||||
return $value->buildSql();
|
||||
}
|
||||
}
|
@ -1,61 +1,56 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Doctrine_Query_Part
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*/
|
||||
abstract class Doctrine_Query_Part
|
||||
{
|
||||
/**
|
||||
* @var Doctrine_Query $query the query object associated with this parser
|
||||
*/
|
||||
protected $query;
|
||||
|
||||
protected $_tokenizer;
|
||||
|
||||
/**
|
||||
* @param Doctrine_Query $query the query object associated with this parser
|
||||
*/
|
||||
public function __construct($query, Doctrine_Query_Tokenizer $tokenizer = null)
|
||||
{
|
||||
$this->query = $query;
|
||||
if ( ! $tokenizer) {
|
||||
$tokenizer = new Doctrine_Query_Tokenizer();
|
||||
}
|
||||
$this->_tokenizer = $tokenizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Doctrine_Query $query the query object associated with this parser
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
}
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DeleteClause = "DELETE" ["FROM"] VariableDeclaration
|
||||
*
|
||||
* @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_Production_DeleteClause extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_variableDeclaration;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// DeleteClause = "DELETE" ["FROM"] VariableDeclaration
|
||||
$this->_parser->match(Doctrine_Query_Token::T_DELETE);
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_FROM)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_FROM);
|
||||
}
|
||||
|
||||
$this->_variableDeclaration = $this->AST('VariableDeclaration', $paramHolder);
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return 'DELETE FROM ' . $this->_variableDeclaration->buildSql();
|
||||
}
|
||||
}
|
59
lib/Doctrine/Query/Production/DeleteStatement.php
Normal file
59
lib/Doctrine/Query/Production/DeleteStatement.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_DeleteStatement extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_deleteClause;
|
||||
|
||||
protected $_whereClause;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// DeleteStatement = DeleteClause [WhereClause]
|
||||
$this->_deleteClause = $this->AST('DeleteClause', $paramHolder);
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_WHERE)) {
|
||||
$this->_whereClause = $this->AST('WhereClause', $paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
54
lib/Doctrine/Query/Production/ExistsExpression.php
Normal file
54
lib/Doctrine/Query/Production/ExistsExpression.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ExistsExpression = "EXISTS" "(" Subselect ")"
|
||||
*
|
||||
* @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_Production_ExistsExpression extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_subselect;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// ExistsExpression = "EXISTS" "(" Subselect ")"
|
||||
$this->_parser->match(Doctrine_Query_Token::T_EXISTS);
|
||||
|
||||
$this->_parser->match('(');
|
||||
$this->_subselect = $this->AST('Subselect', $paramHolder);
|
||||
$this->_parser->match(')');
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return 'EXISTS (' . $this->_subselect->buildSql() . ')';
|
||||
}
|
||||
}
|
79
lib/Doctrine/Query/Production/Expression.php
Normal file
79
lib/Doctrine/Query/Production/Expression.php
Normal 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Expression = Term {("+" | "-") Term}
|
||||
*
|
||||
* @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_Production_Expression extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_terms = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// Expression = Term {("+" | "-") Term}
|
||||
$this->_terms[] = $this->AST('Term', $paramHolder);
|
||||
|
||||
while ($this->_isNextToken('+') || $this->_isNextToken('-')) {
|
||||
if ($this->_isNextToken('+')) {
|
||||
$this->_parser->match('+');
|
||||
$this->_terms[] = '+';
|
||||
} else{
|
||||
$this->_parser->match('-');
|
||||
$this->_terms[] = '-';
|
||||
}
|
||||
|
||||
$this->_terms[] = $this->AST('Term', $paramHolder);
|
||||
}
|
||||
|
||||
// Optimize depth instances in AST
|
||||
if (count($this->_terms) == 1) {
|
||||
return $this->_terms[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return implode(' ', $this->_mapTerms());
|
||||
}
|
||||
|
||||
|
||||
protected function _mapTerms()
|
||||
{
|
||||
return array_map(array(&$this, '_mapTerm'), $this->_terms);
|
||||
}
|
||||
|
||||
|
||||
protected function _mapTerm($value)
|
||||
{
|
||||
return (is_string($value) ? $value : $value->buildSql());
|
||||
}
|
||||
}
|
65
lib/Doctrine/Query/Production/Factor.php
Normal file
65
lib/Doctrine/Query/Production/Factor.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Factor = [("+" | "-")] Primary
|
||||
*
|
||||
* @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_Production_Factor extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_type;
|
||||
|
||||
protected $_primary;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// Factor = [("+" | "-")] Primary
|
||||
if ($this->_isNextToken('+')) {
|
||||
$this->_parser->match('+');
|
||||
$this->_type = '+';
|
||||
} elseif ($this->_isNextToken('-')) {
|
||||
$this->_parser->match('-');
|
||||
$this->_type = '-';
|
||||
}
|
||||
|
||||
$this->_primary = $this->AST('Primary', $paramHolder);
|
||||
|
||||
// Optimize depth instances in AST
|
||||
if ($this->_type === null) {
|
||||
return $this->_primary;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return $this->_type . ' ' . $this->_primary->buildSql();
|
||||
}
|
||||
}
|
74
lib/Doctrine/Query/Production/FromClause.php
Normal file
74
lib/Doctrine/Query/Production/FromClause.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?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_Production_FromClause extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_identificationVariableDeclaration = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// FromClause = "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}
|
||||
$this->_parser->match(Doctrine_Query_Token::T_FROM);
|
||||
|
||||
$this->_identificationVariableDeclaration[] = $this->AST('IdentificationVariableDeclaration', $paramHolder);
|
||||
|
||||
while ($this->_isNextToken(',')) {
|
||||
$this->_parser->match(',');
|
||||
$this->_identificationVariableDeclaration[] = $this->AST('IdentificationVariableDeclaration', $paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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->_identificationVariableDeclaration);
|
||||
}
|
||||
|
||||
|
||||
protected function _mapIdentificationVariableDeclaration($value)
|
||||
{
|
||||
return $value->buildSql();
|
||||
}
|
||||
}
|
79
lib/Doctrine/Query/Production/Function.php
Normal file
79
lib/Doctrine/Query/Production/Function.php
Normal 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function = identifier "(" [Expression {"," Expression}] ")"
|
||||
*
|
||||
* @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_Production_Function extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_functionName;
|
||||
|
||||
protected $_arguments = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// Function = identifier "(" [Expression {"," Expression}] ")"
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
$this->_functionName = $this->_parser->token['value'];
|
||||
|
||||
$this->_parser->match('(');
|
||||
|
||||
if ( ! $this->_isNextToken(')')) {
|
||||
$this->_arguments[] = $this->AST('Expression', $paramHolder);
|
||||
|
||||
while ($this->_isNextToken(',')) {
|
||||
$this->_parser->match(',');
|
||||
|
||||
$this->_arguments[] = $this->AST('Expression', $paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_parser->match(')');
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return $this->_functionName . '(' . implode(', ', $this->_mapArguments()) . ')';
|
||||
}
|
||||
|
||||
|
||||
protected function _mapArguments()
|
||||
{
|
||||
return array_map(array(&$this, '_mapArgument'), $this->_arguments);
|
||||
}
|
||||
|
||||
|
||||
protected function _mapArgument($value)
|
||||
{
|
||||
return $value->buildSql();
|
||||
}
|
||||
}
|
69
lib/Doctrine/Query/Production/GroupByClause.php
Normal file
69
lib/Doctrine/Query/Production/GroupByClause.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GroupByClause = "GROUP" "BY" GroupByItem {"," GroupByItem}
|
||||
*
|
||||
* @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_Production_GroupByClause extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_groupByItems = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
$this->_parser->match(Doctrine_Query_Token::T_GROUP);
|
||||
$this->_parser->match(Doctrine_Query_Token::T_BY);
|
||||
|
||||
$this->_groupByItems[] = $this->AST('GroupByItem', $paramHolder);
|
||||
|
||||
while ($this->_isNextToken(',')) {
|
||||
$this->_parser->match(',');
|
||||
$this->_groupByItems[] = $this->AST('GroupByItem', $paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return 'GROUP BY ' . implode(', ', $this->_mapGroupByItems()) . ')';
|
||||
}
|
||||
|
||||
|
||||
protected function _mapGroupByItems()
|
||||
{
|
||||
return array_map(array(&$this, '_mapGroupByItem'), $this->_groupByItems);
|
||||
}
|
||||
|
||||
|
||||
protected function _mapGroupByItem($value)
|
||||
{
|
||||
return $value->buildSql();
|
||||
}
|
||||
}
|
@ -1,39 +1,40 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id: From.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::autoload("Doctrine_Query_Part");
|
||||
/**
|
||||
* Doctrine_Query_Select
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @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_Query_Select extends Doctrine_Query_Part
|
||||
{
|
||||
public function parse($dql)
|
||||
{
|
||||
$this->query->parseSelect($dql);
|
||||
}
|
||||
}
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* OrderByItem = PathExpression
|
||||
*
|
||||
* @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_Production_GroupByItem extends Doctrine_Query_Production
|
||||
{
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
return $this->AST('PathExpression', $paramHolder);
|
||||
}
|
||||
}
|
52
lib/Doctrine/Query/Production/HavingClause.php
Normal file
52
lib/Doctrine/Query/Production/HavingClause.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* HavingClause = "HAVING" ConditionalExpression
|
||||
*
|
||||
* @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_Production_HavingClause extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_conditionalExpression;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// HavingClause = "HAVING" ConditionalExpression
|
||||
$this->_parser->match(Doctrine_Query_Token::T_HAVING);
|
||||
|
||||
$this->_conditionalExpression = $this->AST('ConditionalExpression', $paramHolder);
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return 'HAVING ' . $this->_conditionalExpression->buildSql();
|
||||
}
|
||||
}
|
64
lib/Doctrine/Query/Production/IdentificationVariable.php
Normal file
64
lib/Doctrine/Query/Production/IdentificationVariable.php
Normal 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 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_Production_IdentificationVariable extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_componentAlias;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// IdentificationVariable = identifier
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
$this->_componentAlias = $this->_parser->token['value'];
|
||||
}
|
||||
|
||||
|
||||
public function semantical($paramHolder)
|
||||
{
|
||||
$parserResult = $this->_parser->getParserResult();
|
||||
|
||||
if ($parserResult->hasQueryComponent($this->_componentAlias)) {
|
||||
// We should throw semantical error if there's already a component for this alias
|
||||
$queryComponent = $parserResult->getQueryComponent($this->_componentAlias);
|
||||
$componentName = $queryComponent['metadata']->getClassName();
|
||||
|
||||
$message = "Cannot re-declare component alias '{$this->_componentAlias}'"
|
||||
. "for '".$paramHolder->get('componentName')."'. It was already declared for "
|
||||
. "component '{$componentName}'.";
|
||||
|
||||
$this->_parser->semanticalError($message);
|
||||
}
|
||||
|
||||
return $this->_componentAlias;
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
<?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] {Join [IndexBy]}
|
||||
*
|
||||
* @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_Production_IdentificationVariableDeclaration extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_rangeVariableDeclaration;
|
||||
|
||||
protected $_indexBy;
|
||||
|
||||
protected $_relations = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
$this->_rangeVariableDeclaration = $this->AST('RangeVariableDeclaration', $paramHolder);
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_INDEX)) {
|
||||
$paramHolder->set('componentAlias', $this->_rangeVariableDeclaration);
|
||||
$this->_indexBy = $this->AST('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)
|
||||
) {
|
||||
$i = count($this->_relations);
|
||||
|
||||
$this->_relations[$i]['join'] = $this->AST('Join', $paramHolder);
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_INDEX)) {
|
||||
$paramHolder->set('componentAlias', $this->_relations[$i]['join']->getRangeVariableDeclaration());
|
||||
$this->_relations[$i]['indexBy'] = $this->AST('IndexBy', $paramHolder);
|
||||
$paramHolder->remove('componentAlias');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
// We need to bring the queryComponent and get things from there.
|
||||
$parserResult = $this->_parser->getParserResult();
|
||||
$queryComponent = $parserResult->getQueryComponent($this->_rangeVariableDeclaration);
|
||||
|
||||
// Retrieving connection
|
||||
$conn = $this->_parser->getSqlBuilder()->getConnection();
|
||||
$manager = Doctrine_Manager::getInstance();
|
||||
|
||||
if ($manager->hasConnectionForComponent($queryComponent['metadata']->getClassName())) {
|
||||
$conn = $manager->getConnectionForComponent($queryComponent['metadata']->getClassName());
|
||||
}
|
||||
|
||||
$str = $conn->quoteIdentifier($queryComponent['metadata']->getTableName()) . ' '
|
||||
. $conn->quoteIdentifier($parserResult->getTableAliasFromComponentAlias($this->_rangeVariableDeclaration));
|
||||
|
||||
for ($i = 0, $l = count($this->_relations); $i < $l; $i++) {
|
||||
$str .= $this->_relations[$i]['join']->buildSql() . ' '
|
||||
. ((isset($this->_relations[$i]['indexby'])) ? $this->_relations[$i]['indexby']->buildSql() . ' ' : '');
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
90
lib/Doctrine/Query/Production/InExpression.php
Normal file
90
lib/Doctrine/Query/Production/InExpression.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* InExpression = ["NOT"] "IN" "(" (Atom {"," Atom} | Subselect) ")"
|
||||
*
|
||||
* @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_Production_InExpression extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_not;
|
||||
|
||||
protected $_subselect;
|
||||
|
||||
protected $_atoms = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// InExpression = ["NOT"] "IN" "(" (Atom {"," Atom} | Subselect) ")"
|
||||
$this->_not = false;
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_NOT)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_NOT);
|
||||
$this->_not = true;
|
||||
}
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IN);
|
||||
|
||||
$this->_parser->match('(');
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_SELECT)) {
|
||||
$this->_subselect = $this->AST('Subselect', $paramHolder);
|
||||
} else {
|
||||
$this->_atoms[] = $this->AST('Atom', $paramHolder);
|
||||
|
||||
while ($this->_isNextToken(',')) {
|
||||
$this->_parser->match(',');
|
||||
$this->_atoms[] = $this->AST('Atom', $paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_parser->match(')');
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return (($this->_not) ? 'NOT ' : '') . 'IN ('
|
||||
. (($this->_subselect !== null) ? $this->_subselect->buildSql() : implode(', ', $this->_mapAtoms()))
|
||||
. ')';
|
||||
}
|
||||
|
||||
|
||||
protected function _mapAtoms()
|
||||
{
|
||||
return array_map(array(&$this, '_mapAtom'), $this->_atoms);
|
||||
}
|
||||
|
||||
|
||||
protected function _mapAtom($value)
|
||||
{
|
||||
return $value->buildSql();
|
||||
}
|
||||
}
|
108
lib/Doctrine/Query/Production/IndexBy.php
Normal file
108
lib/Doctrine/Query/Production/IndexBy.php
Normal file
@ -0,0 +1,108 @@
|
||||
<?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" identifier
|
||||
*
|
||||
* @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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_IndexBy extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_componentAlias;
|
||||
|
||||
protected $_fieldName;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
$this->_componentAlias = $paramHolder->get('componentAlias');
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_INDEX);
|
||||
$this->_parser->match(Doctrine_Query_Token::T_BY);
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
|
||||
$this->_fieldName = $this->_parser->token['value'];
|
||||
}
|
||||
|
||||
|
||||
public function semantical($paramHolder)
|
||||
{
|
||||
$parserResult = $this->_parser->getParserResult();
|
||||
|
||||
//echo "Component alias: " . $this->_componentAlias . "\n";
|
||||
//echo "Has query component: " . ($parserResult->hasQueryComponent($this->_componentAlias) ? "TRUE" : "FALSE") . "\n";
|
||||
//$qc = $parserResult->getQueryComponents();
|
||||
//$qc = array_keys($qc);
|
||||
//echo "Query Components: " . var_export($qc, true) . "\n";
|
||||
|
||||
try {
|
||||
$queryComponent = $parserResult->getQueryComponent($this->_componentAlias);
|
||||
$classMetadata = $queryComponent['metadata'];
|
||||
} catch (Doctrine_Exception $e) {
|
||||
$this->_parser->semanticalError($e->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($classMetadata instanceof Doctrine_ClassMetadata && ! $classMetadata->hasField($this->_fieldName)) {
|
||||
$this->_parser->semanticalError(
|
||||
"Cannot use key mapping. Field '" . $this->_fieldName . "' " .
|
||||
"does not exist in component '" . $classMetadata->getClassName() . "'.",
|
||||
$this->_parser->token
|
||||
);
|
||||
}
|
||||
|
||||
// The INDEXBY field must be either the (primary && not part of composite pk) || (unique && notnull)
|
||||
$columnMapping = $classMetadata->getColumnMapping($this->_fieldName);
|
||||
|
||||
if ( ! $classMetadata->isIdentifier($field) && ! $classMetadata->isUniqueField($field) && ! $classMetadata->isNotNull($field)) {
|
||||
$this->_parser->semanticalError(
|
||||
"Field '" . $this->_fieldName . "' of component '" . $classMetadata->getClassName() .
|
||||
"' must be unique and notnull to be used as index.",
|
||||
$this->_parser->token
|
||||
);
|
||||
}
|
||||
|
||||
if ($classMetadata->isIdentifier($field) && $classMetadata->isIdentifierComposite()) {
|
||||
$this->_parser->semanticalError(
|
||||
"Field '" . $this->_fieldName . "' 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'] = $this->_fieldName;
|
||||
$parserResult->setQueryComponent($this->_componentAlias, $queryComponent);
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
79
lib/Doctrine/Query/Production/Join.php
Normal file
79
lib/Doctrine/Query/Production/Join.php
Normal 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Join = ["LEFT" | "INNER"] "JOIN" RangeVariableDeclaration [("ON" | "WITH") ConditionalExpression]
|
||||
*
|
||||
* @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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_Join extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_joinType;
|
||||
|
||||
protected $_rangeVariableDeclaration;
|
||||
|
||||
protected $_whereType;
|
||||
|
||||
protected $_conditionalExpression;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
$this->_joinType = 'INNER';
|
||||
$this->_whereType = 'WITH';
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_LEFT)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_LEFT);
|
||||
|
||||
$this->_joinType = 'LEFT';
|
||||
} elseif ($this->_isNextToken(Doctrine_Query_Token::T_INNER)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_INNER);
|
||||
}
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_JOIN);
|
||||
|
||||
$this->_rangeVariableDeclaration = $this->AST('RangeVariableDeclaration', $paramHolder);
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_ON)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_ON);
|
||||
|
||||
$this->_whereType = 'ON';
|
||||
|
||||
$this->_conditionalExpression = $this->AST('ConditionalExpression', $paramHolder);
|
||||
} elseif ($this->_isNextToken(Doctrine_Query_Token::T_WITH)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_WITH);
|
||||
|
||||
$this->_conditionalExpression = $this->AST('ConditionalExpression', $paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
72
lib/Doctrine/Query/Production/LikeExpression.php
Normal file
72
lib/Doctrine/Query/Production/LikeExpression.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* LikeExpression = ["NOT"] "LIKE" Expression ["ESCAPE" string]
|
||||
*
|
||||
* @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_Production_LikeExpression extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_not;
|
||||
|
||||
protected $_expression;
|
||||
|
||||
protected $_escapeString;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// LikeExpression = ["NOT"] "LIKE" Expression ["ESCAPE" string]
|
||||
$this->_escapeString = null;
|
||||
$this->_not = false;
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_NOT)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_NOT);
|
||||
$this->_not = true;
|
||||
}
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_LIKE);
|
||||
|
||||
$this->_expression = $this->AST('Expression', $paramHolder);
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_ESCAPE)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_ESCAPE);
|
||||
$this->_parser->match(Doctrine_Query_Token::T_STRING);
|
||||
|
||||
$this->_escapeString = $this->_parser->token['value'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return (($this->_not) ? 'NOT ' : '') . 'LIKE ' . $this->_expression->buildSql()
|
||||
. (($this->_escapeString !== null) ? ' ESCAPE ' . $this->_escapeString : '');
|
||||
}
|
||||
}
|
48
lib/Doctrine/Query/Production/LimitClause.php
Normal file
48
lib/Doctrine/Query/Production/LimitClause.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* LimitClause = "LIMIT" integer
|
||||
*
|
||||
* @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_Production_LimitClause extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_limit;
|
||||
|
||||
|
||||
public function execute(array $params = array())
|
||||
{
|
||||
$this->_parser->match(Doctrine_Query_Token::T_LIMIT);
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_INTEGER);
|
||||
$this->_limit = $this->_parser->token['value'];
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
58
lib/Doctrine/Query/Production/NullComparisonExpression.php
Executable file
58
lib/Doctrine/Query/Production/NullComparisonExpression.php
Executable file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* NullComparisonExpression = "IS" ["NOT"] "NULL"
|
||||
*
|
||||
* @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_Production_NullComparisonExpression extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_not;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
$this->_not = false;
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IS);
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_NOT)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_NOT);
|
||||
$this->_not = true;
|
||||
}
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_NULL);
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return 'IS ' . (($this->_not) ? 'NOT ' : '') . 'NULL';
|
||||
}
|
||||
}
|
57
lib/Doctrine/Query/Production/OffsetClause.php
Normal file
57
lib/Doctrine/Query/Production/OffsetClause.php
Normal 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* OffsetClause = "OFFSET" integer
|
||||
*
|
||||
* @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_Production_OffsetClause extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_offset;
|
||||
|
||||
|
||||
public function execute(array $params = array())
|
||||
{
|
||||
$this->_parser->match(Doctrine_Query_Token::T_OFFSET);
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_INTEGER);
|
||||
$this->_offset = $this->_parser->token['value'];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
// [TODO] How to deal with different DBMS here?
|
||||
// The responsability to apply the limit-subquery is from
|
||||
// SelectStatement, not this object's one.
|
||||
return ' OFFSET ' . $this->_offset;
|
||||
}
|
||||
}
|
68
lib/Doctrine/Query/Production/OrderByClause.php
Normal file
68
lib/Doctrine/Query/Production/OrderByClause.php
Normal 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* OrderByClause = "ORDER" "BY" OrderByItem {"," OrderByItem}
|
||||
*
|
||||
* @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_Production_OrderByClause extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_orderByItems = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
$this->_parser->match(Doctrine_Query_Token::T_ORDER);
|
||||
$this->_parser->match(Doctrine_Query_Token::T_BY);
|
||||
|
||||
$this->_orderByItems[] = $this->AST('OrderByItem', $paramHolder);
|
||||
|
||||
while ($this->_isNextToken(',')) {
|
||||
$this->_parser->match(',');
|
||||
$this->_orderByItems[] = $this->AST('OrderByItem', $paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
$str = 'ORDER BY ';
|
||||
|
||||
for ($i = 0, $l = count($this->_orderByItems); $i < $l; $i++) {
|
||||
if ($i != 0) {
|
||||
$str .= ', ';
|
||||
}
|
||||
|
||||
$str .= ( $this->_orderByItems[$i] instanceof Doctrine_Query_Production ) ?
|
||||
$this->_orderByItems[$i]->buildSql() : $this->_orderByItems[$i];
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
59
lib/Doctrine/Query/Production/OrderByItem.php
Normal file
59
lib/Doctrine/Query/Production/OrderByItem.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* OrderByItem = Expression ["ASC" | "DESC"]
|
||||
*
|
||||
* @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_Production_OrderByItem extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_expression;
|
||||
|
||||
protected $_orderType;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
$this->_expression = $this->AST('Expression', $paramHolder);
|
||||
$this->_orderType = 'ASC';
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_ASC)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_ASC);
|
||||
} elseif ($this->_isNextToken(Doctrine_Query_Token::T_DESC)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_DESC);
|
||||
$this->_orderType = 'DESC';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return $this->_expression->buildSql() . ' ' . $this->_orderType;
|
||||
}
|
||||
}
|
148
lib/Doctrine/Query/Production/PathExpression.php
Normal file
148
lib/Doctrine/Query/Production/PathExpression.php
Normal file
@ -0,0 +1,148 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PathExpression = identifier { "." 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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_PathExpression extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_identifiers = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
$this->_identifiers[] = $this->_parser->token['value'];
|
||||
|
||||
while ($this->_isNextToken('.')) {
|
||||
$this->_parser->match('.');
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
|
||||
$this->_identifiers[] = $this->_parser->token['value'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function semantical($paramHolder)
|
||||
{
|
||||
$parserResult = $this->_parser->getParserResult();
|
||||
$classMetadata = null;
|
||||
|
||||
for ($i = 0, $l = count($this->_identifiers); $i < $l; $i++) {
|
||||
if ($i < $l - 1) {
|
||||
$relationName = $this->_identifiers[$i];
|
||||
|
||||
// We are still checking for relations
|
||||
if ( $classMetadata !== null && ! $classMetadata->hasRelation($relationName)) {
|
||||
$className = $classMetadata->getClassName();
|
||||
|
||||
$this->_parser->semanticalError("Relation '{$relationName}' does not exist in component '{$className}'");
|
||||
|
||||
// Assigning new ClassMetadata
|
||||
$classMetadata = $classMetadata->getRelation($relationName)->getClassMetadata();
|
||||
} elseif ( $classMetadata === null ) {
|
||||
$queryComponent = $parserResult->getQueryComponent($relationName);
|
||||
|
||||
// We should have a semantical error if the queryComponent does not exists yet
|
||||
if ($queryComponent === null) {
|
||||
$this->_parser->semanticalError("Undefined component alias for relation '{$relationName}'");
|
||||
}
|
||||
|
||||
// Initializing ClassMetadata
|
||||
$classMetadata = $queryComponent['metadata'];
|
||||
}
|
||||
} else {
|
||||
$fieldName = $this->_identifiers[$i];
|
||||
|
||||
// We are checking for fields
|
||||
if ($classMetadata === null) {
|
||||
// No metadata selection until now. We might need to deal with:
|
||||
// DELETE FROM Obj alias WHERE field = X
|
||||
$queryComponents = $parserResult->getQueryComponents();
|
||||
|
||||
// Check if we have more than one queryComponent defined
|
||||
if (count($queryComponents) != 1) {
|
||||
$this->_parser->semanticalError("Undefined component alias for field '{$fieldName}'");
|
||||
}
|
||||
|
||||
// Retrieve ClassMetadata
|
||||
$k = array_keys($queryComponents);
|
||||
$componentAlias = $k[0];
|
||||
|
||||
$classMetadata = $queryComponents[$componentAlias]['metadata'];
|
||||
array_unshift($this->_identifiers, $componentAlias);
|
||||
}
|
||||
|
||||
// Check if field exists in ClassMetadata
|
||||
if ( ! $classMetadata->hasField($fieldName)) {
|
||||
$className = $classMetadata->getClassName();
|
||||
|
||||
$this->_parser->semanticalError("Field '{$fieldName}' does not exist in component '{$className}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
// Basic handy variables
|
||||
$parserResult = $this->_parser->getParserResult();
|
||||
|
||||
// Retrieving connection
|
||||
$conn = $this->_parser->getSqlBuilder()->getConnection();
|
||||
$manager = Doctrine_Manager::getInstance();
|
||||
|
||||
// _identifiers are always >= 2
|
||||
if ($manager->hasConnectionForComponent($this->_identifiers[0])) {
|
||||
$conn = $manager->getConnectionForComponent($this->_identifiers[0]);
|
||||
}
|
||||
|
||||
$str = '';
|
||||
|
||||
for ($i = 0, $l = count($this->_identifiers); $i < $l; $i++) {
|
||||
if ($i < $l - 1) {
|
||||
// [TODO] We are assuming we never define relations in SELECT
|
||||
// and WHERE clauses. So, do not bother about table alias that
|
||||
// may not be previously added. At a later stage, we should
|
||||
// deal with it too.
|
||||
$str .= $parserResult->getTableAliasFromComponentAlias($this->_identifiers[$i]) . '.';
|
||||
} else {
|
||||
// Retrieving last ClassMetadata
|
||||
$queryComponent = $parserResult->getQueryComponent($this->_identifiers[$i - 1]);
|
||||
$classMetadata = $queryComponent['metadata'];
|
||||
|
||||
$str .= $classMetadata->getColumnName($this->_identifiers[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
return $conn->quoteIdentifier($str);
|
||||
}
|
||||
}
|
@ -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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PathExpressionEndingWithAsterisk = {identifier "."} "*"
|
||||
*
|
||||
* @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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_PathExpressionEndingWithAsterisk extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_identifiers = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// PathExpressionEndingWithAsterisk = {identifier "."} "*"
|
||||
while ($this->_isNextToken(Doctrine_Query_Token::T_IDENTIFIER)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
$this->_identifiers[] = $this->_parser->token['value'];
|
||||
|
||||
$this->_parser->match('.');
|
||||
}
|
||||
|
||||
$this->_parser->match('*');
|
||||
}
|
||||
|
||||
|
||||
public function semantical($paramHolder)
|
||||
{
|
||||
$parserResult = $this->_parser->getParserResult();
|
||||
|
||||
if (($l = count($this->_identifiers)) > 0) {
|
||||
// We are dealing with component{.component}.*
|
||||
$classMetadata = null;
|
||||
|
||||
for ($i = 0; $i < $l; $i++) {
|
||||
$relationName = $this->_identifiers[$i];
|
||||
|
||||
// We are still checking for relations
|
||||
if ( $classMetadata !== null && ! $classMetadata->hasRelation($relationName)) {
|
||||
$className = $classMetadata->getClassName();
|
||||
|
||||
$this->_parser->semanticalError("Relation '{$relationName}' does not exist in component '{$className}'");
|
||||
|
||||
// Assigning new ClassMetadata
|
||||
$classMetadata = $classMetadata->getRelation($relationName)->getClassMetadata();
|
||||
} elseif ( $classMetadata === null ) {
|
||||
$queryComponent = $parserResult->getQueryComponent($relationName);
|
||||
|
||||
// We should have a semantical error if the queryComponent does not exists yet
|
||||
if ($queryComponent === null) {
|
||||
$this->_parser->semanticalError("Undefined component alias for relation '{$relationName}'");
|
||||
}
|
||||
|
||||
// Initializing ClassMetadata
|
||||
$classMetadata = $queryComponent['metadata'];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We are dealing with a simple * as our PathExpression.
|
||||
// We need to check if there's only one query component.
|
||||
$queryComponents = $parserResult->getQueryComponents();
|
||||
|
||||
if (count($queryComponents) != 1) {
|
||||
$this->_parser->semanticalError(
|
||||
"Cannot use * as selector expression for multiple components."
|
||||
);
|
||||
}
|
||||
|
||||
// We simplify our life adding the component alias to our AST,
|
||||
// since we have it on hands now.
|
||||
$k = array_keys($queryComponents);
|
||||
$this->_identifiers[] = $k[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
85
lib/Doctrine/Query/Production/Primary.php
Normal file
85
lib/Doctrine/Query/Production/Primary.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Primary = PathExpression | Atom | "(" Expression ")" | Function | AggregateExpression
|
||||
*
|
||||
* @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_Production_Primary extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_expression;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// Primary = PathExpression | Atom | "(" Expression ")" | Function | AggregateExpression
|
||||
switch ($this->_parser->lookahead['type']) {
|
||||
case Doctrine_Query_Token::T_IDENTIFIER:
|
||||
if ($this->_isFunction()) {
|
||||
return $this->AST('Function', $paramHolder);
|
||||
} else {
|
||||
return $this->AST('PathExpression', $paramHolder);
|
||||
}
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_STRING:
|
||||
case Doctrine_Query_Token::T_INTEGER:
|
||||
case Doctrine_Query_Token::T_FLOAT:
|
||||
case Doctrine_Query_Token::T_INPUT_PARAMETER:
|
||||
return $this->AST('Atom', $paramHolder);
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_AVG:
|
||||
case Doctrine_Query_Token::T_COUNT:
|
||||
case Doctrine_Query_Token::T_MAX:
|
||||
case Doctrine_Query_Token::T_MIN:
|
||||
case Doctrine_Query_Token::T_SUM:
|
||||
return $this->AST('AggregateExpression', $paramHolder);
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_NONE:
|
||||
if ($this->_isNextToken('(')) {
|
||||
$this->_parser->match('(');
|
||||
$this->_expression = $this->AST('Expression', $paramHolder);
|
||||
$this->_parser->match(')');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->_parser->syntaxError('Could not process primary type');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return '(' . $this->_expression->buildSql() . ')';
|
||||
}
|
||||
}
|
72
lib/Doctrine/Query/Production/QuantifiedExpression.php
Normal file
72
lib/Doctrine/Query/Production/QuantifiedExpression.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* QuantifiedExpression = ("ALL" | "ANY" | "SOME") "(" Subselect ")"
|
||||
*
|
||||
* @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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_QuantifiedExpression extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_type;
|
||||
|
||||
protected $_subselect;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
switch ($this->_parser->lookahead['type']) {
|
||||
case Doctrine_Query_Token::T_ALL:
|
||||
$this->_parser->match(Doctrine_Query_Token::T_ALL);
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_ANY:
|
||||
$this->_parser->match(Doctrine_Query_Token::T_ANY);
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_SOME:
|
||||
$this->_parser->match(Doctrine_Query_Token::T_SOME);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->_parser->logError('ALL, ANY or SOME');
|
||||
break;
|
||||
}
|
||||
|
||||
$this->_type = strtoupper($this->_parser->lookahead['value']);
|
||||
|
||||
$this->_parser->match('(');
|
||||
$this->_subselect = $this->AST('Subselect', $paramHolder);
|
||||
$this->_parser->match(')');
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return $this->_type . ' (' . $this->_subselect->buildSql() . ')';
|
||||
}
|
||||
}
|
57
lib/Doctrine/Query/Production/QueryLanguage.php
Normal file
57
lib/Doctrine/Query/Production/QueryLanguage.php
Normal 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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_QueryLanguage extends Doctrine_Query_Production
|
||||
{
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// QueryLanguage = SelectStatement | UpdateStatement | DeleteStatement
|
||||
switch ($this->_parser->lookahead['type']) {
|
||||
case Doctrine_Query_Token::T_SELECT:
|
||||
return $this->AST('SelectStatement', $paramHolder);
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_UPDATE:
|
||||
return $this->AST('UpdateStatement', $paramHolder);
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_DELETE:
|
||||
return $this->AST('DeleteStatement', $paramHolder);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->_parser->syntaxError('SELECT, UPDATE or DELETE');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
237
lib/Doctrine/Query/Production/RangeVariableDeclaration.php
Normal file
237
lib/Doctrine/Query/Production/RangeVariableDeclaration.php
Normal file
@ -0,0 +1,237 @@
|
||||
<?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 = identifier {"." identifier} [["AS"] IdentificationVariable]
|
||||
*
|
||||
* @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_Production_RangeVariableDeclaration extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_identifiers = array();
|
||||
|
||||
protected $_identificationVariable;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// RangeVariableDeclaration = identifier {"." identifier} [["AS"] IdentificationVariable]
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
$this->_identifiers[] = $this->_parser->token['value'];
|
||||
|
||||
while ($this->_isNextToken('.')) {
|
||||
$this->_parser->match('.');
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
|
||||
$this->_identifiers[] = $this->_parser->token['value'];
|
||||
}
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_AS)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_AS);
|
||||
}
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_IDENTIFIER)) {
|
||||
$paramHolder->set('componentName', implode('.', $this->_identifiers));
|
||||
|
||||
// Will return an identifier, with the semantical check already applied
|
||||
$this->_identificationVariable = $this->AST('IdentificationVariable', $paramHolder);
|
||||
|
||||
$paramHolder->remove('componentName');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function semantical($paramHolder)
|
||||
{
|
||||
$parserResult = $this->_parser->getParserResult();
|
||||
$componentName = implode('.', $this->_identifiers);
|
||||
|
||||
if ($parserResult->hasQueryComponent($componentName)) {
|
||||
//echo "Entered in if of hasQueryComponent(".$componentName."): true\n";
|
||||
|
||||
// As long as name != alias, try to bring the queryComponent from name (already processed)
|
||||
$queryComponent = $parserResult->getQueryComponent($componentName);
|
||||
|
||||
// Check if we defined _identificationVariable. We throw semantical error if not
|
||||
if ($this->_identificationVariable === null) {
|
||||
$componentName = $queryComponent['metadata']->getClassName();
|
||||
|
||||
$this->_parser->semanticalError(
|
||||
"Cannot re-declare component '{$componentName}'. Please assign an alias to it."
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
//echo "Entered in if hasQueryComponent(".$componentName."), alias ".var_export($this->_identificationVariable, true).": false\n";
|
||||
|
||||
// No queryComponent was found. We will have to build it for the first time
|
||||
if (count($this->_identifiers) > 1) {
|
||||
// We are in a multiple identifier declaration; we are dealing with relations here
|
||||
$this->_semanticalWithMultipleIdentifier();
|
||||
} else {
|
||||
// We are in a single identifier declaration; our identifier is the class name
|
||||
$this->_semanticalWithSingleIdentifier();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_identificationVariable;
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
private function _semanticalWithSingleIdentifier()
|
||||
{
|
||||
$parserResult = $this->_parser->getParserResult();
|
||||
|
||||
// Get the connection for the component
|
||||
$conn = $this->_parser->getSqlBuilder()->getConnection();
|
||||
$manager = Doctrine_EntityManager::getManager();
|
||||
$componentName = $this->_identifiers[0];
|
||||
|
||||
// Retrieving ClassMetadata and Mapper
|
||||
try {
|
||||
$classMetadata = $manager->getClassMetadata($componentName);
|
||||
|
||||
// Building queryComponent
|
||||
$queryComponent = array(
|
||||
'metadata' => $classMetadata,
|
||||
'mapper' => $manager->getEntityPersister($componentName),
|
||||
'parent' => null,
|
||||
'relation' => null,
|
||||
'map' => null,
|
||||
'agg' => null,
|
||||
);
|
||||
} catch (Doctrine_Exception $e) {
|
||||
//echo "Tried to load class metadata from '".$componentName."': " . $e->getMessage() . "\n";
|
||||
$this->_parser->semanticalError($e->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->_identificationVariable === null) {
|
||||
$this->_identificationVariable = $componentName;
|
||||
}
|
||||
|
||||
//echo "Identification Variable: " .$this->_identificationVariable . "\n";
|
||||
|
||||
$tableAlias = $parserResult->generateTableAlias($componentName);
|
||||
$parserResult->setQueryComponent($this->_identificationVariable, $queryComponent);
|
||||
$parserResult->setTableAlias($tableAlias, $this->_identificationVariable);
|
||||
}
|
||||
|
||||
|
||||
private function _semanticalWithMultipleIdentifier()
|
||||
{
|
||||
$parserResult = $this->_parser->getParserResult();
|
||||
|
||||
// Get the connection for the component
|
||||
$conn = $this->_parser->getSqlBuilder()->getConnection();
|
||||
$manager = Doctrine_EntityManager::getManager();
|
||||
|
||||
// Retrieve the base component
|
||||
try {
|
||||
$queryComponent = $parserResult->getQueryComponent($this->_identifiers[0]);
|
||||
$classMetadata = $queryComponent['metadata'];
|
||||
$className = $classMetadata->getClassName();
|
||||
$parent = $path = $this->_identifiers[0];
|
||||
} catch (Doctrine_Exception $e) {
|
||||
$this->_parser->semanticalError($e->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// We loop into others identifier to build query components
|
||||
for ($i = 1, $l = count($this->_identifiers); $i < $l; $i++) {
|
||||
$relationName = $this->_identifiers[$i];
|
||||
$path = '.' . $relationName;
|
||||
|
||||
if ($parserResult->hasQueryComponent($path)) {
|
||||
// We already have the query component on hands, get it
|
||||
$queryComponent = $parserResult->getQueryComponent($path);
|
||||
$classMetadata = $queryComponent['metadata'];
|
||||
|
||||
// If we are in our last check and identification variable is null, we throw semantical error
|
||||
if ($i == $l - 1 && $this->_identificationVariable === null) {
|
||||
$componentName = $classMetadata->getClassName();
|
||||
|
||||
$this->_parser->semanticalError(
|
||||
"Cannot re-declare component '{$componentName}' in path '{$path}'. " .
|
||||
"Please assign an alias to it."
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// We don't have the query component yet
|
||||
if ( ! $classMetadata->hasRelation($relationName)) {
|
||||
$className = $classMetadata->getClassName();
|
||||
|
||||
$this->_parser->semanticalError("Relation '{$relationName}' does not exist in component '{$className}'");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieving ClassMetadata and Mapper
|
||||
try {
|
||||
$relation = $classMetadata->getRelation($relationName);
|
||||
$classMetadata = $relation->getClassMetadata();
|
||||
|
||||
$queryComponent = array(
|
||||
'metadata' => $classMetadata,
|
||||
'mapper' => $manager->getEntityPersister($relation->getForeignComponentName()),
|
||||
'parent' => $parent,
|
||||
'relation' => $relation,
|
||||
'map' => null,
|
||||
'agg' => null,
|
||||
);
|
||||
|
||||
$parent = $path;
|
||||
} catch (Doctrine_Exception $e) {
|
||||
//echo "Tried to load class metadata from '".$relationName."'\n";
|
||||
$this->_parser->semanticalError($e->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->_identificationVariable === null) {
|
||||
$this->_identificationVariable = $path;
|
||||
}
|
||||
|
||||
$tableAlias = $parserResult->generateTableAlias($path);
|
||||
$parserResult->setQueryComponent($this->_identificationVariable, $queryComponent);
|
||||
$parserResult->setTableAlias($tableAlias, $this->_identificationVariable);
|
||||
}
|
||||
}
|
88
lib/Doctrine/Query/Production/SelectClause.php
Normal file
88
lib/Doctrine/Query/Production/SelectClause.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_SelectClause extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_isDistinct;
|
||||
|
||||
protected $_selectExpressions = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// SelectClause = "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression}
|
||||
$this->_isDistinct = false;
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_SELECT);
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_DISTINCT)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_DISTINCT);
|
||||
$this->_isDistinct = true;
|
||||
}
|
||||
|
||||
$this->_selectExpressions[] = $this->AST('SelectExpression', $paramHolder);
|
||||
|
||||
while ($this->_isNextToken(',')) {
|
||||
$this->_parser->match(',');
|
||||
$this->_selectExpressions[] = $this->AST('SelectExpression', $paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function semantical($paramHolder)
|
||||
{
|
||||
// We need to validate each SelectExpression
|
||||
for ($i = 0, $l = count($this->_selectExpressions); $i < $l; $i++) {
|
||||
$this->_selectExpressions[$i]->semantical($paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
126
lib/Doctrine/Query/Production/SelectExpression.php
Normal file
126
lib/Doctrine/Query/Production/SelectExpression.php
Normal file
@ -0,0 +1,126 @@
|
||||
<?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 = (PathExpressionEndingWithAsterisk | Expression | "(" Subselect ")")
|
||||
* [["AS"] IdentificationVariable]
|
||||
*
|
||||
* @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_Production_SelectExpression extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_leftExpression;
|
||||
|
||||
protected $_isSubselect;
|
||||
|
||||
protected $_identificationVariable;
|
||||
|
||||
private $__columnAliasInSql;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// SelectExpression = (PathExpressionEndingWithAsterisk | Expression | "(" Subselect ")")
|
||||
// [["AS"] IdentificationVariable]
|
||||
$this->_isSubselect = false;
|
||||
|
||||
if ($this->_isPathExpressionEndingWithAsterisk()) {
|
||||
$this->_leftExpression = $this->AST('PathExpressionEndingWithAsterisk', $paramHolder);
|
||||
} elseif(($this->_isSubselect = $this->_isSubselect()) === true) {
|
||||
$this->_parser->match('(');
|
||||
$this->_leftExpression = $this->AST('Subselect', $paramHolder);
|
||||
$this->_parser->match(')');
|
||||
} else {
|
||||
$this->_leftExpression = $this->AST('Expression', $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->_identificationVariable = $this->AST('IdentificationVariable', $paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function semantical($paramHolder)
|
||||
{
|
||||
// Here we inspect for duplicate IdentificationVariable, and if the
|
||||
// left expression needs the identification variable. If yes, check
|
||||
// its existance.
|
||||
if ($this->_leftExpression instanceof Doctrine_Query_Production_PathExpressionEndingWithAsterisk && $this->_identificationVariable !== null) {
|
||||
$this->_parser->semanticalError(
|
||||
"Cannot assign an identification variable to a path expression with asterisk (ie. foo.bar.* AS foobaz)."
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->_identificationVariable !== null) {
|
||||
if ($this->_leftExpression instanceof Doctrine_Query_Production_PathExpression) {
|
||||
// We bring the queryComponent from the class instance
|
||||
// $queryComponent = $this->_leftExpression->getQueryComponent();
|
||||
} else {
|
||||
// We bring the default queryComponent
|
||||
// $queryComponent = $parserResult->getQueryComponent(null);
|
||||
}
|
||||
|
||||
$idx = count($queryComponent['scalar']);
|
||||
$this->__columnAliasInSql .= '__' . $idx;
|
||||
|
||||
$queryComponent['scalar'][$idx] = $this->_identificationVariable;
|
||||
|
||||
//$parserResult->setQueryComponent($componentAlias, $queryComponent);
|
||||
}
|
||||
|
||||
// We need to add scalar in queryComponent the item alias if identificationvariable is set.
|
||||
echo "SelectExpression:\n";
|
||||
echo get_class($this->_leftExpression) . "\n";
|
||||
|
||||
// The check for duplicate IdentificationVariable was already done
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return $this->_leftExpression->buildSql() . ' AS '
|
||||
. (($this->_identificationVariable !== null) ? $this->_identificationVariable : '');
|
||||
}
|
||||
|
||||
|
||||
protected function _isPathExpressionEndingWithAsterisk()
|
||||
{
|
||||
$token = $this->_parser->lookahead;
|
||||
$this->_parser->getScanner()->resetPeek();
|
||||
|
||||
while (($token['type'] === Doctrine_Query_Token::T_IDENTIFIER) || ($token['value'] === '.')) {
|
||||
$token = $this->_parser->getScanner()->peek();
|
||||
}
|
||||
|
||||
return $token['value'] === '*';
|
||||
}
|
||||
}
|
96
lib/Doctrine/Query/Production/SelectStatement.php
Normal file
96
lib/Doctrine/Query/Production/SelectStatement.php
Normal file
@ -0,0 +1,96 @@
|
||||
<?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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_SelectStatement extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_selectClause;
|
||||
|
||||
protected $_fromClause;
|
||||
|
||||
protected $_whereClause;
|
||||
|
||||
protected $_groupByClause;
|
||||
|
||||
protected $_havingClause;
|
||||
|
||||
protected $_orderByClause;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// SelectStatement = SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
|
||||
|
||||
// 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 clause be processed).
|
||||
$paramHolder->set('semanticalCheck', false);
|
||||
$this->_selectClause = $this->AST('SelectClause', $paramHolder);
|
||||
$paramHolder->remove('semanticalCheck');
|
||||
|
||||
$this->_fromClause = $this->AST('FromClause', $paramHolder);
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_WHERE)) {
|
||||
$this->_whereClause = $this->AST('WhereClause', $paramHolder);
|
||||
}
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_GROUP)) {
|
||||
$this->_groupByClause = $this->AST('GroupByClause', $paramHolder);
|
||||
}
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_HAVING)) {
|
||||
$this->_havingClause = $this->AST('HavingClause', $paramHolder);
|
||||
}
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_ORDER)) {
|
||||
$this->_orderByClause = $this->AST('OrderByClause', $paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function semantical($paramHolder)
|
||||
{
|
||||
// We need to invoke the semantical check of SelectClause here, since
|
||||
// it was not yet checked.
|
||||
$this->_selectClause->semantical($paramHolder);
|
||||
}
|
||||
|
||||
|
||||
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() : '');
|
||||
}
|
||||
}
|
109
lib/Doctrine/Query/Production/SimpleConditionalExpression.php
Normal file
109
lib/Doctrine/Query/Production/SimpleConditionalExpression.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SimpleConditionalExpression =
|
||||
* ExistsExpression | Expression (ComparisonExpression | BetweenExpression |
|
||||
* LikeExpression | InExpression | NullComparisonExpression | QuantifiedExpression)
|
||||
*
|
||||
* @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_Production_SimpleConditionalExpression extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_leftExpression;
|
||||
|
||||
protected $_rightExpression;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// SimpleConditionalExpression =
|
||||
// ExistsExpression | Expression (ComparisonExpression | BetweenExpression |
|
||||
// LikeExpression | InExpression | NullComparisonExpression | QuantifiedExpression)
|
||||
if ($this->_getExpressionType() === Doctrine_Query_Token::T_EXISTS) {
|
||||
return $this->AST('ExistsExpression', $paramHolder);
|
||||
}
|
||||
|
||||
$this->_leftExpression = $this->AST('Expression', $paramHolder);
|
||||
|
||||
switch ($this->_getExpressionType()) {
|
||||
case Doctrine_Query_Token::T_BETWEEN:
|
||||
$this->_rightExpression = $this->AST('BetweenExpression', $paramHolder);
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_LIKE:
|
||||
$this->_rightExpression = $this->AST('LikeExpression', $paramHolder);
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_IN:
|
||||
$this->_rightExpression = $this->AST('InExpression', $paramHolder);
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_IS:
|
||||
$this->_rightExpression = $this->AST('NullComparisonExpression', $paramHolder);
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_ALL:
|
||||
case Doctrine_Query_Token::T_ANY:
|
||||
case Doctrine_Query_Token::T_SOME:
|
||||
$this->_rightExpression = $this->AST('QuantifiedExpression', $paramHolder);
|
||||
break;
|
||||
|
||||
case Doctrine_Query_Token::T_NONE:
|
||||
// [TODO] Check out ticket #935 to understand what will be done with enumParams
|
||||
$this->_rightExpression = $this->AST('ComparisonExpression', $paramHolder);
|
||||
break;
|
||||
|
||||
default:
|
||||
$message = "BETWEEN, LIKE, IN, IS, quantified (ALL, ANY or SOME) "
|
||||
. "or comparison (=, <, <=, <>, >, >=, !=)";
|
||||
$this->_parser->syntaxError($message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return $this->_leftExpression->buildSql() . ' ' . $this->_rightExpression->buildSql();
|
||||
}
|
||||
|
||||
|
||||
protected function _getExpressionType() {
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_NOT)) {
|
||||
$scanner = $this->_parser->getScanner();
|
||||
|
||||
$token = $scanner->peek();
|
||||
$scanner->resetPeek();
|
||||
} else {
|
||||
$token = $this->_parser->lookahead;
|
||||
}
|
||||
|
||||
return $token['type'];
|
||||
}
|
||||
}
|
68
lib/Doctrine/Query/Production/SimpleSelectClause.php
Normal file
68
lib/Doctrine/Query/Production/SimpleSelectClause.php
Normal 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SimpleSelectClause = "SELECT" ["DISTINCT"] SelectExpression
|
||||
*
|
||||
* @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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_SimpleSelectClause extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_isDistinct;
|
||||
|
||||
protected $_selectExpression;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// SimpleSelectClause = "SELECT" ["DISTINCT"] SelectExpression
|
||||
$this->_isDistinct = false;
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_SELECT);
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_DISTINCT)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_DISTINCT);
|
||||
$this->_isDistinct = true;
|
||||
}
|
||||
|
||||
$this->_selectExpression = $this->AST('SelectExpression', $paramHolder);
|
||||
}
|
||||
|
||||
|
||||
public function semantical($paramHolder)
|
||||
{
|
||||
// We need to validate the SelectExpression
|
||||
$this->_selectExpression->semantical($paramHolder);
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return 'SELECT ' . (($this->_isDistinct) ? 'DISTINCT ' : '')
|
||||
. $this->_selectExpression->buildSql();
|
||||
}
|
||||
}
|
105
lib/Doctrine/Query/Production/Subselect.php
Normal file
105
lib/Doctrine/Query/Production/Subselect.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Subselect = SimpleSelectClause FromClause [WhereClause] [GroupByClause]
|
||||
* [HavingClause] [OrderByClause] [LimitClause] [OffsetClause]
|
||||
*
|
||||
* @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_Production_Subselect extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_simpleSelectClause;
|
||||
|
||||
protected $_fromClause;
|
||||
|
||||
protected $_whereClause;
|
||||
|
||||
protected $_groupByClause;
|
||||
|
||||
protected $_havingClause;
|
||||
|
||||
protected $_orderByClause;
|
||||
|
||||
protected $_limitClause;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// Subselect = SimpleSelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] [LimitClause]
|
||||
|
||||
// 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 clause be processed).
|
||||
$paramHolder->set('semanticalCheck', false);
|
||||
$this->_simpleSelectClause = $this->AST('SimpleSelectClause', $paramHolder);
|
||||
$paramHolder->remove('semanticalCheck');
|
||||
|
||||
$this->_fromClause = $this->AST('FromClause', $paramHolder);
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_WHERE)) {
|
||||
$this->_whereClause = $this->AST('WhereClause', $paramHolder);
|
||||
}
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_GROUP)) {
|
||||
$this->_groupByClause = $this->AST('GroupByClause', $paramHolder);
|
||||
}
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_HAVING)) {
|
||||
$this->_havingClause = $this->AST('HavingClause', $paramHolder);
|
||||
}
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_ORDER)) {
|
||||
$this->_orderByClause = $this->AST('OrderByClause', $paramHolder);
|
||||
}
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_LIMIT)) {
|
||||
$this->_limitClause = $this->AST('LimitClause', $paramHolder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function semantical($paramHolder)
|
||||
{
|
||||
// We need to invoke the semantical check of SelectClause here, since
|
||||
// it was not yet checked.
|
||||
$this->_simpleSelectClause->semantical($paramHolder);
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return $this->_simpleSelectClause->buildSql() . ' ' . $this->_fromClause->buildSql()
|
||||
. (($this->_whereClause !== null) ? ' ' . $this->_whereClause->buildSql() : '')
|
||||
. (($this->_groupByClause !== null) ? ' ' . $this->_groupByClause->buildSql() : '')
|
||||
. (($this->_havingClause !== null) ? ' ' . $this->_havingClause->buildSql() : '')
|
||||
. (($this->_orderByClause !== null) ? ' ' . $this->_orderByClause->buildSql() : '');
|
||||
}
|
||||
|
||||
}
|
79
lib/Doctrine/Query/Production/Term.php
Normal file
79
lib/Doctrine/Query/Production/Term.php
Normal 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Term = Factor {("*" | "/") Factor}
|
||||
*
|
||||
* @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_Production_Term extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_factors = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// Term = Factor {("*" | "/") Factor}
|
||||
$this->_factors[] = $this->AST('Factor', $paramHolder);
|
||||
|
||||
while ($this->_isNextToken('*') || $this->_isNextToken('/')) {
|
||||
if ($this->_isNextToken('*')) {
|
||||
$this->_parser->match('*');
|
||||
$this->_factors[] = '*';
|
||||
} else {
|
||||
$this->_parser->match('/');
|
||||
$this->_factors[] = '/';
|
||||
}
|
||||
|
||||
$this->_factors[] = $this->AST('Factor', $paramHolder);
|
||||
}
|
||||
|
||||
// Optimize depth instances in AST
|
||||
if (count($this->_factors) == 1) {
|
||||
return $this->_factors[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return implode(' ', $this->_mapFactors());
|
||||
}
|
||||
|
||||
|
||||
protected function _mapFactors()
|
||||
{
|
||||
return array_map(array(&$this, '_mapFactor'), $this->_factors);
|
||||
}
|
||||
|
||||
|
||||
protected function _mapFactor($value)
|
||||
{
|
||||
return (is_string($value) ? $value : $value->buildSql());
|
||||
}
|
||||
}
|
77
lib/Doctrine/Query/Production/UpdateClause.php
Normal file
77
lib/Doctrine/Query/Production/UpdateClause.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* UpdateClause = "UPDATE" VariableDeclaration "SET" UpdateItem {"," UpdateItem}
|
||||
*
|
||||
* @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_Production_UpdateClause extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_variableDeclaration;
|
||||
|
||||
protected $_updateItems = array();
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// UpdateClause = "UPDATE" VariableDeclaration "SET" UpdateItem {"," UpdateItem}
|
||||
$this->_parser->match(Doctrine_Query_Token::T_UPDATE);
|
||||
|
||||
$this->_variableDeclaration = $this->AST('VariableDeclaration', $paramHolder);
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_SET);
|
||||
|
||||
$this->_updateItems[] = $this->AST('UpdateItem', $paramHolder);
|
||||
|
||||
while ($this->_isNextToken(',')) {
|
||||
$this->_parser->match(',');
|
||||
|
||||
$this->_updateItems[] = $this->AST('UpdateItem', $paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return 'UPDATE ' . $this->_variableDeclaration->buildSql()
|
||||
. ' SET ' . implode(', ', $this->_mapUpdateItems());
|
||||
}
|
||||
|
||||
|
||||
protected function _mapUpdateItems()
|
||||
{
|
||||
return array_map(array(&$this, '_mapUpdateItem'), $this->_updateItems);
|
||||
}
|
||||
|
||||
|
||||
protected function _mapUpdateItem($value)
|
||||
{
|
||||
return $value->buildSql();
|
||||
}
|
||||
}
|
62
lib/Doctrine/Query/Production/UpdateItem.php
Normal file
62
lib/Doctrine/Query/Production/UpdateItem.php
Normal 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* UpdateItem = PathExpression "=" (Expression | "NULL")
|
||||
*
|
||||
* @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_Production_UpdateItem extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_pathExpression;
|
||||
|
||||
protected $_expression;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// UpdateItem = PathExpression "=" (Expression | "NULL")
|
||||
$this->_pathExpression = $this->AST('PathExpression', $paramHolder);
|
||||
|
||||
$this->_parser->match('=');
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_NULL)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_NULL);
|
||||
$this->_expression = null;
|
||||
} else {
|
||||
$this->_expression = $this->AST('Expression', $paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return $this->_pathExpression->buildSql() . ' = '
|
||||
. ($this->_expression === null ? 'NULL' : $this->_expression->buildSql());
|
||||
}
|
||||
}
|
59
lib/Doctrine/Query/Production/UpdateStatement.php
Normal file
59
lib/Doctrine/Query/Production/UpdateStatement.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?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 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_UpdateStatement extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_updateClause;
|
||||
|
||||
protected $_whereClause;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// UpdateStatement = UpdateClause [WhereClause]
|
||||
$this->_updateClause = $this->AST('UpdateClause', $paramHolder);
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_WHERE)) {
|
||||
$this->_whereClause = $this->AST('WhereClause', $paramHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
138
lib/Doctrine/Query/Production/VariableDeclaration.php
Normal file
138
lib/Doctrine/Query/Production/VariableDeclaration.php
Normal file
@ -0,0 +1,138 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* VariableDeclaration = identifier [["AS"] IdentificationVariable]
|
||||
*
|
||||
* @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_Production_VariableDeclaration extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_componentName;
|
||||
|
||||
protected $_componentAlias;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// VariableDeclaration = identifier [["AS"] IdentificationVariable]
|
||||
if ($this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER)) {
|
||||
// identifier
|
||||
$this->_componentName = $this->_parser->token['value'];
|
||||
}
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_AS)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_AS);
|
||||
}
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_IDENTIFIER)) {
|
||||
$paramHolder->set('componentName', $this->_componentName);
|
||||
|
||||
// Will return an identifier, with the semantical check already applied
|
||||
$this->_componentAlias = $this->AST('IdentificationVariable', $paramHolder);
|
||||
|
||||
$paramHolder->remove('componentName');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function semantical($paramHolder)
|
||||
{
|
||||
$parserResult = $this->_parser->getParserResult();
|
||||
|
||||
if ($parserResult->hasQueryComponent($this->_componentName)) {
|
||||
// As long as name != alias, try to bring the queryComponent from name (already processed)
|
||||
$queryComponent = $parserResult->getQueryComponent($this->_componentName);
|
||||
|
||||
// Check if we defined _componentAlias. We throw semantical error if not
|
||||
if ($this->_componentAlias === null) {
|
||||
$componentName = $queryComponent['metadata']->getClassName();
|
||||
|
||||
$this->_parser->semanticalError(
|
||||
"Cannot re-declare component '{$this->_componentName}'. Please assign an alias to it."
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// No queryComponent was found. We will have to build it for the first time
|
||||
|
||||
// Get the connection for the component
|
||||
$conn = $this->_parser->getSqlBuilder()->getConnection();
|
||||
$manager = Doctrine_EntityManager::getManager();
|
||||
|
||||
// Retrieving ClassMetadata and Mapper
|
||||
try {
|
||||
$classMetadata = $manager->getMetadata($this->_componentName);
|
||||
|
||||
// Building queryComponent
|
||||
$queryComponent = array(
|
||||
'metadata' => $classMetadata,
|
||||
'mapper' => $manager->getEntityPersister($this->_componentName),
|
||||
'parent' => null,
|
||||
'relation' => null,
|
||||
'map' => null,
|
||||
'agg' => null,
|
||||
);
|
||||
} catch (Doctrine_Exception $e) {
|
||||
$this->_parser->semanticalError($e->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Define ParserResult assertions for later usage
|
||||
$tableAlias = $this->_parser->getParserResult()->generateTableAlias($this->_componentName);
|
||||
|
||||
if ($this->_componentAlias === null) {
|
||||
$this->_componentAlias = $this->_componentName;
|
||||
}
|
||||
|
||||
$parserResult->setQueryComponent($this->_componentAlias, $queryComponent);
|
||||
$parserResult->setTableAlias($tableAlias, $this->_componentAlias);
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
// Basic handy variables
|
||||
$parserResult = $this->_parser->getParserResult();
|
||||
$queryComponent = $parserResult->getQueryComponent($this->_componentAlias);
|
||||
|
||||
// Retrieving connection
|
||||
$conn = $this->_parser->getSqlBuilder()->getConnection();
|
||||
$manager = Doctrine_Manager::getInstance();
|
||||
|
||||
if ($manager->hasConnectionForComponent($this->_componentName)) {
|
||||
$conn = $manager->getConnectionForComponent($this->_componentName);
|
||||
}
|
||||
|
||||
return $conn->quoteIdentifier($queryComponent['metadata']->getTableName()) . ' '
|
||||
. $conn->quoteIdentifier($parserResult->getTableAliasFromComponentAlias($this->_componentAlias));
|
||||
}
|
||||
}
|
@ -1,52 +1,52 @@
|
||||
<?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>.
|
||||
*/
|
||||
Doctrine::autoload('Doctrine_Query_Part');
|
||||
/**
|
||||
* Doctrine_Query_Groupby
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*/
|
||||
class Doctrine_Query_Groupby extends Doctrine_Query_Part
|
||||
{
|
||||
/**
|
||||
* DQL GROUP BY PARSER
|
||||
* parses the group by part of the query string
|
||||
*
|
||||
* @param string $str
|
||||
* @return void
|
||||
*/
|
||||
public function parse($str, $append = false)
|
||||
{
|
||||
$r = array();
|
||||
foreach (explode(',', $str) as $reference) {
|
||||
$reference = trim($reference);
|
||||
|
||||
$r[] = $this->query->parseClause($reference);
|
||||
}
|
||||
return implode(', ', $r);
|
||||
}
|
||||
}
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* WhereClause = "WHERE" ConditionalExpression
|
||||
*
|
||||
* @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_Production_WhereClause extends Doctrine_Query_Production
|
||||
{
|
||||
protected $_conditionalExpression;
|
||||
|
||||
|
||||
public function syntax($paramHolder)
|
||||
{
|
||||
// WhereClause = "WHERE" ConditionalExpression
|
||||
$this->_parser->match(Doctrine_Query_Token::T_WHERE);
|
||||
|
||||
$this->_conditionalExpression = $this->AST('ConditionalExpression', $paramHolder);
|
||||
}
|
||||
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
return ' WHERE ' . $this->_conditionalExpression->buildSql();
|
||||
}
|
||||
}
|
89
lib/Doctrine/Query/ProductionParamHolder.php
Normal file
89
lib/Doctrine/Query/ProductionParamHolder.php
Normal 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Production variables holder
|
||||
*
|
||||
* @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_ProductionParamHolder
|
||||
{
|
||||
protected static $_instance;
|
||||
|
||||
protected $_data;
|
||||
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
$this->free();
|
||||
}
|
||||
|
||||
|
||||
public static function create()
|
||||
{
|
||||
if ( ! isset(self::$_instance)) {
|
||||
self::$_instance = new self;
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
|
||||
public function free()
|
||||
{
|
||||
$this->_data = array();
|
||||
}
|
||||
|
||||
|
||||
public function set($offset, $value)
|
||||
{
|
||||
$this->_data[$offset] = $value;
|
||||
}
|
||||
|
||||
|
||||
public function get($offset)
|
||||
{
|
||||
return isset($this->_data[$offset]) ? $this->_data[$offset] : null;
|
||||
}
|
||||
|
||||
|
||||
public function has($offset)
|
||||
{
|
||||
return isset($this->_data[$offset]);
|
||||
}
|
||||
|
||||
|
||||
public function remove($offset)
|
||||
{
|
||||
if ($this->has($offset)) {
|
||||
$this->_data[$offset] = null;
|
||||
unset($this->_data[$offset]);
|
||||
}
|
||||
}
|
||||
}
|
101
lib/Doctrine/Query/Orderby.php → lib/Doctrine/Query/QueryResult.php
Normal file → Executable file
101
lib/Doctrine/Query/Orderby.php → lib/Doctrine/Query/QueryResult.php
Normal file → Executable file
@ -1,53 +1,48 @@
|
||||
<?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>.
|
||||
*/
|
||||
Doctrine::autoload('Doctrine_Query_Part');
|
||||
/**
|
||||
* Doctrine_Query_Orderby
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*/
|
||||
class Doctrine_Query_Orderby extends Doctrine_Query_Part
|
||||
{
|
||||
/**
|
||||
* DQL ORDER BY PARSER
|
||||
* parses the order by part of the query string
|
||||
*
|
||||
* @param string $str
|
||||
* @return void
|
||||
*/
|
||||
public function parse($str, $append = false)
|
||||
{
|
||||
$ret = array();
|
||||
|
||||
foreach (explode(',', trim($str)) as $r) {
|
||||
$r = $this->query->parseClause($r);
|
||||
|
||||
$ret[] = $r;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
Doctrine::autoload('Doctrine_Query_AbstractResult');
|
||||
|
||||
/**
|
||||
* Doctrine_Query_QueryResult
|
||||
*
|
||||
* @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_QueryResult extends Doctrine_Query_AbstractResult
|
||||
{
|
||||
/**
|
||||
* Returns cached resultset.
|
||||
*
|
||||
* @return array Resultset.
|
||||
*/
|
||||
public function getResultSet()
|
||||
{
|
||||
return $this->_data;
|
||||
}
|
||||
|
||||
}
|
219
lib/Doctrine/Query/Scanner.php
Normal file
219
lib/Doctrine/Query/Scanner.php
Normal file
@ -0,0 +1,219 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Scans a DQL query for tokens.
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Scanner
|
||||
{
|
||||
/**
|
||||
* Array of scanned tokens
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_tokens = array();
|
||||
|
||||
protected $_position = 0;
|
||||
|
||||
protected $_peek = 0;
|
||||
|
||||
/**
|
||||
* Creates a new query scanner object.
|
||||
*
|
||||
* @param string $input a query string
|
||||
*/
|
||||
public function __construct($input)
|
||||
{
|
||||
$this->_scan($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an identifier is a keyword and returns its correct type.
|
||||
*
|
||||
* @param string $identifier identifier name
|
||||
* @return int token type
|
||||
*/
|
||||
public function _checkLiteral($identifier)
|
||||
{
|
||||
$name = 'Doctrine_Query_Token::T_' . strtoupper($identifier);
|
||||
|
||||
if (defined($name)) {
|
||||
$type = constant($name);
|
||||
|
||||
if ($type > 100) {
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
|
||||
return Doctrine_Query_Token::T_IDENTIFIER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the input string for tokens.
|
||||
*
|
||||
* @param string $input a query string
|
||||
*/
|
||||
protected function _scan($input)
|
||||
{
|
||||
static $regex;
|
||||
|
||||
if ( ! isset($regex)) {
|
||||
$patterns = array(
|
||||
'[a-z_][a-z0-9_]*',
|
||||
'(?:[0-9]+(?:[,\.][0-9]+)*)(?:e[+-]?[0-9]+)?',
|
||||
"'(?:[^']|'')*'",
|
||||
'\?|:[a-z]+'
|
||||
);
|
||||
$regex = '/(' . implode(')|(', $patterns) . ')|\s+|(.)/i';
|
||||
}
|
||||
|
||||
$flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
|
||||
$matches = preg_split($regex, $input, -1, $flags);
|
||||
|
||||
foreach ($matches as $match) {
|
||||
$value = $match[0];
|
||||
|
||||
$type = $this->_getType($value);
|
||||
|
||||
$this->_tokens[] = array(
|
||||
'value' => $value,
|
||||
'type' => $type,
|
||||
'position' => $match[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function _getType(&$value)
|
||||
{
|
||||
// $value is referenced because it can be changed if it is numeric.
|
||||
// [TODO] Revisit the _isNumeric and _getNumeric methods to reduce overhead.
|
||||
$type = Doctrine_Query_Token::T_NONE;
|
||||
|
||||
$newVal = $this->_getNumeric($value);
|
||||
if($newVal !== false){
|
||||
$value = $newVal;
|
||||
if (strpos($value, '.') !== false || stripos($value, 'e') !== false) {
|
||||
$type = Doctrine_Query_Token::T_FLOAT;
|
||||
} else{
|
||||
$type = Doctrine_Query_Token::T_INTEGER;
|
||||
}
|
||||
|
||||
}
|
||||
if ($value[0] === "'" && $value[strlen($value) - 1] === "'") {
|
||||
$type = Doctrine_Query_Token::T_STRING;
|
||||
} elseif (ctype_alpha($value[0]) || $value[0] === '_') {
|
||||
$type = $this->_checkLiteral($value);
|
||||
} elseif ($value[0] === '?' || $value[0] === ':') {
|
||||
$type = Doctrine_Query_Token::T_INPUT_PARAMETER;
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
|
||||
protected function _getNumeric($value)
|
||||
{
|
||||
if (!is_scalar($value)) {
|
||||
return false;
|
||||
}
|
||||
// Checking for valid numeric numbers: 1.234, -1.234e-2
|
||||
if (is_numeric($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// World number: 1.000.000,02 or -1,234e-2
|
||||
$worldnum = strtr($value, array('.' => '', ',' => '.'));
|
||||
if(is_numeric($worldnum)) {
|
||||
return $worldnum;
|
||||
}
|
||||
|
||||
// American extensive number: 1,000,000.02
|
||||
$american_en = strtr($value, array(',' => ''));
|
||||
if (is_numeric($american_en)) {
|
||||
return $american_en;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function isA($value, $token)
|
||||
{
|
||||
$type = $this->_getType($value);
|
||||
|
||||
return $type === $token;
|
||||
}
|
||||
|
||||
|
||||
public function peek()
|
||||
{
|
||||
if (isset($this->_tokens[$this->_position + $this->_peek])) {
|
||||
return $this->_tokens[$this->_position + $this->_peek++];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function resetPeek()
|
||||
{
|
||||
$this->_peek = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the next token in the input string.
|
||||
*
|
||||
* A token is an associative array containing three items:
|
||||
* - 'value' : the string value of the token in the input string
|
||||
* - 'type' : the type of the token (identifier, numeric, string, input
|
||||
* parameter, none)
|
||||
* - 'position' : the position of the token in the input string
|
||||
*
|
||||
* @return array|null the next token; null if there is no more tokens left
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->_peek = 0;
|
||||
|
||||
if (isset($this->_tokens[$this->_position])) {
|
||||
return $this->_tokens[$this->_position++];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function resetPosition($position = 0)
|
||||
{
|
||||
$this->_position = $position;
|
||||
}
|
||||
}
|
87
lib/Doctrine/Query/SqlBuilder.php
Executable file
87
lib/Doctrine/Query/SqlBuilder.php
Executable 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base class of each Sql Builder object
|
||||
*
|
||||
* @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$
|
||||
*/
|
||||
abstract class Doctrine_Query_SqlBuilder
|
||||
{
|
||||
/**
|
||||
* The Connection object.
|
||||
*
|
||||
* @var Doctrine_Connection
|
||||
*/
|
||||
protected $_connection;
|
||||
|
||||
|
||||
public static function fromConnection(Doctrine_Connection $connection = null)
|
||||
{
|
||||
if ($connection === null) {
|
||||
$connection = Doctrine_EntityManager::getManager()->getConnection();
|
||||
}
|
||||
|
||||
$className = "Doctrine_Query_SqlBuilder_" . $connection->getDriverName();
|
||||
$sqlBuilder = new $className();
|
||||
$sqlBuilder->_connection = $connection;
|
||||
|
||||
return $sqlBuilder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the assocated Doctrine_Connection to this object.
|
||||
*
|
||||
* @return Doctrine_Connection
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->_connection;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @nodoc
|
||||
*/
|
||||
public function quoteIdentifier($identifier)
|
||||
{
|
||||
return $this->_connection->quoteIdentifier($identifier);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Start Common SQL generations
|
||||
// Here we follow the SQL-99 specifications available at:
|
||||
// http://savage.net.au/SQL/sql-99.bnf
|
||||
|
||||
|
||||
|
||||
// End of Common SQL generations
|
||||
}
|
38
lib/Doctrine/Query/SqlBuilder/Mysql.php
Executable file
38
lib/Doctrine/Query/SqlBuilder/Mysql.php
Executable file
@ -0,0 +1,38 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* MySql class of Sql Builder object
|
||||
*
|
||||
* @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_SqlBuilder_Mysql extends Doctrine_Query_SqlBuilder
|
||||
{
|
||||
|
||||
}
|
75
lib/Doctrine/Query/Limit.php → lib/Doctrine/Query/SqlBuilder/Sqlite.php
Normal file → Executable file
75
lib/Doctrine/Query/Limit.php → lib/Doctrine/Query/SqlBuilder/Sqlite.php
Normal file → Executable file
@ -1,39 +1,38 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id: Where.php 1352 2007-05-15 10:07:05Z zYne $
|
||||
*
|
||||
* 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_Query_Limit
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision: 1352 $
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*/
|
||||
class Doctrine_Query_Limit extends Doctrine_Query_Part
|
||||
{
|
||||
public function parse($limit)
|
||||
{
|
||||
return (int) $limit;
|
||||
}
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sqlite class of Sql Builder object
|
||||
*
|
||||
* @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_SqlBuilder_Sqlite extends Doctrine_Query_SqlBuilder
|
||||
{
|
||||
|
||||
}
|
115
lib/Doctrine/Query/SqlExecutor/Abstract.php
Normal file
115
lib/Doctrine/Query/SqlExecutor/Abstract.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Doctrine_Query_QueryResult
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
abstract class Doctrine_Query_SqlExecutor_Abstract implements Serializable
|
||||
{
|
||||
// [TODO] Remove me later!
|
||||
public $AST;
|
||||
|
||||
protected $_sqlStatements;
|
||||
|
||||
public function __construct(Doctrine_Query_Production $AST)
|
||||
{
|
||||
// [TODO] Remove me later!
|
||||
$this->AST = $AST;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the SQL statements that are executed by the executor.
|
||||
*
|
||||
* @return array All the SQL update statements.
|
||||
*/
|
||||
public function getSqlStatements()
|
||||
{
|
||||
return $this->_sqlStatements;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes all sql statements.
|
||||
*
|
||||
* @param Doctrine_Connection $conn The database connection that is used to execute the queries.
|
||||
* @param array $params The parameters.
|
||||
*/
|
||||
abstract public function execute(Doctrine_Connection $conn, array $params);
|
||||
|
||||
|
||||
/**
|
||||
* Factory method.
|
||||
* Creates an appropriate sql executor for the given AST.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
$isDeleteStatement = $AST instanceof Doctrine_Query_Production_DeleteStatement;
|
||||
$isUpdateStatement = $AST instanceof Doctrine_Query_Production_UpdateStatement;
|
||||
|
||||
if ($isUpdateStatement || $isDeleteStatement) {
|
||||
// TODO: Inspect the $AST and create the proper executor like so (pseudo-code):
|
||||
/*
|
||||
if (primaryClassInFromClause->isMultiTable()) {
|
||||
if ($isDeleteStatement) {
|
||||
return new Doctrine_Query_SqlExecutor_MultiTableDelete($AST);
|
||||
} else {
|
||||
return new Doctrine_Query_SqlExecutor_MultiTableUpdate($AST);
|
||||
}
|
||||
} else ...
|
||||
*/
|
||||
return new Doctrine_Query_SqlExecutor_SingleTableDeleteUpdate($AST);
|
||||
} else {
|
||||
return new Doctrine_Query_SqlExecutor_SingleSelect($AST);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the sql statements of the executor.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
return serialize($this->_sqlStatements);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reconstructs the executor with it's sql statements.
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
$this->_sqlStatements = unserialize($serialized);
|
||||
}
|
||||
}
|
40
lib/Doctrine/Query/SqlExecutor/MultiTableDelete.php
Normal file
40
lib/Doctrine/Query/SqlExecutor/MultiTableDelete.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Executes the SQL statements for bulk DQL DELETE statements on classes in
|
||||
* Class Table Inheritance (JOINED).
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @todo For a good implementation that uses temporary tables see the Hibernate sources:
|
||||
* (org.hibernate.hql.ast.exec.MultiTableDeleteExecutor).
|
||||
*/
|
||||
class Doctrine_Query_SqlExecutor_MultiTableDelete extends Doctrine_Query_SqlExecutor_Abstract
|
||||
{
|
||||
|
||||
|
||||
}
|
44
lib/Doctrine/Query/SqlExecutor/MultiTableUpdate.php
Normal file
44
lib/Doctrine/Query/SqlExecutor/MultiTableUpdate.php
Normal 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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Executes the SQL statements for bulk DQL UPDATE statements on classes in
|
||||
* Class Table Inheritance (JOINED).
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
* @todo For a good implementation that uses temporary tables see the Hibernate sources:
|
||||
* (org.hibernate.hql.ast.exec.MultiTableUpdateExecutor).
|
||||
*/
|
||||
class Doctrine_Query_SqlExecutor_MultiTableUpdate extends Doctrine_Query_SqlExecutor_Abstract
|
||||
{
|
||||
public function __construct(Doctrine_Query_Production $AST)
|
||||
{
|
||||
// TODO: Inspect the AST, create the necessary SQL queries and store them
|
||||
// in $this->_sqlStatements
|
||||
}
|
||||
|
||||
}
|
45
lib/Doctrine/Query/SqlExecutor/SingleSelect.php
Normal file
45
lib/Doctrine/Query/SqlExecutor/SingleSelect.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Executor that executes the SQL statement for simple DQL SELECT statements.
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Abstract
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @version $Revision$
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 2.0
|
||||
*/
|
||||
class Doctrine_Query_SqlExecutor_SingleSelect extends Doctrine_Query_SqlExecutor_Abstract
|
||||
{
|
||||
public function __construct(Doctrine_Query_Production $AST)
|
||||
{
|
||||
parent::__construct($AST);
|
||||
$this->_sqlStatements = $AST->buildSql();
|
||||
}
|
||||
|
||||
public function execute(Doctrine_Connection $conn, array $params)
|
||||
{
|
||||
return $conn->execute($this->_sqlStatements, $params);
|
||||
}
|
||||
}
|
46
lib/Doctrine/Query/SqlExecutor/SingleTableDeleteUpdate.php
Normal file
46
lib/Doctrine/Query/SqlExecutor/SingleTableDeleteUpdate.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Executor that executes the SQL statements for DQL DELETE/UPDATE statements on classes
|
||||
* that are mapped to a single table.
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage SingleTableDeleteUpdate
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @version $Revision$
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 2.0
|
||||
*/
|
||||
class Doctrine_Query_SqlExecutor_SingleTableDeleteUpdate extends Doctrine_Query_SqlExecutor_Abstract
|
||||
{
|
||||
public function __construct(Doctrine_Query_Production $AST)
|
||||
{
|
||||
parent::__construct($AST);
|
||||
$this->_sqlStatements = $AST->buildSql();
|
||||
}
|
||||
|
||||
public function execute(Doctrine_Connection $conn, array $params)
|
||||
{
|
||||
return $conn->exec($this->_sqlStatements, $params);
|
||||
}
|
||||
}
|
151
lib/Doctrine/Query/Token.php
Normal file
151
lib/Doctrine/Query/Token.php
Normal file
@ -0,0 +1,151 @@
|
||||
<?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 1.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] : '';
|
||||
}
|
||||
}
|
@ -1,180 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
Doctrine::autoload('Doctrine_Query_Condition');
|
||||
/**
|
||||
* Doctrine_Query_Where
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*/
|
||||
class Doctrine_Query_Where extends Doctrine_Query_Condition
|
||||
{
|
||||
public function load($where)
|
||||
{
|
||||
$where = $this->_tokenizer->bracketTrim(trim($where));
|
||||
$conn = $this->query->getConnection();
|
||||
$terms = $this->_tokenizer->sqlExplode($where);
|
||||
|
||||
if (count($terms) > 1) {
|
||||
if (substr($where, 0, 6) == 'EXISTS') {
|
||||
return $this->parseExists($where, true);
|
||||
} elseif (substr($where, 0, 10) == 'NOT EXISTS') {
|
||||
return $this->parseExists($where, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($terms) < 3) {
|
||||
$terms = $this->_tokenizer->sqlExplode($where, array('=', '<', '<>', '>', '!='));
|
||||
}
|
||||
|
||||
if (count($terms) > 1) {
|
||||
$first = array_shift($terms);
|
||||
$value = array_pop($terms);
|
||||
$operator = trim(substr($where, strlen($first), -strlen($value)));
|
||||
$table = null;
|
||||
$field = null;
|
||||
|
||||
if (strpos($first, "'") === false && strpos($first, '(') === false) {
|
||||
// normal field reference found
|
||||
$a = explode('.', $first);
|
||||
|
||||
$field = array_pop($a);
|
||||
$reference = implode('.', $a);
|
||||
|
||||
if (empty($reference)) {
|
||||
$map = $this->query->getRootDeclaration();
|
||||
|
||||
$alias = $this->query->getTableAlias($this->query->getRootAlias());
|
||||
$table = $map['table'];
|
||||
} else {
|
||||
$map = $this->query->load($reference, false);
|
||||
|
||||
$alias = $this->query->getTableAlias($reference);
|
||||
$table = $map['table'];
|
||||
}
|
||||
}
|
||||
$first = $this->query->parseClause($first);
|
||||
|
||||
$sql = $first . ' ' . $operator . ' ' . $this->parseValue($value, $table, $field);
|
||||
|
||||
return $sql;
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function parseValue($value, $table = null, $field = null)
|
||||
{
|
||||
$conn = $this->query->getConnection();
|
||||
|
||||
if (substr($value, 0, 1) == '(') {
|
||||
// trim brackets
|
||||
$trimmed = $this->_tokenizer->bracketTrim($value);
|
||||
|
||||
if (substr($trimmed, 0, 4) == 'FROM' ||
|
||||
substr($trimmed, 0, 6) == 'SELECT') {
|
||||
|
||||
// subquery found
|
||||
$q = new Doctrine_Query();
|
||||
$value = '(' . $this->query->createSubquery()->parseQuery($trimmed, false)->getQuery() . ')';
|
||||
|
||||
} elseif (substr($trimmed, 0, 4) == 'SQL:') {
|
||||
$value = '(' . substr($trimmed, 4) . ')';
|
||||
} else {
|
||||
// simple IN expression found
|
||||
$e = $this->_tokenizer->sqlExplode($trimmed, ',');
|
||||
|
||||
$value = array();
|
||||
|
||||
$index = false;
|
||||
|
||||
foreach ($e as $part) {
|
||||
if (isset($table) && isset($field)) {
|
||||
$index = $table->enumIndex($field, trim($part, "'"));
|
||||
|
||||
if (false !== $index && $conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)) {
|
||||
$index = $conn->quote($index, 'text');
|
||||
}
|
||||
}
|
||||
|
||||
if ($index !== false) {
|
||||
$value[] = $index;
|
||||
} else {
|
||||
$value[] = $this->parseLiteralValue($part);
|
||||
}
|
||||
}
|
||||
|
||||
$value = '(' . implode(', ', $value) . ')';
|
||||
}
|
||||
} else if (substr($value, 0, 1) == ':' || $value === '?') {
|
||||
// placeholder found
|
||||
if (isset($table) && isset($field) && $table->getTypeOf($field) == 'enum') {
|
||||
$this->query->addEnumParam($value, $table, $field);
|
||||
} else {
|
||||
$this->query->addEnumParam($value, null, null);
|
||||
}
|
||||
} else {
|
||||
$enumIndex = false;
|
||||
if (isset($table) && isset($field)) {
|
||||
// check if value is enumerated value
|
||||
$enumIndex = $table->enumIndex($field, trim($value, "'"));
|
||||
|
||||
if (false !== $enumIndex && $conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)) {
|
||||
$enumIndex = $conn->quote($enumIndex, 'text');
|
||||
}
|
||||
}
|
||||
|
||||
if ($enumIndex !== false) {
|
||||
$value = $enumIndex;
|
||||
} else {
|
||||
$value = $this->parseLiteralValue($value);
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* parses an EXISTS expression
|
||||
*
|
||||
* @param string $where query where part to be parsed
|
||||
* @param boolean $negation whether or not to use the NOT keyword
|
||||
* @return string
|
||||
*/
|
||||
public function parseExists($where, $negation)
|
||||
{
|
||||
$operator = ($negation) ? 'EXISTS' : 'NOT EXISTS';
|
||||
|
||||
$pos = strpos($where, '(');
|
||||
|
||||
if ($pos == false) {
|
||||
throw new Doctrine_Query_Exception('Unknown expression, expected a subquery with () -marks');
|
||||
}
|
||||
|
||||
$sub = $this->_tokenizer->bracketTrim(substr($where, $pos));
|
||||
|
||||
return $operator . ' (' . $this->query->createSubquery()->parseQuery($sub, false)->getQuery() . ')';
|
||||
}
|
||||
}
|
590
lib/Doctrine/Query_old.php
Normal file
590
lib/Doctrine/Query_old.php
Normal file
@ -0,0 +1,590 @@
|
||||
<?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>.
|
||||
*/
|
||||
Doctrine::autoload('Doctrine_Query_Abstract');
|
||||
/**
|
||||
* Doctrine_Query
|
||||
* A Doctrine_Query object represents a DQL query. It is used to query databases for
|
||||
* data in an object-oriented fashion. A DQL query understands relations and inheritance
|
||||
* and is dbms independant.
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @todo Proposal: This class does far too much. It should have only 1 task: Collecting
|
||||
* the DQL query parts and the query parameters (the query state and caching options/methods
|
||||
* can remain here, too).
|
||||
* The actual SQL construction could be done by a separate object (Doctrine_Query_SqlBuilder?)
|
||||
* whose task it is to convert DQL into SQL.
|
||||
* Furthermore the SqlBuilder? can then use other objects (Doctrine_Query_Tokenizer?),
|
||||
* (Doctrine_Query_Parser(s)?) to accomplish his work. Doctrine_Query does not need
|
||||
* to know the tokenizer/parsers. There could be extending
|
||||
* implementations of SqlBuilder? that cover the specific SQL dialects.
|
||||
* This would release Doctrine_Connection and the Doctrine_Connection_xxx classes
|
||||
* from this tedious task.
|
||||
* This would also largely reduce the currently huge interface of Doctrine_Query(_Abstract)
|
||||
* and better hide all these transformation internals from the public Query API.
|
||||
*
|
||||
* @internal The lifecycle of a Query object is the following:
|
||||
* After construction the query object is empty. Through using the fluent
|
||||
* query interface the user fills the query object with DQL parts and query parameters.
|
||||
* These get collected in {@link $_dqlParts} and {@link $_params}, respectively.
|
||||
* When the query is executed the first time, or when {@link getSqlQuery()}
|
||||
* is called the first time, the collected DQL parts get parsed and the resulting
|
||||
* connection-driver specific SQL is generated. The generated SQL parts are
|
||||
* stored in {@link $_sqlParts} and the final resulting SQL query is stored in
|
||||
* {@link $_sql}.
|
||||
*/
|
||||
class Doctrine_Query extends Doctrine_Query_Abstract implements Countable, Serializable
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $_subqueryAliases = array();
|
||||
|
||||
/**
|
||||
* @var array $_aggregateAliasMap an array containing all aggregate aliases, keys as dql aliases
|
||||
* and values as sql aliases
|
||||
*/
|
||||
protected $_aggregateAliasMap = array();
|
||||
|
||||
/**
|
||||
* @param boolean $needsSubquery
|
||||
*/
|
||||
protected $_needsSubquery = false;
|
||||
|
||||
/**
|
||||
* @param boolean $isSubquery whether or not this query object is a subquery of another
|
||||
* query object
|
||||
*/
|
||||
protected $_isSubquery;
|
||||
|
||||
/**
|
||||
* @var array $_neededTables an array containing the needed table aliases
|
||||
*/
|
||||
protected $_neededTables = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $_expressionMap = array();
|
||||
|
||||
/**
|
||||
* @var string $_sql cached SQL query
|
||||
*/
|
||||
protected $_sql;
|
||||
|
||||
protected $_dql;
|
||||
|
||||
|
||||
/**
|
||||
* create
|
||||
* returns a new Doctrine_Query object
|
||||
*
|
||||
* @param Doctrine_Connection $conn optional connection parameter
|
||||
* @return Doctrine_Query
|
||||
*/
|
||||
public static function create($conn = null)
|
||||
{
|
||||
return new Doctrine_Query($conn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the query to the state just after it has been instantiated.
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->_neededTables = array();
|
||||
$this->_expressionMap = array();
|
||||
$this->_subqueryAliases = array();
|
||||
$this->_needsSubquery = false;
|
||||
$this->_isLimitSubqueryUsed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* createSubquery
|
||||
* creates a subquery
|
||||
*
|
||||
* @return Doctrine_Hydrate
|
||||
*/
|
||||
public function createSubquery()
|
||||
{
|
||||
$class = get_class($this);
|
||||
$obj = new $class();
|
||||
|
||||
// copy the aliases to the subquery
|
||||
$obj->copyAliases($this);
|
||||
|
||||
// this prevents the 'id' being selected, re ticket #307
|
||||
$obj->isSubquery(true);
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* addEnumParam
|
||||
* sets input parameter as an enumerated parameter
|
||||
*
|
||||
* @param string $key the key of the input parameter
|
||||
* @return Doctrine_Query
|
||||
*/
|
||||
public function addEnumParam($key, $table = null, $column = null)
|
||||
{
|
||||
$array = (isset($table) || isset($column)) ? array($table, $column) : array();
|
||||
|
||||
if ($key === '?') {
|
||||
$this->_enumParams[] = $array;
|
||||
} else {
|
||||
$this->_enumParams[$key] = $array;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* getEnumParams
|
||||
* get all enumerated parameters
|
||||
*
|
||||
* @return array all enumerated parameters
|
||||
*/
|
||||
public function getEnumParams()
|
||||
{
|
||||
return $this->_enumParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* getDql
|
||||
* returns the DQL query that is represented by this query object.
|
||||
*
|
||||
* the query is built from $_dqlParts
|
||||
*
|
||||
* @return string the DQL query
|
||||
*/
|
||||
public function getDql()
|
||||
{
|
||||
if ($this->_dql !== null) {
|
||||
return $this->_dql;
|
||||
}
|
||||
|
||||
$q = '';
|
||||
$q .= ( ! empty($this->_dqlParts['select']))? 'SELECT ' . implode(', ', $this->_dqlParts['select']) : '';
|
||||
$q .= ( ! empty($this->_dqlParts['from']))? ' FROM ' . implode(' ', $this->_dqlParts['from']) : '';
|
||||
$q .= ( ! empty($this->_dqlParts['where']))? ' WHERE ' . implode(' AND ', $this->_dqlParts['where']) : '';
|
||||
$q .= ( ! empty($this->_dqlParts['groupby']))? ' GROUP BY ' . implode(', ', $this->_dqlParts['groupby']) : '';
|
||||
$q .= ( ! empty($this->_dqlParts['having']))? ' HAVING ' . implode(' AND ', $this->_dqlParts['having']) : '';
|
||||
$q .= ( ! empty($this->_dqlParts['orderby']))? ' ORDER BY ' . implode(', ', $this->_dqlParts['orderby']) : '';
|
||||
$q .= ( ! empty($this->_dqlParts['limit']))? ' LIMIT ' . implode(' ', $this->_dqlParts['limit']) : '';
|
||||
$q .= ( ! empty($this->_dqlParts['offset']))? ' OFFSET ' . implode(' ', $this->_dqlParts['offset']) : '';
|
||||
|
||||
return $q;
|
||||
}
|
||||
|
||||
/**
|
||||
* getParams
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getParams()
|
||||
{
|
||||
return array_merge($this->_params['join'], $this->_params['set'], $this->_params['where'], $this->_params['having']);
|
||||
}
|
||||
|
||||
/**
|
||||
* setParams
|
||||
*
|
||||
* @param array $params
|
||||
*/
|
||||
public function setParams(array $params = array()) {
|
||||
$this->_params = $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetchArray
|
||||
* Convenience method to execute using array fetching as hydration mode.
|
||||
*
|
||||
* @param string $params
|
||||
* @return array
|
||||
*/
|
||||
public function fetchArray($params = array()) {
|
||||
return $this->execute($params, Doctrine::HYDRATE_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* fetchOne
|
||||
* Convenience method to execute the query and return the first item
|
||||
* of the collection.
|
||||
*
|
||||
* @param string $params Parameters
|
||||
* @param int $hydrationMode Hydration mode
|
||||
* @return mixed Array or Doctrine_Collection or false if no result.
|
||||
*/
|
||||
public function fetchOne($params = array(), $hydrationMode = null)
|
||||
{
|
||||
$collection = $this->execute($params, $hydrationMode);
|
||||
|
||||
if (count($collection) === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($collection instanceof Doctrine_Collection) {
|
||||
return $collection->getFirst();
|
||||
} else if (is_array($collection)) {
|
||||
return array_shift($collection);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* isSubquery
|
||||
* if $bool parameter is set this method sets the value of
|
||||
* Doctrine_Query::$isSubquery. If this value is set to true
|
||||
* the query object will not load the primary key fields of the selected
|
||||
* components.
|
||||
*
|
||||
* If null is given as the first parameter this method retrieves the current
|
||||
* value of Doctrine_Query::$isSubquery.
|
||||
*
|
||||
* @param boolean $bool whether or not this query acts as a subquery
|
||||
* @return Doctrine_Query|bool
|
||||
*/
|
||||
public function isSubquery($bool = null)
|
||||
{
|
||||
if ($bool === null) {
|
||||
return $this->_isSubquery;
|
||||
}
|
||||
|
||||
$this->_isSubquery = (bool) $bool;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* getAggregateAlias
|
||||
*
|
||||
* @param string $dqlAlias the dql alias of an aggregate value
|
||||
* @return string
|
||||
* @deprecated
|
||||
*/
|
||||
public function getAggregateAlias($dqlAlias)
|
||||
{
|
||||
return $this->getSqlAggregateAlias($dqlAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* getSqlAggregateAlias
|
||||
*
|
||||
* @param string $dqlAlias the dql alias of an aggregate value
|
||||
* @return string
|
||||
*/
|
||||
public function getSqlAggregateAlias($dqlAlias)
|
||||
{
|
||||
if (isset($this->_aggregateAliasMap[$dqlAlias])) {
|
||||
// mark the expression as used
|
||||
$this->_expressionMap[$dqlAlias][1] = true;
|
||||
|
||||
return $this->_aggregateAliasMap[$dqlAlias];
|
||||
} else if ( ! empty($this->_pendingAggregates)) {
|
||||
$this->processPendingAggregates();
|
||||
|
||||
return $this->getSqlAggregateAlias($dqlAlias);
|
||||
} else {
|
||||
throw new Doctrine_Query_Exception('Unknown aggregate alias: ' . $dqlAlias);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* getDqlPart
|
||||
* returns a specific DQL query part.
|
||||
*
|
||||
* @param string $queryPart the name of the query part
|
||||
* @return string the DQL query part
|
||||
* @todo Description: List which query parts exist or point to the method/property
|
||||
* where they are listed.
|
||||
*/
|
||||
public function getDqlPart($queryPart)
|
||||
{
|
||||
if ( ! isset($this->_dqlParts[$queryPart])) {
|
||||
throw new Doctrine_Query_Exception('Unknown query part ' . $queryPart);
|
||||
}
|
||||
|
||||
return $this->_dqlParts[$queryPart];
|
||||
}
|
||||
|
||||
/**
|
||||
* contains
|
||||
*
|
||||
* Method to check if a arbitrary piece of dql exists
|
||||
*
|
||||
* @param string $dql Arbitrary piece of dql to check for
|
||||
* @return boolean
|
||||
*/
|
||||
public function contains($dql)
|
||||
{
|
||||
return stripos($this->getDql(), $dql) === false ? false : true;
|
||||
}
|
||||
|
||||
|
||||
public function parseSubquery($subquery)
|
||||
{
|
||||
$trimmed = trim($this->_tokenizer->bracketTrim($subquery));
|
||||
|
||||
// check for possible subqueries
|
||||
if (substr($trimmed, 0, 4) == 'FROM' || substr($trimmed, 0, 6) == 'SELECT') {
|
||||
// parse subquery
|
||||
$trimmed = $this->createSubquery()->parseDqlQuery($trimmed)->getQuery();
|
||||
} else {
|
||||
// parse normal clause
|
||||
$trimmed = $this->parseClause($trimmed);
|
||||
}
|
||||
|
||||
return '(' . $trimmed . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* preQuery
|
||||
*
|
||||
* Empty template method to provide Query subclasses with the possibility
|
||||
* to hook into the query building procedure, doing any custom / specialized
|
||||
* query building procedures that are neccessary.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function preQuery()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* postQuery
|
||||
*
|
||||
* Empty template method to provide Query subclasses with the possibility
|
||||
* to hook into the query building procedure, doing any custom / specialized
|
||||
* post query procedures (for example logging) that are neccessary.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function postQuery()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* builds the sql query from the given parameters and applies things such as
|
||||
* column aggregation inheritance and limit subqueries if needed
|
||||
*
|
||||
* @param array $params an array of prepared statement params (needed only in mysql driver
|
||||
* when limit subquery algorithm is used)
|
||||
* @return string the built sql query
|
||||
*/
|
||||
public function getSqlQuery($params = array())
|
||||
{
|
||||
if ($this->_state === self::STATE_DIRTY) {
|
||||
$this->parse();
|
||||
}
|
||||
|
||||
return $this->_sql;
|
||||
}
|
||||
|
||||
public function parse()
|
||||
{
|
||||
$this->reset();
|
||||
|
||||
// invoke the preQuery hook
|
||||
$this->preQuery();
|
||||
|
||||
$parser = new Doctrine_Query_Parser($this);
|
||||
$parser->parse();
|
||||
|
||||
if ($parser->isErrors()) {
|
||||
throw new Doctrine_Query_Parser_Exception(
|
||||
"Errors were detected during query parsing:\n" .
|
||||
implode("\n", $parser->getErrors())
|
||||
);
|
||||
}
|
||||
|
||||
$this->_state = self::STATE_CLEAN;
|
||||
$this->_sql = $parser->getSql();
|
||||
}
|
||||
|
||||
/**
|
||||
* count
|
||||
* fetches the count of the query
|
||||
*
|
||||
* This method executes the main query without all the
|
||||
* selected fields, ORDER BY part, LIMIT part and OFFSET part.
|
||||
*
|
||||
* Example:
|
||||
* Main query:
|
||||
* SELECT u.*, p.phonenumber FROM User u
|
||||
* LEFT JOIN u.Phonenumber p
|
||||
* WHERE p.phonenumber = '123 123' LIMIT 10
|
||||
*
|
||||
* The modified DQL query:
|
||||
* SELECT COUNT(DISTINCT u.id) FROM User u
|
||||
* LEFT JOIN u.Phonenumber p
|
||||
* WHERE p.phonenumber = '123 123'
|
||||
*
|
||||
* @param array $params an array of prepared statement parameters
|
||||
* @return integer the count of this query
|
||||
*/
|
||||
public function count($params = array())
|
||||
{
|
||||
// triggers dql parsing/processing
|
||||
$this->getQuery(); // this is ugly
|
||||
|
||||
// initialize temporary variables
|
||||
$where = $this->_sqlParts['where'];
|
||||
$having = $this->_sqlParts['having'];
|
||||
$groupby = $this->_sqlParts['groupby'];
|
||||
$map = reset($this->_queryComponents);
|
||||
$componentAlias = key($this->_queryComponents);
|
||||
$table = $map['table'];
|
||||
|
||||
// build the query base
|
||||
$q = 'SELECT COUNT(DISTINCT ' . $this->getTableAlias($componentAlias)
|
||||
. '.' . implode(',', $table->getIdentifierColumnNames())
|
||||
. ') AS num_results';
|
||||
|
||||
foreach ($this->_sqlParts['select'] as $field) {
|
||||
if (strpos($field, '(') !== false) {
|
||||
$q .= ', ' . $field;
|
||||
}
|
||||
}
|
||||
|
||||
$q .= ' FROM ' . $this->_buildSqlFromPart();
|
||||
|
||||
// append discriminator column conditions (if any)
|
||||
$string = $this->_createDiscriminatorConditionSql();
|
||||
if ( ! empty($string)) {
|
||||
$where[] = $string;
|
||||
}
|
||||
|
||||
// append conditions
|
||||
$q .= ( ! empty($where)) ? ' WHERE ' . implode(' AND ', $where) : '';
|
||||
$q .= ( ! empty($groupby)) ? ' GROUP BY ' . implode(', ', $groupby) : '';
|
||||
$q .= ( ! empty($having)) ? ' HAVING ' . implode(' AND ', $having): '';
|
||||
|
||||
if ( ! is_array($params)) {
|
||||
$params = array($params);
|
||||
}
|
||||
// append parameters
|
||||
$params = array_merge($this->_params['where'], $this->_params['having'], $params);
|
||||
|
||||
$params = $this->convertEnums($params);
|
||||
|
||||
$results = $this->getConnection()->fetchAll($q, $params);
|
||||
|
||||
if (count($results) > 1) {
|
||||
$count = 0;
|
||||
foreach ($results as $result) {
|
||||
$count += $result['num_results'];
|
||||
}
|
||||
} else {
|
||||
$count = isset($results[0]) ? $results[0]['num_results']:0;
|
||||
}
|
||||
|
||||
return (int) $count;
|
||||
}
|
||||
|
||||
public function setDql($query)
|
||||
{
|
||||
$this->_dql = $query;
|
||||
$this->_state = self::STATE_DIRTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* query
|
||||
* query the database with DQL (Doctrine Query Language)
|
||||
*
|
||||
* @param string $query DQL query
|
||||
* @param array $params prepared statement parameters
|
||||
* @param int $hydrationMode Doctrine::FETCH_ARRAY or Doctrine::FETCH_RECORD
|
||||
* @see Doctrine::FETCH_* constants
|
||||
* @return mixed
|
||||
*/
|
||||
public function query($query, $params = array(), $hydrationMode = null)
|
||||
{
|
||||
$this->setDql($query);
|
||||
return $this->execute($params, $hydrationMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a Doctrine_Query object.
|
||||
*
|
||||
* @param Doctrine_Query Doctrine query instance.
|
||||
* If ommited the instance itself will be used as source.
|
||||
* @return Doctrine_Query Copy of the Doctrine_Query instance.
|
||||
*/
|
||||
public function copy(Doctrine_Query $query = null)
|
||||
{
|
||||
if ( ! $query) {
|
||||
$query = $this;
|
||||
}
|
||||
|
||||
$new = new Doctrine_Query();
|
||||
$new->_dqlParts = $query->_dqlParts;
|
||||
$new->_params = $query->_params;
|
||||
$new->_hydrator = $query->_hydrator;
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the resources used by the query object. It especially breaks a
|
||||
* cyclic reference between the query object and it's parsers. This enables
|
||||
* PHP's current GC to reclaim the memory.
|
||||
* This method can therefore be used to reduce memory usage when creating a lot
|
||||
* of query objects during a request.
|
||||
*
|
||||
* @return Doctrine_Query this object
|
||||
*/
|
||||
public function free()
|
||||
{
|
||||
$this->reset();
|
||||
$this->_parsers = array();
|
||||
$this->_dqlParts = array();
|
||||
$this->_enumParams = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* serialize
|
||||
* this method is automatically called when this Doctrine_Hydrate is serialized
|
||||
*
|
||||
* @return array an array of serialized properties
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
$vars = get_object_vars($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* unseralize
|
||||
* this method is automatically called everytime a Doctrine_Hydrate object is unserialized
|
||||
*
|
||||
* @param string $serialized Doctrine_Record as serialized string
|
||||
* @return void
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -236,6 +236,18 @@ abstract class Doctrine_Relation implements ArrayAccess
|
||||
{
|
||||
return $this->definition['relName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* getTable
|
||||
* returns the foreign table object
|
||||
*
|
||||
* @return object Doctrine_Table
|
||||
*/
|
||||
final public function getTable()
|
||||
{
|
||||
return Doctrine_EntityManager::getManager($this->definition['class'])
|
||||
->getClassMetadata($this->definition['class']);
|
||||
}
|
||||
|
||||
/**
|
||||
* getType
|
||||
@ -255,7 +267,7 @@ abstract class Doctrine_Relation implements ArrayAccess
|
||||
*
|
||||
* @return object Doctrine_Table
|
||||
*/
|
||||
final public function getTable()
|
||||
final public function getClassMetadata()
|
||||
{
|
||||
return Doctrine_EntityManager::getManager($this->definition['class'])
|
||||
->getClassMetadata($this->definition['class']);
|
||||
@ -334,7 +346,7 @@ abstract class Doctrine_Relation implements ArrayAccess
|
||||
*/
|
||||
public function getRelationDql($count)
|
||||
{
|
||||
$component = $this->getTable()->getComponentName();
|
||||
$component = $this->getClassMetadata()->getComponentName();
|
||||
|
||||
$dql = 'FROM ' . $component
|
||||
. ' WHERE ' . $component . '.' . $this->definition['foreign']
|
||||
|
@ -7,6 +7,7 @@ require_once 'lib/DoctrineTestInit.php';
|
||||
|
||||
// Suites
|
||||
require_once 'Orm/Component/AllTests.php';
|
||||
require_once 'Orm/Query/AllTests.php';
|
||||
require_once 'Orm/Hydration/AllTests.php';
|
||||
require_once 'Orm/Ticket/AllTests.php';
|
||||
|
||||
@ -28,13 +29,14 @@ class Orm_AllTests
|
||||
//$suite->addTestSuite('Orm_ConfigurableTestCase');
|
||||
|
||||
$suite->addTest(Orm_Component_AllTests::suite());
|
||||
$suite->addTest(Orm_Query_AllTests::suite());
|
||||
$suite->addTest(Orm_Hydration_AllTests::suite());
|
||||
$suite->addTest(Orm_Ticket_AllTests::suite());
|
||||
|
||||
|
||||
return $suite;
|
||||
}
|
||||
}
|
||||
|
||||
if (PHPUnit_MAIN_METHOD == 'Orm_AllTests::main') {
|
||||
Orm_AllTests::main();
|
||||
}
|
||||
}
|
||||
|
@ -28,5 +28,5 @@ class Orm_Component_AllTests
|
||||
}
|
||||
|
||||
if (PHPUnit_MAIN_METHOD == 'Orm_Component_AllTests::main') {
|
||||
Dbal_Component_AllTests::main();
|
||||
Orm_Component_AllTests::main();
|
||||
}
|
||||
|
41
tests/Orm/Query/AllTests.php
Executable file
41
tests/Orm/Query/AllTests.php
Executable file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
if (!defined('PHPUnit_MAIN_METHOD')) {
|
||||
define('PHPUnit_MAIN_METHOD', 'Orm_Query_AllTests::main');
|
||||
}
|
||||
|
||||
require_once 'lib/DoctrineTestInit.php';
|
||||
|
||||
require_once 'IdentifierRecognitionTest.php';
|
||||
require_once 'ScannerTest.php';
|
||||
require_once 'DqlGenerationTest.php';
|
||||
require_once 'DeleteSqlGenerationTest.php';
|
||||
require_once 'UpdateSqlGenerationTest.php';
|
||||
require_once 'SelectSqlGenerationTest.php';
|
||||
require_once 'LanguageRecognitionTest.php';
|
||||
|
||||
class Orm_Query_AllTests
|
||||
{
|
||||
public static function main()
|
||||
{
|
||||
PHPUnit_TextUI_TestRunner::run(self::suite());
|
||||
}
|
||||
|
||||
public static function suite()
|
||||
{
|
||||
$suite = new Doctrine_TestSuite('Doctrine Orm Query');
|
||||
|
||||
$suite->addTestSuite('Orm_Query_IdentifierRecognitionTest');
|
||||
$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');
|
||||
|
||||
return $suite;
|
||||
}
|
||||
}
|
||||
|
||||
if (PHPUnit_MAIN_METHOD == 'Orm_Query_AllTests::main') {
|
||||
Orm_Query_AllTests::main();
|
||||
}
|
270
tests/Orm/Query/DeleteSqlGenerationTest.php
Executable file
270
tests/Orm/Query/DeleteSqlGenerationTest.php
Executable file
@ -0,0 +1,270 @@
|
||||
<?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>.
|
||||
*/
|
||||
require_once 'lib/DoctrineTestInit.php';
|
||||
/**
|
||||
* Test case for testing the saving and referencing of query identifiers.
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @todo 1) [romanb] We might want to split the SQL generation tests into multiple
|
||||
* testcases later since we'll have a lot of them and we might want to have special SQL
|
||||
* generation tests for some dbms specific SQL syntaxes.
|
||||
*/
|
||||
class Orm_Query_DeleteSqlGenerationTest extends Doctrine_OrmTestCase
|
||||
{
|
||||
public function testWithoutWhere()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
// NO WhereClause
|
||||
$q->setDql('DELETE CmsUser u');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE 1 = 1', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE FROM CmsUser u');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE 1 = 1', $q->getSql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
public function testWithWhere()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
// "WHERE" ConditionalExpression
|
||||
// ConditionalExpression = ConditionalTerm {"OR" ConditionalTerm}
|
||||
// ConditionalTerm = ConditionalFactor {"AND" ConditionalFactor}
|
||||
// ConditionalFactor = ["NOT"] ConditionalPrimary
|
||||
// ConditionalPrimary = SimpleConditionalExpression | "(" ConditionalExpression ")"
|
||||
// SimpleConditionalExpression
|
||||
// = Expression (ComparisonExpression | BetweenExpression | LikeExpression
|
||||
// | InExpression | NullComparisonExpression) | ExistsExpression
|
||||
|
||||
// If this one test fail, all others will fail too. That's the simplest case possible
|
||||
$q->setDql('DELETE CmsUser u WHERE id = ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.id = ?', $q->getSql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
public function testWithConditionalExpressions()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE u.username = ? OR u.name = ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.username = ? OR cu.name = ?', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE u.id = ? OR ( u.username = ? OR u.name = ? )');
|
||||
$this->assertEquals(
|
||||
'DELETE FROM cms_user cu WHERE cu.id = ? OR (cu.username = ? OR cu.name = ?)',
|
||||
$q->getSql()
|
||||
);
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE FROM CmsUser WHERE id = ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.id = ?', $q->getSql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
public function testInvalidSyntaxIsRejected()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
$invalidDql = 'FOOBAR CmsUser';
|
||||
$q->setDql($invalidDql);
|
||||
try {
|
||||
$q->getSql();
|
||||
$this->fail("Invalid DQL '$invalidDql' was not rejected.");
|
||||
} catch (Doctrine_Query_Parser_Exception $parseEx) {}
|
||||
|
||||
$invalidDql = 'DELETE FROM hey.boy';
|
||||
$q->setDql($invalidDql);
|
||||
try {
|
||||
$q->getSql();
|
||||
$this->fail("Invalid DQL '$invalidDql' was not rejected.");
|
||||
} catch (Doctrine_Query_Parser_Exception $parseEx) {}
|
||||
|
||||
$invalidDql = 'DELETE FROM CmsUser cu WHERE cu.my.thing > ?';
|
||||
$q->setDql($invalidDql);
|
||||
try {
|
||||
$q->getSql();
|
||||
$this->fail("Invalid DQL '$invalidDql' was not rejected.");
|
||||
} catch (Doctrine_Relation_Exception $parseEx) {}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function testParserIsCaseAgnostic()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
$q->setDql('delete from CmsUser u where u.username = ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.username = ?', $q->getSql());
|
||||
}
|
||||
|
||||
|
||||
public function testWithConditionalTerms()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE u.username = ? AND u.name = ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.username = ? AND cu.name = ?', $q->getSql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
public function testWithConditionalFactors()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE NOT id != ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE NOT cu.id <> ?', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE NOT ( id != ? )');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE NOT (cu.id <> ?)', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE NOT ( id != ? AND username = ? )');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE NOT (cu.id <> ? AND cu.username = ?)', $q->getSql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
// ConditionalPrimary was already tested (see testDeleteWithWhere() and testDeleteWithConditionalFactors())
|
||||
|
||||
|
||||
public function testWithExprAndComparison()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
// id = ? was already tested (see testDeleteWithWhere())
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE id > ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.id > ?', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE id >= ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.id >= ?', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE id < ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.id < ?', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE id <= ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.id <= ?', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE id <> ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.id <> ?', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE id != ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.id <> ?', $q->getSql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
public function testWithExprAndBetween()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
// "WHERE" Expression BetweenExpression
|
||||
$q->setDql('DELETE CmsUser u WHERE u.id NOT BETWEEN ? AND ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.id NOT BETWEEN ? AND ?', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE u.id BETWEEN ? AND ? AND u.username != ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.id BETWEEN ? AND ? AND cu.username <> ?', $q->getSql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
public function testWithExprAndLike()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
// "WHERE" Expression LikeExpression
|
||||
$q->setDql('DELETE CmsUser u WHERE u.username NOT LIKE ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.username NOT LIKE ?', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql("DELETE CmsUser u WHERE u.username LIKE ? ESCAPE '\\'");
|
||||
$this->assertEquals("DELETE FROM cms_user cu WHERE cu.username LIKE ? ESCAPE '\\'", $q->getSql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
public function testWithExprAndIn()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
// "WHERE" Expression InExpression
|
||||
$q->setDql('DELETE CmsUser u WHERE u.id IN ( ?, ?, ?, ? )');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.id IN (?, ?, ?, ?)', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE u.id NOT IN ( ?, ? )');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.id NOT IN (?, ?)', $q->getSql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
public function testWithExprAndNull()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
// "WHERE" Expression NullComparisonExpression
|
||||
$q->setDql('DELETE CmsUser u WHERE u.name IS NULL');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.name IS NULL', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE u.name IS NOT NULL');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.name IS NOT NULL', $q->getSql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
// All previously defined tests used Primary as PathExpression. No need to check it again.
|
||||
|
||||
public function testWithPrimaryAsAtom()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
// Atom = string | integer | float | boolean | input_parameter
|
||||
$q->setDql('DELETE CmsUser u WHERE 1 = 1');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE 1 = 1', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('DELETE CmsUser u WHERE ? = 1');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE ? = 1', $q->getSql());
|
||||
$q->free();
|
||||
}
|
||||
}
|
249
tests/Orm/Query/DqlGenerationTest.php
Executable file
249
tests/Orm/Query/DqlGenerationTest.php
Executable file
@ -0,0 +1,249 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test case for testing the saving and referencing of query identifiers.
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Orm_Query_DqlGenerationTest extends Doctrine_OrmTestCase
|
||||
{
|
||||
const QueryClass = 'Doctrine_Query';
|
||||
|
||||
public function testSelect()
|
||||
{
|
||||
$class = self::QueryClass;
|
||||
$q = new $class();
|
||||
|
||||
// select and from
|
||||
$q->setDql('FROM User u');
|
||||
$this->assertEquals('FROM User u', $q->getDql()); // Internally we use SELECT * FROM User u to process the DQL
|
||||
$q->free();
|
||||
|
||||
$q->select()->from('User u');
|
||||
$this->assertEquals('SELECT * FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.*')->from('User u');
|
||||
$this->assertEquals('SELECT u.* FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.id')->from('User u');
|
||||
$this->assertEquals('SELECT u.id FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.id, u.name')->from('User u');
|
||||
$this->assertEquals('SELECT u.id, u.name FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name AS myCustomName')->from('User u');
|
||||
$this->assertEquals('SELECT u.name AS myCustomName FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.id')->select('u.name')->from('User u');
|
||||
$this->assertEquals('SELECT u.id, u.name FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
public function testSelectDistinct()
|
||||
{
|
||||
$class = self::QueryClass;
|
||||
$q = new $class();
|
||||
|
||||
$q->select()->distinct()->from('User u');
|
||||
$this->assertEquals('SELECT DISTINCT * FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->distinct(false)->from('User u');
|
||||
$this->assertEquals('SELECT u.name FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select()->distinct(false)->from('User u');
|
||||
$this->assertEquals('SELECT * FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->distinct()->from('User u');
|
||||
$this->assertEquals('SELECT DISTINCT u.name FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name, u.email')->distinct()->from('User u');
|
||||
$this->assertEquals('SELECT DISTINCT u.name, u.email FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->select('u.email')->distinct()->from('User u');
|
||||
$this->assertEquals('SELECT DISTINCT u.name, u.email FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select('DISTINCT u.name')->from('User u');
|
||||
$this->assertEquals('SELECT DISTINCT u.name FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select('DISTINCT u.name, u.email')->from('User u');
|
||||
$this->assertEquals('SELECT DISTINCT u.name, u.email FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select('DISTINCT u.name')->select('u.email')->from('User u');
|
||||
$this->assertEquals('SELECT DISTINCT u.name, u.email FROM User u', $q->getDql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
public function testSelectJoin()
|
||||
{
|
||||
$class = self::QueryClass;
|
||||
$q = new $class();
|
||||
|
||||
$q->select('u.*')->from('User u')->join('u.Group g')->where('g.id = ?', 1);
|
||||
$this->assertEquals('SELECT u.* FROM User u INNER JOIN u.Group g WHERE g.id = ?', $q->getDql());
|
||||
$this->assertEquals(array(1), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.*')->from('User u')->innerJoin('u.Group g')->where('g.id = ?', 1);
|
||||
$this->assertEquals('SELECT u.* FROM User u INNER JOIN u.Group g WHERE g.id = ?', $q->getDql());
|
||||
$this->assertEquals(array(1), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.*')->from('User u')->leftJoin('u.Group g')->where('g.id IS NULL');
|
||||
$this->assertEquals('SELECT u.* FROM User u LEFT JOIN u.Group g WHERE g.id IS NULL', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.*')->from('User u')->leftJoin('u.UserGroup ug')->leftJoin('ug.Group g')->where('g.name = ?', 'admin');
|
||||
$this->assertEquals('SELECT u.* FROM User u LEFT JOIN u.UserGroup ug LEFT JOIN ug.Group g WHERE g.name = ?', $q->getDql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
public function testSelectWhere()
|
||||
{
|
||||
$class = self::QueryClass;
|
||||
$q = new $class();
|
||||
|
||||
$q->select('u.name')->from('User u')->where('u.id = ?', 1);
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE u.id = ?', $q->getDql());
|
||||
$this->assertEquals(array(1), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->from('User u')->where('u.id = ? AND u.type != ?', array(1, 'admin'));
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE u.id = ? AND u.type != ?', $q->getDql());
|
||||
$this->assertEquals(array(1, 'admin'), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->from('User u')->where('u.id = ?', 1)->andWhere('u.type != ?', 'admin');
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE u.id = ? AND u.type != ?', $q->getDql());
|
||||
$this->assertEquals(array(1, 'admin'), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->from('User u')->where('( u.id = ?', 1)->andWhere('u.type != ? )', 'admin');
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE ( u.id = ? AND u.type != ? )', $q->getDql());
|
||||
$this->assertEquals(array(1, 'admin'), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->from('User u')->where('u.id = ? OR u.type != ?', array(1, 'admin'));
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE u.id = ? OR u.type != ?', $q->getDql());
|
||||
$this->assertEquals(array(1, 'admin'), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->from('User u')->where('u.id = ?', 1)->orWhere('u.type != ?', 'admin');
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE u.id = ? OR u.type != ?', $q->getDql());
|
||||
$this->assertEquals(array(1, 'admin'), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->from('User u')->andwhere('u.id = ?', 1)->andWhere('u.type != ?', 'admin')->orWhere('u.email = ?', 'admin@localhost');
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE u.id = ? AND u.type != ? OR u.email = ?', $q->getDql());
|
||||
$this->assertEquals(array(1, 'admin', 'admin@localhost'), $q->getParams());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
public function testSelectWhereIn()
|
||||
{
|
||||
$class = self::QueryClass;
|
||||
$q = new $class();
|
||||
|
||||
$q->select('u.name')->from('User u')->whereIn('u.id', array(1, 2, 3, 4, 5));
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE u.id IN (?, ?, ?, ?, ?)', $q->getDql());
|
||||
$this->assertEquals(array(1, 2, 3, 4, 5), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->from('User u')->whereNotIn('u.id', array(1, 2, 3));
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE u.id NOT IN (?, ?, ?)', $q->getDql());
|
||||
$this->assertEquals(array(1, 2, 3), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->from('User u')->where('u.type = ?', 'admin')->andWhereIn('u.id', array(1, 2));
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE u.type = ? AND u.id IN (?, ?)', $q->getDql());
|
||||
$this->assertEquals(array('admin', 1, 2), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->from('User u')->where('u.type = ?', 'admin')->andWhereNotIn('u.id', array(1, 2));
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE u.type = ? AND u.id NOT IN (?, ?)', $q->getDql());
|
||||
$this->assertEquals(array('admin', 1, 2), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->from('User u')->whereIn('u.type', array('admin', 'moderator'))->andWhereNotIn('u.id', array(1, 2, 3, 4));
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE u.type IN (?, ?) AND u.id NOT IN (?, ?, ?, ?)', $q->getDql());
|
||||
$this->assertEquals(array('admin', 'moderator', 1, 2, 3, 4), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->from('User u')->whereIn('u.type', array('admin', 'moderator'))->orWhereIn('u.id', array(1, 2, 3, 4));
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE u.type IN (?, ?) OR u.id IN (?, ?, ?, ?)', $q->getDql());
|
||||
$this->assertEquals(array('admin', 'moderator', 1, 2, 3, 4), $q->getParams());
|
||||
$q->free();
|
||||
|
||||
$q->select('u.name')->from('User u')->whereIn('u.type', array('admin', 'moderator'))->andWhereNotIn('u.id', array(1, 2))->orWhereNotIn('u.type', array('admin', 'moderator'))->andWhereNotIn('u.email', array('user@localhost', 'guest@localhost'));
|
||||
$this->assertEquals('SELECT u.name FROM User u WHERE u.type IN (?, ?) AND u.id NOT IN (?, ?) OR u.type NOT IN (?, ?) AND u.email NOT IN (?, ?)', $q->getDql());
|
||||
$this->assertEquals(array('admin', 'moderator', 1, 2, 'admin', 'moderator', 'user@localhost', 'guest@localhost'), $q->getParams());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
|
||||
public function testDelete()
|
||||
{
|
||||
$class = self::QueryClass;
|
||||
$q = new $class();
|
||||
|
||||
$q->setDql('DELETE CmsUser u');
|
||||
$this->assertEquals('DELETE CmsUser u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->delete()->from('CmsUser u');
|
||||
$this->assertEquals('DELETE FROM CmsUser u', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->delete()->from('CmsUser u')->where('u.id = ?', 1);
|
||||
$this->assertEquals('DELETE FROM CmsUser u WHERE u.id = ?', $q->getDql());
|
||||
$q->free();
|
||||
|
||||
$q->delete()->from('CmsUser u')->where('u.username = ?', 'gblanco')->orWhere('u.name = ?', 'Guilherme');
|
||||
$this->assertEquals('DELETE FROM CmsUser u WHERE u.username = ? OR u.name = ?', $q->getDql());
|
||||
$q->free();
|
||||
}
|
||||
|
||||
}
|
124
tests/Orm/Query/IdentifierRecognitionTest.php
Executable file
124
tests/Orm/Query/IdentifierRecognitionTest.php
Executable file
@ -0,0 +1,124 @@
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
require_once 'lib/DoctrineTestInit.php';
|
||||
|
||||
/**
|
||||
* Test case for testing the saving and referencing of query identifiers.
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Orm_Query_IdentifierRecognitionTest extends Doctrine_OrmTestCase
|
||||
{
|
||||
|
||||
public function testSingleAliasDeclarationIsSupported()
|
||||
{
|
||||
$query = new Doctrine_Query;
|
||||
$query->setDql('SELECT u.* FROM CmsUser u');
|
||||
$parserResult = $query->parse();
|
||||
|
||||
$decl = $parserResult->getQueryComponent('u');
|
||||
|
||||
$this->assertTrue($decl['metadata'] instanceof Doctrine_ClassMetadata);
|
||||
$this->assertEquals(null, $decl['relation']);
|
||||
$this->assertEquals(null, $decl['parent']);
|
||||
$this->assertEquals(null, $decl['agg']);
|
||||
$this->assertEquals(null, $decl['map']);
|
||||
}
|
||||
|
||||
public function testSingleAliasDeclarationWithIndexByIsSupported()
|
||||
{
|
||||
$query = new Doctrine_Query;
|
||||
$query->setDql('SELECT u.* FROM CmsUser u INDEX BY name');
|
||||
$parserResult = $query->parse();
|
||||
|
||||
$decl = $parserResult->getQueryComponent('u');
|
||||
|
||||
$this->assertTrue($decl['metadata'] instanceof Doctrine_ClassMetadata);
|
||||
$this->assertEquals(null, $decl['relation']);
|
||||
$this->assertEquals(null, $decl['parent']);
|
||||
$this->assertEquals(null, $decl['agg']);
|
||||
$this->assertEquals('name', $decl['map']);
|
||||
}
|
||||
|
||||
public function testQueryParserSupportsMultipleAliasDeclarations()
|
||||
{
|
||||
$query = new Doctrine_Query;
|
||||
$query->setDql('SELECT u.* FROM CmsUser u INDEX BY name LEFT JOIN u.phonenumbers p');
|
||||
$parserResult = $query->parse();
|
||||
|
||||
$decl = $parserResult->getQueryComponent('u');
|
||||
|
||||
$this->assertTrue($decl['metadata'] instanceof Doctrine_ClassMetadata);
|
||||
$this->assertEquals(null, $decl['relation']);
|
||||
$this->assertEquals(null, $decl['parent']);
|
||||
$this->assertEquals(null, $decl['agg']);
|
||||
$this->assertEquals('name', $decl['map']);
|
||||
|
||||
$decl = $parserResult->getQueryComponent('p');
|
||||
|
||||
$this->assertTrue($decl['metadata'] instanceof Doctrine_ClassMetadata);
|
||||
$this->assertTrue($decl['relation'] instanceof Doctrine_Relation);
|
||||
$this->assertEquals('u', $decl['parent']);
|
||||
$this->assertEquals(null, $decl['agg']);
|
||||
$this->assertEquals(null, $decl['map']);
|
||||
}
|
||||
|
||||
|
||||
public function testQueryParserSupportsMultipleAliasDeclarationsWithIndexBy()
|
||||
{
|
||||
$query = new Doctrine_Query;
|
||||
$query->setDql('SELECT u.* FROM CmsUser u INDEX BY name LEFT JOIN u.articles a INNER JOIN u.phonenumbers pn INDEX BY phonenumber');
|
||||
$parserResult = $query->parse();
|
||||
|
||||
$decl = $parserResult->getQueryComponent('u');
|
||||
|
||||
$this->assertTrue($decl['metadata'] instanceof Doctrine_ClassMetadata);
|
||||
$this->assertEquals(null, $decl['relation']);
|
||||
$this->assertEquals(null, $decl['parent']);
|
||||
$this->assertEquals(null, $decl['agg']);
|
||||
$this->assertEquals('name', $decl['map']);
|
||||
|
||||
$decl = $parserResult->getQueryComponent('a');
|
||||
|
||||
$this->assertTrue($decl['metadata'] instanceof Doctrine_ClassMetadata);
|
||||
$this->assertTrue($decl['relation'] instanceof Doctrine_Relation);
|
||||
$this->assertEquals('u', $decl['parent']);
|
||||
$this->assertEquals(null, $decl['agg']);
|
||||
$this->assertEquals(null, $decl['map']);
|
||||
|
||||
$decl = $parserResult->getQueryComponent('pn');
|
||||
|
||||
$this->assertTrue($decl['metadata'] instanceof Doctrine_ClassMetadata);
|
||||
$this->assertTrue($decl['relation'] instanceof Doctrine_Relation);
|
||||
$this->assertEquals('u', $decl['parent']);
|
||||
$this->assertEquals(null, $decl['agg']);
|
||||
$this->assertEquals('phonenumber', $decl['map']);
|
||||
}
|
||||
}
|
345
tests/Orm/Query/LanguageRecognitionTest.php
Executable file
345
tests/Orm/Query/LanguageRecognitionTest.php
Executable file
@ -0,0 +1,345 @@
|
||||
<?php
|
||||
class Orm_Query_LanguageRecognitionTest extends Doctrine_OrmTestCase
|
||||
{
|
||||
public function assertValidDql($dql, $method = '')
|
||||
{
|
||||
try {
|
||||
$query = new Doctrine_Query;
|
||||
$query->setDql($dql);
|
||||
$parserResult = $query->parse();
|
||||
} catch (Doctrine_Exception $e) {
|
||||
$this->fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function assertInvalidDql($dql)
|
||||
{
|
||||
try {
|
||||
$query = new Doctrine_Query;
|
||||
$query->setDql($dql);
|
||||
$parserResult = $query->parse();
|
||||
|
||||
$this->fail('No syntax errors were detected, when syntax errors were expected');
|
||||
} catch (Doctrine_Exception $e) {
|
||||
// It was expected!
|
||||
}
|
||||
}
|
||||
|
||||
public function testEmptyQueryString()
|
||||
{
|
||||
$this->assertInvalidDql('');
|
||||
}
|
||||
|
||||
public function testPlainFromClauseWithoutAlias()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM CmsUser');
|
||||
}
|
||||
|
||||
public function testPlainFromClauseWithAlias()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.* FROM CmsUser u');
|
||||
}
|
||||
|
||||
public function testSelectSingleComponentWithAsterisk()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.* FROM CmsUser u');
|
||||
}
|
||||
|
||||
public function testInvalidSelectSingleComponentWithAsterisk()
|
||||
{
|
||||
$this->assertValidDql('SELECT p.* FROM CmsUser u');
|
||||
}
|
||||
|
||||
public function testSelectSingleComponentWithMultipleColumns()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name, u.username FROM CmsUser u');
|
||||
}
|
||||
|
||||
public function testSelectMultipleComponentsWithAsterisk()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, p.* FROM CmsUser u, u.phonenumbers p');
|
||||
}
|
||||
|
||||
public function testSelectDistinctIsSupported()
|
||||
{
|
||||
$this->assertValidDql('SELECT DISTINCT u.name FROM CmsUser u');
|
||||
}
|
||||
|
||||
public function testAggregateFunctionInSelect()
|
||||
{
|
||||
$this->assertValidDql('SELECT COUNT(u.id) FROM CmsUser u');
|
||||
}
|
||||
|
||||
public function testAggregateFunctionWithDistinctInSelect()
|
||||
{
|
||||
$this->assertValidDql('SELECT COUNT(DISTINCT u.name) FROM CmsUser u');
|
||||
}
|
||||
|
||||
public function testFunctionalExpressionsSupportedInWherePart()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.name FROM CmsUser u WHERE TRIM(u.name) = 'someone'");
|
||||
}
|
||||
|
||||
public function testArithmeticExpressionsSupportedInWherePart()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.* FROM CmsUser u WHERE ((u.id + 5000) * u.id + 3) < 10000000');
|
||||
}
|
||||
|
||||
public function testInExpressionSupportedInWherePart()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM CmsUser WHERE CmsUser.id IN (1, 2)');
|
||||
}
|
||||
|
||||
public function testNotInExpressionSupportedInWherePart()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM CmsUser WHERE CmsUser.id NOT IN (1)');
|
||||
}
|
||||
|
||||
public function testExistsExpressionSupportedInWherePart()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM CmsUser u WHERE EXISTS (SELECT p.user_id FROM CmsPhonenumber p WHERE p.user_id = u.id)');
|
||||
}
|
||||
|
||||
public function testNotExistsExpressionSupportedInWherePart()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM CmsUser u WHERE NOT EXISTS (SELECT p.user_id FROM CmsPhonenumber p WHERE p.user_id = u.id)');
|
||||
}
|
||||
|
||||
public function testLiteralValueAsInOperatorOperandIsSupported()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.id FROM CmsUser u WHERE 1 IN (1, 2)');
|
||||
}
|
||||
|
||||
public function testUpdateWorksWithOneColumn()
|
||||
{
|
||||
$this->assertValidDql("UPDATE CmsUser u SET u.name = 'someone'");
|
||||
}
|
||||
|
||||
public function testUpdateWorksWithMultipleColumns()
|
||||
{
|
||||
$this->assertValidDql("UPDATE CmsUser u SET u.name = 'someone', u.username = 'some'");
|
||||
}
|
||||
|
||||
public function testUpdateSupportsConditions()
|
||||
{
|
||||
$this->assertValidDql("UPDATE CmsUser u SET u.name = 'someone' WHERE u.id = 5");
|
||||
}
|
||||
|
||||
public function testDeleteAll()
|
||||
{
|
||||
$this->assertValidDql('DELETE FROM CmsUser');
|
||||
}
|
||||
|
||||
public function testDeleteWithCondition()
|
||||
{
|
||||
$this->assertValidDql('DELETE FROM CmsUser WHERE id = 3');
|
||||
}
|
||||
/*
|
||||
public function testDeleteWithLimit()
|
||||
{
|
||||
// LIMIT is not supported in DELETE
|
||||
$this->assertValidDql('DELETE FROM CmsUser LIMIT 20');
|
||||
}
|
||||
|
||||
public function testDeleteWithLimitAndOffset()
|
||||
{
|
||||
// LIMIT and OFFSET are not supported in DELETE
|
||||
$this->assertValidDql('DELETE FROM CmsUser LIMIT 10 OFFSET 20');
|
||||
}
|
||||
*/
|
||||
public function testAdditionExpression()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, (u.id + u.id) addition FROM CmsUser u');
|
||||
}
|
||||
|
||||
public function testSubtractionExpression()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, (u.id - u.id) subtraction FROM CmsUser u');
|
||||
}
|
||||
|
||||
public function testDivisionExpression()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, (u.id/u.id) division FROM CmsUser u');
|
||||
}
|
||||
|
||||
public function testMultiplicationExpression()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, (u.id * u.id) multiplication FROM CmsUser u');
|
||||
}
|
||||
|
||||
public function testNegationExpression()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, -u.id negation FROM CmsUser u');
|
||||
}
|
||||
|
||||
public function testExpressionWithPrecedingPlusSign()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, +u.id FROM CmsUser u');
|
||||
}
|
||||
|
||||
public function testAggregateFunctionInHavingClause()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name FROM CmsUser u LEFT JOIN u.phonenumbers p HAVING COUNT(p.phonenumber) > 2');
|
||||
$this->assertValidDql("SELECT u.name FROM CmsUser u LEFT JOIN u.phonenumbers p HAVING MAX(u.name) = 'zYne'");
|
||||
}
|
||||
|
||||
public function testMultipleAggregateFunctionsInHavingClause()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.name FROM CmsUser u LEFT JOIN u.phonenumbers p HAVING MAX(u.name) = 'zYne'");
|
||||
}
|
||||
|
||||
public function testLeftJoin()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM CmsUser u LEFT JOIN u.phonenumbers');
|
||||
}
|
||||
|
||||
public function testJoin()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.* FROM CmsUser u JOIN u.phonenumbers');
|
||||
}
|
||||
|
||||
public function testInnerJoin()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM CmsUser u INNER JOIN u.phonenumbers');
|
||||
}
|
||||
|
||||
public function testMultipleLeftJoin()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM CmsUser u LEFT JOIN u.articles LEFT JOIN u.phonenumbers');
|
||||
}
|
||||
|
||||
public function testMultipleInnerJoin()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name FROM CmsUser u INNER JOIN u.articles INNER JOIN u.phonenumbers');
|
||||
}
|
||||
|
||||
public function testMultipleInnerJoin2()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name FROM CmsUser u INNER JOIN u.articles, u.phonenumbers');
|
||||
}
|
||||
|
||||
public function testMixingOfJoins()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name, a.topic, p.phonenumber FROM CmsUser u INNER JOIN u.articles a LEFT JOIN u.phonenumbers p');
|
||||
}
|
||||
|
||||
public function testMixingOfJoins2()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name, u.articles.topic, c.text FROM CmsUser u INNER JOIN u.articles.comments c');
|
||||
}
|
||||
|
||||
public function testOrderBySingleColumn()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name FROM CmsUser u ORDER BY u.name');
|
||||
}
|
||||
|
||||
public function testOrderBySingleColumnAscending()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name FROM CmsUser u ORDER BY u.name ASC');
|
||||
}
|
||||
|
||||
public function testOrderBySingleColumnDescending()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name FROM CmsUser u ORDER BY u.name DESC');
|
||||
}
|
||||
|
||||
public function testOrderByMultipleColumns()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name, u.username FROM CmsUser u ORDER BY u.username DESC, u.name DESC');
|
||||
}
|
||||
|
||||
public function testOrderByWithFunctionExpression()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name FROM CmsUser u ORDER BY COALESCE(u.id, u.name) DESC');
|
||||
}
|
||||
|
||||
public function testSubselectInInExpression()
|
||||
{
|
||||
$this->assertValidDql("SELECT * FROM CmsUser u WHERE u.id NOT IN (SELECT u2.id FROM CmsUser u2 WHERE u2.name = 'zYne')");
|
||||
}
|
||||
/*
|
||||
public function testSubselectInSelectPart()
|
||||
{
|
||||
// Semantical error: Unknown query component u (probably in subselect)
|
||||
$this->assertValidDql("SELECT u.name, (SELECT COUNT(p.phonenumber) FROM CmsPhonenumber p WHERE p.user_id = u.id) pcount FROM CmsUser u WHERE u.name = 'zYne' LIMIT 1");
|
||||
}
|
||||
*/
|
||||
public function testPositionalInputParameter()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM CmsUser u WHERE u.id = ?');
|
||||
}
|
||||
|
||||
public function testNamedInputParameter()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM CmsUser u WHERE u.id = :id');
|
||||
}
|
||||
/*
|
||||
public function testCustomJoinsAndWithKeywordSupported()
|
||||
{
|
||||
// We need existant classes here, otherwise semantical will always fail
|
||||
$this->assertValidDql('SELECT c.*, c2.*, d.* FROM Record_Country c INNER JOIN c.City c2 WITH c2.id = 2 WHERE c.id = 1');
|
||||
}
|
||||
*/
|
||||
public function testJoinConditionsSupported()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.name, p.* FROM CmsUser u LEFT JOIN u.phonenumbers p ON p.phonenumber = '123 123'");
|
||||
}
|
||||
|
||||
public function testIndexByClauseWithOneComponent()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM CmsUser u INDEX BY name');
|
||||
}
|
||||
|
||||
public function testIndexBySupportsJoins()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM CmsUser u LEFT JOIN u.articles INDEX BY topic');
|
||||
}
|
||||
|
||||
public function testIndexBySupportsJoins2()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM CmsUser u INDEX BY name LEFT JOIN u.phonenumbers p INDEX BY phonenumber');
|
||||
}
|
||||
|
||||
public function testBetweenExpressionSupported()
|
||||
{
|
||||
$this->assertValidDql("SELECT * FROM CmsUser u WHERE u.name BETWEEN 'jepso' AND 'zYne'");
|
||||
}
|
||||
|
||||
public function testNotBetweenExpressionSupported()
|
||||
{
|
||||
$this->assertValidDql("SELECT * FROM CmsUser u WHERE u.name NOT BETWEEN 'jepso' AND 'zYne'");
|
||||
}
|
||||
/*
|
||||
public function testAllExpression()
|
||||
{
|
||||
// We need existant classes here, otherwise semantical will always fail
|
||||
$this->assertValidDql('SELECT * FROM Employee e WHERE e.salary > ALL (SELECT m.salary FROM Manager m WHERE m.department = e.department)');
|
||||
}
|
||||
|
||||
public function testAnyExpression()
|
||||
{
|
||||
// We need existant classes here, otherwise semantical will always fail
|
||||
$this->assertValidDql('SELECT * FROM Employee e WHERE e.salary > ANY (SELECT m.salary FROM Manager m WHERE m.department = e.department)');
|
||||
}
|
||||
|
||||
public function testSomeExpression()
|
||||
{
|
||||
// We need existant classes here, otherwise semantical will always fail
|
||||
$this->assertValidDql('SELECT * FROM Employee e WHERE e.salary > SOME (SELECT m.salary FROM Manager m WHERE m.department = e.department)');
|
||||
}
|
||||
*/
|
||||
public function testLikeExpression()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.id FROM CmsUser u WHERE u.name LIKE 'z%'");
|
||||
}
|
||||
|
||||
public function testNotLikeExpression()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.id FROM CmsUser u WHERE u.name NOT LIKE 'z%'");
|
||||
}
|
||||
|
||||
public function testLikeExpressionWithCustomEscapeCharacter()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.id FROM CmsUser u WHERE u.name LIKE 'z|%' ESCAPE '|'");
|
||||
}
|
||||
}
|
280
tests/Orm/Query/ScannerTest.php
Executable file
280
tests/Orm/Query/ScannerTest.php
Executable file
@ -0,0 +1,280 @@
|
||||
<?php
|
||||
class Orm_Query_ScannerTest extends Doctrine_OrmTestCase
|
||||
{
|
||||
public function testScannerRecognizesIdentifierWithLengthOfOneCharacter()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('u');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_IDENTIFIER, $token['type']);
|
||||
$this->assertEquals('u', $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesIdentifierConsistingOfLetters()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('someIdentifier');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_IDENTIFIER, $token['type']);
|
||||
$this->assertEquals('someIdentifier', $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesIdentifierIncludingDigits()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('s0m31d3nt1f13r');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_IDENTIFIER, $token['type']);
|
||||
$this->assertEquals('s0m31d3nt1f13r', $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesIdentifierIncludingUnderscore()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('some_identifier');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_IDENTIFIER, $token['type']);
|
||||
$this->assertEquals('some_identifier', $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesDecimalInteger()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('1234');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_INTEGER, $token['type']);
|
||||
$this->assertEquals(1234, $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesFloat()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('1.234');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_FLOAT, $token['type']);
|
||||
$this->assertEquals(1.234, $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesFloatWithExponent()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('1.2e3');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_FLOAT, $token['type']);
|
||||
$this->assertEquals(1.2e3, $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesFloatWithExponent2()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('0.2e3');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_FLOAT, $token['type']);
|
||||
$this->assertEquals(.2e3, $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesFloatWithNegativeExponent()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('7E-10');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_FLOAT, $token['type']);
|
||||
$this->assertEquals(7E-10, $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesFloatBig()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('1,234,567.89');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_FLOAT, $token['type']);
|
||||
$this->assertEquals(1.23456789e6, $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesFloatBigWrongPoint()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('12,34,56,7.89');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_FLOAT, $token['type']);
|
||||
$this->assertEquals(1.23456789e6, $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesFloatLocaleSpecific()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('1,234');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_FLOAT, $token['type']);
|
||||
$this->assertEquals(1.234, $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesFloatLocaleSpecificBig()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('1.234.567,89');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_FLOAT, $token['type']);
|
||||
$this->assertEquals(1.23456789e6, $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesFloatLocaleSpecificBigWrongPoint()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('12.34.56.7,89');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_FLOAT, $token['type']);
|
||||
$this->assertEquals(1.23456789e6, $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesFloatLocaleSpecificExponent()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('1,234e2');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_FLOAT, $token['type']);
|
||||
$this->assertEquals(1.234e2, $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesFloatLocaleSpecificExponent2()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('0,234e2');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_FLOAT, $token['type']);
|
||||
$this->assertEquals(.234e2, $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesFloatContainingWhitespace()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('- 1.234e2');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_NONE, $token['type']);
|
||||
$this->assertEquals('-', $token['value']);
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_FLOAT, $token['type']);
|
||||
$this->assertNotEquals(-1.234e2, $token['value']);
|
||||
$this->assertEquals(1.234e2, $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesStringContainingWhitespace()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner("'This is a string.'");
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_STRING, $token['type']);
|
||||
$this->assertEquals("'This is a string.'", $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesStringContainingSingleQuotes()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner("'abc''defg'''");
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_STRING, $token['type']);
|
||||
$this->assertEquals("'abc''defg'''", $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesInputParameter()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner('?');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_INPUT_PARAMETER, $token['type']);
|
||||
$this->assertEquals('?', $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerRecognizesNamedInputParameter()
|
||||
{
|
||||
$scanner = new Doctrine_Query_Scanner(':name');
|
||||
|
||||
$token = $scanner->next();
|
||||
$this->assertEquals(Doctrine_Query_Token::T_INPUT_PARAMETER, $token['type']);
|
||||
$this->assertEquals(':name', $token['value']);
|
||||
}
|
||||
|
||||
public function testScannerTokenizesASimpleQueryCorrectly()
|
||||
{
|
||||
$dql = "SELECT u.* FROM User u WHERE u.name = 'Jack O''Neil'";
|
||||
$scanner = new Doctrine_Query_Scanner($dql);
|
||||
|
||||
$tokens = array(
|
||||
array(
|
||||
'value' => 'SELECT',
|
||||
'type' => Doctrine_Query_Token::T_SELECT,
|
||||
'position' => 0
|
||||
),
|
||||
array(
|
||||
'value' => 'u',
|
||||
'type' => Doctrine_Query_Token::T_IDENTIFIER,
|
||||
'position' => 7
|
||||
),
|
||||
array(
|
||||
'value' => '.',
|
||||
'type' => Doctrine_Query_Token::T_NONE,
|
||||
'position' => 8
|
||||
),
|
||||
array(
|
||||
'value' => '*',
|
||||
'type' => Doctrine_Query_Token::T_NONE,
|
||||
'position' => 9
|
||||
),
|
||||
array(
|
||||
'value' => 'FROM',
|
||||
'type' => Doctrine_Query_Token::T_FROM,
|
||||
'position' => 11
|
||||
),
|
||||
array(
|
||||
'value' => 'User',
|
||||
'type' => Doctrine_Query_Token::T_IDENTIFIER,
|
||||
'position' => 16
|
||||
),
|
||||
array(
|
||||
'value' => 'u',
|
||||
'type' => Doctrine_Query_Token::T_IDENTIFIER,
|
||||
'position' => 21
|
||||
),
|
||||
array(
|
||||
'value' => 'WHERE',
|
||||
'type' => Doctrine_Query_Token::T_WHERE,
|
||||
'position' => 23
|
||||
),
|
||||
array(
|
||||
'value' => 'u',
|
||||
'type' => Doctrine_Query_Token::T_IDENTIFIER,
|
||||
'position' => 29
|
||||
),
|
||||
array(
|
||||
'value' => '.',
|
||||
'type' => Doctrine_Query_Token::T_NONE,
|
||||
'position' => 30
|
||||
),
|
||||
array(
|
||||
'value' => 'name',
|
||||
'type' => Doctrine_Query_Token::T_IDENTIFIER,
|
||||
'position' => 31
|
||||
),
|
||||
array(
|
||||
'value' => '=',
|
||||
'type' => Doctrine_Query_Token::T_NONE,
|
||||
'position' => 36
|
||||
),
|
||||
array(
|
||||
'value' => "'Jack O''Neil'",
|
||||
'type' => Doctrine_Query_Token::T_STRING,
|
||||
'position' => 38
|
||||
)
|
||||
);
|
||||
|
||||
foreach ($tokens as $expected) {
|
||||
$actual = $scanner->next();
|
||||
$this->assertEquals($expected['value'], $actual['value']);
|
||||
$this->assertEquals($expected['type'], $actual['type']);
|
||||
$this->assertEquals($expected['position'], $actual['position']);
|
||||
}
|
||||
|
||||
$this->assertNull($scanner->next());
|
||||
}
|
||||
}
|
74
tests/Orm/Query/SelectSqlGenerationTest.php
Executable file
74
tests/Orm/Query/SelectSqlGenerationTest.php
Executable file
@ -0,0 +1,74 @@
|
||||
<?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>.
|
||||
*/
|
||||
require_once 'lib/DoctrineTestInit.php';
|
||||
/**
|
||||
* Test case for testing the saving and referencing of query identifiers.
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @todo 1) [romanb] We might want to split the SQL generation tests into multiple
|
||||
* testcases later since we'll have a lot of them and we might want to have special SQL
|
||||
* generation tests for some dbms specific SQL syntaxes.
|
||||
*/
|
||||
class Orm_Query_SelectSqlGenerationTest extends Doctrine_OrmTestCase
|
||||
{
|
||||
public function testWithoutWhere()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
// NO WhereClause
|
||||
$q->setDql('SELECT u.id FROM CmsUser u');
|
||||
$this->assertEquals('SELECT cu.id AS cu__id FROM cms_user cu WHERE 1 = 1', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
//$q->setDql('SELECT u.* FROM CmsUser u');
|
||||
//$this->assertEquals('DELETE FROM cms_user cu WHERE 1 = 1', $q->getSql());
|
||||
//$q->free();
|
||||
}
|
||||
|
||||
/*
|
||||
public function testWithWhere()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
// "WHERE" ConditionalExpression
|
||||
// ConditionalExpression = ConditionalTerm {"OR" ConditionalTerm}
|
||||
// ConditionalTerm = ConditionalFactor {"AND" ConditionalFactor}
|
||||
// ConditionalFactor = ["NOT"] ConditionalPrimary
|
||||
// ConditionalPrimary = SimpleConditionalExpression | "(" ConditionalExpression ")"
|
||||
// SimpleConditionalExpression
|
||||
// = Expression (ComparisonExpression | BetweenExpression | LikeExpression
|
||||
// | InExpression | NullComparisonExpression) | ExistsExpression
|
||||
|
||||
// If this one test fail, all others will fail too. That's the simplest case possible
|
||||
$q->setDql('SELECT u.* FROM CmsUser u WHERE id = ?');
|
||||
$this->assertEquals('DELETE FROM cms_user cu WHERE cu.id = ?', $q->getSql());
|
||||
$q->free();
|
||||
}
|
||||
*/
|
||||
}
|
113
lib/Doctrine/Query/Set.php → tests/Orm/Query/UpdateSqlGenerationTest.php
Normal file → Executable file
113
lib/Doctrine/Query/Set.php → tests/Orm/Query/UpdateSqlGenerationTest.php
Normal file → Executable file
@ -1,60 +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>.
|
||||
*/
|
||||
Doctrine::autoload('Doctrine_Query_Part');
|
||||
/**
|
||||
* Doctrine_Query
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
*/
|
||||
class Doctrine_Query_Set extends Doctrine_Query_Part
|
||||
{
|
||||
public function parse($dql)
|
||||
{
|
||||
$terms = $this->_tokenizer->sqlExplode($dql, ' ');
|
||||
|
||||
foreach ($terms as $term) {
|
||||
|
||||
preg_match_all("/[a-z0-9_]+\.[a-z0-9_]+[\.[a-z0-9]+]*/i", $term, $m);
|
||||
|
||||
if (isset($m[0])) {
|
||||
foreach ($m[0] as $part) {
|
||||
$e = explode('.', trim($part));
|
||||
$field = array_pop($e);
|
||||
|
||||
$reference = implode('.', $e);
|
||||
|
||||
$alias = $this->query->getTableAlias($reference);
|
||||
$map = $this->query->getAliasDeclaration($reference);
|
||||
|
||||
$dql = str_replace($part, $map['table']->getColumnName($field), $dql);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $dql;
|
||||
}
|
||||
}
|
||||
<?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>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test case for testing the saving and referencing of query identifiers.
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
* @todo 1) [romanb] We might want to split the SQL generation tests into multiple
|
||||
* testcases later since we'll have a lot of them and we might want to have special SQL
|
||||
* generation tests for some dbms specific SQL syntaxes.
|
||||
*/
|
||||
class Orm_Query_UpdateSqlGenerationTest extends Doctrine_OrmTestCase
|
||||
{
|
||||
public function testWithoutWhere()
|
||||
{
|
||||
$q = new Doctrine_Query();
|
||||
|
||||
// NO WhereClause
|
||||
$q->setDql('UPDATE CmsUser u SET name = ?');
|
||||
$this->assertEquals('UPDATE cms_user cu SET cu.name = ? WHERE 1 = 1', $q->getSql());
|
||||
$q->free();
|
||||
|
||||
$q->setDql('UPDATE CmsUser u SET name = ?, username = ?');
|
||||
$this->assertEquals('UPDATE cms_user cu SET cu.name = ?, cu.username = ? WHERE 1 = 1', $q->getSql());
|
||||
$q->free();
|
||||
}
|
||||
}
|
@ -5,5 +5,7 @@
|
||||
*/
|
||||
class Doctrine_OrmTestCase extends Doctrine_TestCase
|
||||
{
|
||||
|
||||
}
|
||||
protected function setUp() {
|
||||
$em = new Doctrine_EntityManager(new Doctrine_Connection_Mock());
|
||||
}
|
||||
}
|
||||
|
0
tests/models/cms/CmsArticle.php
Normal file → Executable file
0
tests/models/cms/CmsArticle.php
Normal file → Executable file
0
tests/models/cms/CmsComment.php
Normal file → Executable file
0
tests/models/cms/CmsComment.php
Normal file → Executable file
0
tests/models/cms/CmsPhonenumber.php
Normal file → Executable file
0
tests/models/cms/CmsPhonenumber.php
Normal file → Executable file
0
tests/models/forum/ForumBoard.php
Normal file → Executable file
0
tests/models/forum/ForumBoard.php
Normal file → Executable file
0
tests/models/forum/ForumCategory.php
Normal file → Executable file
0
tests/models/forum/ForumCategory.php
Normal file → Executable file
Loading…
x
Reference in New Issue
Block a user