From bdd2241fb5ca132d79e87e8a0460929746609510 Mon Sep 17 00:00:00 2001 From: piccoloprincipe Date: Tue, 2 Jun 2009 18:05:26 +0000 Subject: [PATCH] set svn:eol-style property on plain text files --- lib/Doctrine/Common/EventArgs.php | 98 +- lib/Doctrine/Common/EventSubscriber.php | 78 +- lib/Doctrine/DBAL/Driver/Statement.php | 584 +-- lib/Doctrine/DBAL/Statement.php | 874 ++-- lib/Doctrine/ORM/Cache/ApcCache.php | 152 +- lib/Doctrine/ORM/Cache/ArrayCache.php | 182 +- lib/Doctrine/ORM/Cache/Cache.php | 140 +- lib/Doctrine/ORM/Cache/DbCache.php | 360 +- lib/Doctrine/ORM/Cache/MemcacheCache.php | 200 +- .../ORM/Query/AST/DeleteStatement.php | 122 +- lib/Doctrine/ORM/Query/AST/FromClause.php | 102 +- .../AST/IdentificationVariableDeclaration.php | 138 +- lib/Doctrine/ORM/Query/AST/IndexBy.php | 102 +- lib/Doctrine/ORM/Query/AST/Join.php | 192 +- .../ORM/Query/AST/JoinVariableDeclaration.php | 116 +- lib/Doctrine/ORM/Query/AST/Node.php | 74 +- .../Query/AST/RangeVariableDeclaration.php | 130 +- lib/Doctrine/ORM/Query/AST/SelectClause.php | 152 +- .../ORM/Query/AST/SelectExpression.php | 118 +- .../ORM/Query/AST/SelectStatement.php | 172 +- .../ORM/Query/AST/SimpleSelectClause.php | 124 +- .../ORM/Query/AST/SimpleSelectExpression.php | 124 +- .../AST/SimpleStateFieldPathExpression.php | 116 +- lib/Doctrine/ORM/Query/AST/Subselect.php | 204 +- .../ORM/Query/AST/SubselectFromClause.php | 102 +- .../ORM/Query/AST/UpdateStatement.php | 122 +- lib/Doctrine/ORM/Query/CacheHandler.php | 290 +- lib/Doctrine/ORM/Query/Parser.php | 3780 ++++++++--------- lib/vendor/addendum/annotations.php | 682 +-- .../annotations/annotation_parser.php | 670 +-- .../addendum/annotations/doc_comment.php | 258 +- .../annotations/tests/acceptance_test.php | 466 +- .../addendum/annotations/tests/all_tests.php | 66 +- .../tests/annotation_parser_test.php | 622 +-- .../annotations/tests/annotation_test.php | 54 +- .../tests/constrained_annotation_test.php | 144 +- .../annotations/tests/doc_comment_test.php | 174 +- .../ORM/Query/IdentifierRecognitionTest.php | 260 +- 38 files changed, 6172 insertions(+), 6172 deletions(-) diff --git a/lib/Doctrine/Common/EventArgs.php b/lib/Doctrine/Common/EventArgs.php index b5b4ba841..0f0fe9b49 100644 --- a/lib/Doctrine/Common/EventArgs.php +++ b/lib/Doctrine/Common/EventArgs.php @@ -1,49 +1,49 @@ -. - */ - -namespace Doctrine\Common; - -/** - * EventArgs is the base class for classes containing event data. - * - * This class contains no event data. It is used by events that do not pass state - * information to an event handler when an event is raised. The single empty EventArgs - * instance can be obtained through {@link getEmptyInstance()}. - * - * @author Konsta Vesterinen - * @author Roman Borschel - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -class EventArgs -{ - private static $_emptyEventArgsInstance; - - public static function getEmptyInstance() - { - if ( ! self::$_emptyEventArgsInstance) { - self::$_emptyEventArgsInstance = new EventArgs; - } - return self::$_emptyEventArgsInstance; - } -} +. + */ + +namespace Doctrine\Common; + +/** + * EventArgs is the base class for classes containing event data. + * + * This class contains no event data. It is used by events that do not pass state + * information to an event handler when an event is raised. The single empty EventArgs + * instance can be obtained through {@link getEmptyInstance()}. + * + * @author Konsta Vesterinen + * @author Roman Borschel + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +class EventArgs +{ + private static $_emptyEventArgsInstance; + + public static function getEmptyInstance() + { + if ( ! self::$_emptyEventArgsInstance) { + self::$_emptyEventArgsInstance = new EventArgs; + } + return self::$_emptyEventArgsInstance; + } +} diff --git a/lib/Doctrine/Common/EventSubscriber.php b/lib/Doctrine/Common/EventSubscriber.php index a117950f1..5bbfdfbc4 100644 --- a/lib/Doctrine/Common/EventSubscriber.php +++ b/lib/Doctrine/Common/EventSubscriber.php @@ -1,39 +1,39 @@ -. - */ - -namespace Doctrine\Common; - -/** - * An EventSubscriber knows himself what events he is interested in. - * If an EventSubscriber is added to an EventManager, the manager invokes - * getSubscribedEvents() and registers the subscriber as a listener for all - * returned events. - * - * @author Roman Borschel - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.phpdoctrine.org - * @since 2.0 - * @version $Revision: 4653 $ - */ -interface EventSubscriber -{ - public function getSubscribedEvents(); -} +. + */ + +namespace Doctrine\Common; + +/** + * An EventSubscriber knows himself what events he is interested in. + * If an EventSubscriber is added to an EventManager, the manager invokes + * getSubscribedEvents() and registers the subscriber as a listener for all + * returned events. + * + * @author Roman Borschel + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.org + * @since 2.0 + * @version $Revision: 4653 $ + */ +interface EventSubscriber +{ + public function getSubscribedEvents(); +} diff --git a/lib/Doctrine/DBAL/Driver/Statement.php b/lib/Doctrine/DBAL/Driver/Statement.php index b3f933557..9d0d79e17 100644 --- a/lib/Doctrine/DBAL/Driver/Statement.php +++ b/lib/Doctrine/DBAL/Driver/Statement.php @@ -1,293 +1,293 @@ -. - */ - -namespace Doctrine\DBAL\Driver; - -/** - * Statement interface. - * Drivers must implement this interface. - * - * This resembles the PDOStatement interface. - * - * @author Konsta Vesterinen - * @author Roman Borschel - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -interface Statement -{ - /** - * Bind a column to a PHP variable - * - * @param mixed $column Number of the column (1-indexed) or name of the column in the result set. - * If using the column name, be aware that the name should match - * the case of the column, as returned by the driver. - * @param string $param Name of the PHP variable to which the column will be bound. - * @param integer $type Data type of the parameter, specified by the PDO::PARAM_* constants. - * @return boolean Returns TRUE on success or FALSE on failure - */ - public function bindColumn($column, &$param, $type = null); - - /** - * Binds a value to a corresponding named or positional - * placeholder in the SQL statement that was used to prepare the statement. - * - * @param mixed $param Parameter identifier. For a prepared statement using named placeholders, - * this will be a parameter name of the form :name. For a prepared statement - * using question mark placeholders, this will be the 1-indexed position of the parameter - * - * @param mixed $value The value to bind to the parameter. - * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. - * - * @return boolean Returns TRUE on success or FALSE on failure. - */ - public function bindValue($param, $value, $type = null); - - /** - * Binds a PHP variable to a corresponding named or question mark placeholder in the - * SQL statement that was use to prepare the statement. Unlike PDOStatement->bindValue(), - * the variable is bound as a reference and will only be evaluated at the time - * that PDOStatement->execute() is called. - * - * Most parameters are input parameters, that is, parameters that are - * used in a read-only fashion to build up the query. Some drivers support the invocation - * of stored procedures that return data as output parameters, and some also as input/output - * parameters that both send in data and are updated to receive it. - * - * @param mixed $param Parameter identifier. For a prepared statement using named placeholders, - * this will be a parameter name of the form :name. For a prepared statement - * using question mark placeholders, this will be the 1-indexed position of the parameter - * - * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter. - * - * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. To return - * an INOUT parameter from a stored procedure, use the bitwise OR operator to set the - * PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter. - * - * @param integer $length Length of the data type. To indicate that a parameter is an OUT parameter - * from a stored procedure, you must explicitly set the length. - * @param mixed $driverOptions - * @return boolean Returns TRUE on success or FALSE on failure. - */ - public function bindParam($column, &$variable, $type = null, $length = null, $driverOptions = array()); - - /** - * closeCursor - * Closes the cursor, enabling the statement to be executed again. - * - * @return boolean Returns TRUE on success or FALSE on failure. - */ - public function closeCursor(); - - /** - * columnCount - * Returns the number of columns in the result set - * - * @return integer Returns the number of columns in the result set represented - * by the PDOStatement object. If there is no result set, - * this method should return 0. - */ - public function columnCount(); - - /** - * errorCode - * Fetch the SQLSTATE associated with the last operation on the statement handle - * - * @see Doctrine_Adapter_Interface::errorCode() - * @return string error code string - */ - public function errorCode(); - - /** - * errorInfo - * Fetch extended error information associated with the last operation on the statement handle - * - * @see Doctrine_Adapter_Interface::errorInfo() - * @return array error info array - */ - public function errorInfo(); - - /** - * Executes a prepared statement - * - * If the prepared statement included parameter markers, you must either: - * call PDOStatement->bindParam() to bind PHP variables to the parameter markers: - * bound variables pass their value as input and receive the output value, - * if any, of their associated parameter markers or pass an array of input-only - * parameter values - * - * - * @param array $params An array of values with as many elements as there are - * bound parameters in the SQL statement being executed. - * @return boolean Returns TRUE on success or FALSE on failure. - */ - public function execute($params = null); - - /** - * fetch - * - * @see Query::HYDRATE_* constants - * @param integer $fetchStyle Controls how the next row will be returned to the caller. - * This value must be one of the Query::HYDRATE_* constants, - * defaulting to Query::HYDRATE_BOTH - * - * @param integer $cursorOrientation For a PDOStatement object representing a scrollable cursor, - * this value determines which row will be returned to the caller. - * This value must be one of the Query::HYDRATE_ORI_* constants, defaulting to - * Query::HYDRATE_ORI_NEXT. To request a scrollable cursor for your - * PDOStatement object, - * you must set the PDO::ATTR_CURSOR attribute to Doctrine::CURSOR_SCROLL when you - * prepare the SQL statement with Doctrine_Adapter_Interface->prepare(). - * - * @param integer $cursorOffset For a PDOStatement object representing a scrollable cursor for which the - * $cursorOrientation parameter is set to Query::HYDRATE_ORI_ABS, this value specifies - * the absolute number of the row in the result set that shall be fetched. - * - * For a PDOStatement object representing a scrollable cursor for - * which the $cursorOrientation parameter is set to Query::HYDRATE_ORI_REL, this value - * specifies the row to fetch relative to the cursor position before - * PDOStatement->fetch() was called. - * - * @return mixed - */ - public function fetch($fetchStyle = Query::HYDRATE_BOTH, - $cursorOrientation = Query::HYDRATE_ORI_NEXT, - $cursorOffset = null); - - /** - * fetchAll - * Returns an array containing all of the result set rows - * - * @param integer $fetchStyle Controls how the next row will be returned to the caller. - * This value must be one of the Query::HYDRATE_* constants, - * defaulting to Query::HYDRATE_BOTH - * - * @param integer $columnIndex Returns the indicated 0-indexed column when the value of $fetchStyle is - * Query::HYDRATE_COLUMN. Defaults to 0. - * - * @return array - */ - public function fetchAll($fetchStyle = Query::HYDRATE_BOTH); - - /** - * fetchColumn - * Returns a single column from the next row of a - * result set or FALSE if there are no more rows. - * - * @param integer $columnIndex 0-indexed number of the column you wish to retrieve from the row. If no - * value is supplied, PDOStatement->fetchColumn() - * fetches the first column. - * - * @return string returns a single column in the next row of a result set. - */ - public function fetchColumn($columnIndex = 0); - - /** - * fetchObject - * Fetches the next row and returns it as an object. - * - * Fetches the next row and returns it as an object. This function is an alternative to - * PDOStatement->fetch() with Query::HYDRATE_CLASS or Query::HYDRATE_OBJ style. - * - * @param string $className Name of the created class, defaults to stdClass. - * @param array $args Elements of this array are passed to the constructor. - * - * @return mixed an instance of the required class with property names that correspond - * to the column names or FALSE in case of an error. - */ - public function fetchObject($className = 'stdClass', $args = array()); - - /** - * getAttribute - * Retrieve a statement attribute - * - * @param integer $attribute - * @see Doctrine::ATTR_* constants - * @return mixed the attribute value - */ - public function getAttribute($attribute); - - /** - * getColumnMeta - * Returns metadata for a column in a result set - * - * @param integer $column The 0-indexed column in the result set. - * - * @return array Associative meta data array with the following structure: - * - * native_type The PHP native type used to represent the column value. - * driver:decl_ type The SQL type used to represent the column value in the database. If the column in the result set is the result of a function, this value is not returned by PDOStatement->getColumnMeta(). - * flags Any flags set for this column. - * name The name of this column as returned by the database. - * len The length of this column. Normally -1 for types other than floating point decimals. - * precision The numeric precision of this column. Normally 0 for types other than floating point decimals. - * pdo_type The type of this column as represented by the PDO::PARAM_* constants. - */ - public function getColumnMeta($column); - - /** - * nextRowset - * Advances to the next rowset in a multi-rowset statement handle - * - * Some database servers support stored procedures that return more than one rowset - * (also known as a result set). The nextRowset() method enables you to access the second - * and subsequent rowsets associated with a PDOStatement object. Each rowset can have a - * different set of columns from the preceding rowset. - * - * @return boolean Returns TRUE on success or FALSE on failure. - */ - public function nextRowset(); - - /** - * rowCount - * rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement - * executed by the corresponding object. - * - * If the last SQL statement executed by the associated Statement object was a SELECT statement, - * some databases may return the number of rows returned by that statement. However, - * this behaviour is not guaranteed for all databases and should not be - * relied on for portable applications. - * - * @return integer Returns the number of rows. - */ - public function rowCount(); - - /** - * setAttribute - * Set a statement attribute - * - * @param integer $attribute - * @param mixed $value the value of given attribute - * @return boolean Returns TRUE on success or FALSE on failure. - */ - public function setAttribute($attribute, $value); - - /** - * setFetchMode - * Set the default fetch mode for this statement - * - * @param integer $mode The fetch mode must be one of the Query::HYDRATE_* constants. - * @return boolean Returns 1 on success or FALSE on failure. - */ - public function setFetchMode($mode, $arg1); +. + */ + +namespace Doctrine\DBAL\Driver; + +/** + * Statement interface. + * Drivers must implement this interface. + * + * This resembles the PDOStatement interface. + * + * @author Konsta Vesterinen + * @author Roman Borschel + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +interface Statement +{ + /** + * Bind a column to a PHP variable + * + * @param mixed $column Number of the column (1-indexed) or name of the column in the result set. + * If using the column name, be aware that the name should match + * the case of the column, as returned by the driver. + * @param string $param Name of the PHP variable to which the column will be bound. + * @param integer $type Data type of the parameter, specified by the PDO::PARAM_* constants. + * @return boolean Returns TRUE on success or FALSE on failure + */ + public function bindColumn($column, &$param, $type = null); + + /** + * Binds a value to a corresponding named or positional + * placeholder in the SQL statement that was used to prepare the statement. + * + * @param mixed $param Parameter identifier. For a prepared statement using named placeholders, + * this will be a parameter name of the form :name. For a prepared statement + * using question mark placeholders, this will be the 1-indexed position of the parameter + * + * @param mixed $value The value to bind to the parameter. + * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. + * + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function bindValue($param, $value, $type = null); + + /** + * Binds a PHP variable to a corresponding named or question mark placeholder in the + * SQL statement that was use to prepare the statement. Unlike PDOStatement->bindValue(), + * the variable is bound as a reference and will only be evaluated at the time + * that PDOStatement->execute() is called. + * + * Most parameters are input parameters, that is, parameters that are + * used in a read-only fashion to build up the query. Some drivers support the invocation + * of stored procedures that return data as output parameters, and some also as input/output + * parameters that both send in data and are updated to receive it. + * + * @param mixed $param Parameter identifier. For a prepared statement using named placeholders, + * this will be a parameter name of the form :name. For a prepared statement + * using question mark placeholders, this will be the 1-indexed position of the parameter + * + * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter. + * + * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. To return + * an INOUT parameter from a stored procedure, use the bitwise OR operator to set the + * PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter. + * + * @param integer $length Length of the data type. To indicate that a parameter is an OUT parameter + * from a stored procedure, you must explicitly set the length. + * @param mixed $driverOptions + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function bindParam($column, &$variable, $type = null, $length = null, $driverOptions = array()); + + /** + * closeCursor + * Closes the cursor, enabling the statement to be executed again. + * + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function closeCursor(); + + /** + * columnCount + * Returns the number of columns in the result set + * + * @return integer Returns the number of columns in the result set represented + * by the PDOStatement object. If there is no result set, + * this method should return 0. + */ + public function columnCount(); + + /** + * errorCode + * Fetch the SQLSTATE associated with the last operation on the statement handle + * + * @see Doctrine_Adapter_Interface::errorCode() + * @return string error code string + */ + public function errorCode(); + + /** + * errorInfo + * Fetch extended error information associated with the last operation on the statement handle + * + * @see Doctrine_Adapter_Interface::errorInfo() + * @return array error info array + */ + public function errorInfo(); + + /** + * Executes a prepared statement + * + * If the prepared statement included parameter markers, you must either: + * call PDOStatement->bindParam() to bind PHP variables to the parameter markers: + * bound variables pass their value as input and receive the output value, + * if any, of their associated parameter markers or pass an array of input-only + * parameter values + * + * + * @param array $params An array of values with as many elements as there are + * bound parameters in the SQL statement being executed. + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function execute($params = null); + + /** + * fetch + * + * @see Query::HYDRATE_* constants + * @param integer $fetchStyle Controls how the next row will be returned to the caller. + * This value must be one of the Query::HYDRATE_* constants, + * defaulting to Query::HYDRATE_BOTH + * + * @param integer $cursorOrientation For a PDOStatement object representing a scrollable cursor, + * this value determines which row will be returned to the caller. + * This value must be one of the Query::HYDRATE_ORI_* constants, defaulting to + * Query::HYDRATE_ORI_NEXT. To request a scrollable cursor for your + * PDOStatement object, + * you must set the PDO::ATTR_CURSOR attribute to Doctrine::CURSOR_SCROLL when you + * prepare the SQL statement with Doctrine_Adapter_Interface->prepare(). + * + * @param integer $cursorOffset For a PDOStatement object representing a scrollable cursor for which the + * $cursorOrientation parameter is set to Query::HYDRATE_ORI_ABS, this value specifies + * the absolute number of the row in the result set that shall be fetched. + * + * For a PDOStatement object representing a scrollable cursor for + * which the $cursorOrientation parameter is set to Query::HYDRATE_ORI_REL, this value + * specifies the row to fetch relative to the cursor position before + * PDOStatement->fetch() was called. + * + * @return mixed + */ + public function fetch($fetchStyle = Query::HYDRATE_BOTH, + $cursorOrientation = Query::HYDRATE_ORI_NEXT, + $cursorOffset = null); + + /** + * fetchAll + * Returns an array containing all of the result set rows + * + * @param integer $fetchStyle Controls how the next row will be returned to the caller. + * This value must be one of the Query::HYDRATE_* constants, + * defaulting to Query::HYDRATE_BOTH + * + * @param integer $columnIndex Returns the indicated 0-indexed column when the value of $fetchStyle is + * Query::HYDRATE_COLUMN. Defaults to 0. + * + * @return array + */ + public function fetchAll($fetchStyle = Query::HYDRATE_BOTH); + + /** + * fetchColumn + * Returns a single column from the next row of a + * result set or FALSE if there are no more rows. + * + * @param integer $columnIndex 0-indexed number of the column you wish to retrieve from the row. If no + * value is supplied, PDOStatement->fetchColumn() + * fetches the first column. + * + * @return string returns a single column in the next row of a result set. + */ + public function fetchColumn($columnIndex = 0); + + /** + * fetchObject + * Fetches the next row and returns it as an object. + * + * Fetches the next row and returns it as an object. This function is an alternative to + * PDOStatement->fetch() with Query::HYDRATE_CLASS or Query::HYDRATE_OBJ style. + * + * @param string $className Name of the created class, defaults to stdClass. + * @param array $args Elements of this array are passed to the constructor. + * + * @return mixed an instance of the required class with property names that correspond + * to the column names or FALSE in case of an error. + */ + public function fetchObject($className = 'stdClass', $args = array()); + + /** + * getAttribute + * Retrieve a statement attribute + * + * @param integer $attribute + * @see Doctrine::ATTR_* constants + * @return mixed the attribute value + */ + public function getAttribute($attribute); + + /** + * getColumnMeta + * Returns metadata for a column in a result set + * + * @param integer $column The 0-indexed column in the result set. + * + * @return array Associative meta data array with the following structure: + * + * native_type The PHP native type used to represent the column value. + * driver:decl_ type The SQL type used to represent the column value in the database. If the column in the result set is the result of a function, this value is not returned by PDOStatement->getColumnMeta(). + * flags Any flags set for this column. + * name The name of this column as returned by the database. + * len The length of this column. Normally -1 for types other than floating point decimals. + * precision The numeric precision of this column. Normally 0 for types other than floating point decimals. + * pdo_type The type of this column as represented by the PDO::PARAM_* constants. + */ + public function getColumnMeta($column); + + /** + * nextRowset + * Advances to the next rowset in a multi-rowset statement handle + * + * Some database servers support stored procedures that return more than one rowset + * (also known as a result set). The nextRowset() method enables you to access the second + * and subsequent rowsets associated with a PDOStatement object. Each rowset can have a + * different set of columns from the preceding rowset. + * + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function nextRowset(); + + /** + * rowCount + * rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement + * executed by the corresponding object. + * + * If the last SQL statement executed by the associated Statement object was a SELECT statement, + * some databases may return the number of rows returned by that statement. However, + * this behaviour is not guaranteed for all databases and should not be + * relied on for portable applications. + * + * @return integer Returns the number of rows. + */ + public function rowCount(); + + /** + * setAttribute + * Set a statement attribute + * + * @param integer $attribute + * @param mixed $value the value of given attribute + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function setAttribute($attribute, $value); + + /** + * setFetchMode + * Set the default fetch mode for this statement + * + * @param integer $mode The fetch mode must be one of the Query::HYDRATE_* constants. + * @return boolean Returns 1 on success or FALSE on failure. + */ + public function setFetchMode($mode, $arg1); } \ No newline at end of file diff --git a/lib/Doctrine/DBAL/Statement.php b/lib/Doctrine/DBAL/Statement.php index fb481aa6b..a6686f7ac 100644 --- a/lib/Doctrine/DBAL/Statement.php +++ b/lib/Doctrine/DBAL/Statement.php @@ -1,438 +1,438 @@ -. - */ - -namespace Doctrine\DBAL; - -/** - * A thin wrapper around PDOStatement. - * - * @author Konsta Vesterinen - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.phpdoctrine.org - * @since 1.0 - * @version $Revision: 1532 $ - * @todo Do we seriously need this wrapper? - */ -class Statement -{ - /** - * @var Doctrine_Connection $conn Doctrine_Connection object, every connection - * statement holds an instance of Doctrine_Connection - */ - protected $_conn; - - /** - * @var Doctrine::DBAL::Driver::Statement - */ - protected $_stmt; - - /** - * constructor - * - * @param Doctrine_Connection $conn Doctrine_Connection object, every connection - * statement holds an instance of Doctrine_Connection - * @param mixed $stmt - */ - public function __construct(Connection $conn, $stmt) - { - $this->_conn = $conn; - $this->_stmt = $stmt; - - if ($stmt === false) { - throw \Doctrine\Common\DoctrineException::updateMe('Unknown statement object given.'); - } - } - - /** - * getConnection - * returns the connection object this statement uses - * - * @return Doctrine_Connection - */ - public function getConnection() - { - return $this->_conn; - } - public function getStatement() - { - return $this->_stmt; - } - public function getQuery() - { - return $this->_stmt->queryString; - } - - /** - * Bind a column to a PHP variable - * - * @param mixed $column Number of the column (1-indexed) or name of the column in the result set. - * If using the column name, be aware that the name should match - * the case of the column, as returned by the driver. - * - * @param string $param Name of the PHP variable to which the column will be bound. - * @param integer $type Data type of the parameter, specified by the PDO::PARAM_* constants. - * @return boolean Returns TRUE on success or FALSE on failure - */ - public function bindColumn($column, $param, $type = null) - { - if ($type === null) { - return $this->_stmt->bindColumn($column, $param); - } else { - return $this->_stmt->bindColumn($column, $param, $type); - } - } - - /** - * bindValue - * Binds a value to a corresponding named or question mark - * placeholder in the SQL statement that was use to prepare the statement. - * - * @param mixed $param Parameter identifier. For a prepared statement using named placeholders, - * this will be a parameter name of the form :name. For a prepared statement - * using question mark placeholders, this will be the 1-indexed position of the parameter - * - * @param mixed $value The value to bind to the parameter. - * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. - * - * @return boolean Returns TRUE on success or FALSE on failure. - */ - public function bindValue($param, $value, $type = null) - { - if ($type === null) { - return $this->_stmt->bindValue($param, $value); - } else { - return $this->_stmt->bindValue($param, $value, $type); - } - } - - /** - * Binds a PHP variable to a corresponding named or question mark placeholder in the - * SQL statement that was use to prepare the statement. Unlike PDOStatement->bindValue(), - * the variable is bound as a reference and will only be evaluated at the time - * that PDOStatement->execute() is called. - * - * Most parameters are input parameters, that is, parameters that are - * used in a read-only fashion to build up the query. Some drivers support the invocation - * of stored procedures that return data as output parameters, and some also as input/output - * parameters that both send in data and are updated to receive it. - * - * @param mixed $param Parameter identifier. For a prepared statement using named placeholders, - * this will be a parameter name of the form :name. For a prepared statement - * using question mark placeholders, this will be the 1-indexed position of the parameter - * - * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter. - * - * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. To return - * an INOUT parameter from a stored procedure, use the bitwise OR operator to set the - * PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter. - * - * @param integer $length Length of the data type. To indicate that a parameter is an OUT parameter - * from a stored procedure, you must explicitly set the length. - * @param mixed $driverOptions - * @return boolean Returns TRUE on success or FALSE on failure. - */ - public function bindParam($column, &$variable, $type = null, $length = null, $driverOptions = array()) - { - if ($type === null) { - return $this->_stmt->bindParam($column, $variable); - } else { - return $this->_stmt->bindParam($column, $variable, $type, $length, $driverOptions); - } - } - - /** - * Closes the cursor, enabling the statement to be executed again. - * - * @return boolean Returns TRUE on success or FALSE on failure. - */ - public function closeCursor() - { - return $this->_stmt->closeCursor(); - } - - /** - * Returns the number of columns in the result set - * - * @return integer Returns the number of columns in the result set represented - * by the PDOStatement object. If there is no result set, - * this method should return 0. - */ - public function columnCount() - { - return $this->_stmt->columnCount(); - } - - /** - * Fetch the SQLSTATE associated with the last operation on the statement handle - * - * @see Doctrine_Adapter_Interface::errorCode() - * @return string error code string - */ - public function errorCode() - { - return $this->_stmt->errorCode(); - } - - /** - * Fetch extended error information associated with the last operation on the statement handle - * - * @see Doctrine_Adapter_Interface::errorInfo() - * @return array error info array - */ - public function errorInfo() - { - return $this->_stmt->errorInfo(); - } - - /** - * Executes a prepared statement - * - * If the prepared statement included parameter markers, you must either: - * call PDOStatement->bindParam() to bind PHP variables to the parameter markers: - * bound variables pass their value as input and receive the output value, - * if any, of their associated parameter markers or pass an array of input-only - * parameter values - * - * - * @param array $params An array of values with as many elements as there are - * bound parameters in the SQL statement being executed. - * @return boolean Returns TRUE on success or FALSE on failure. - */ - public function execute($params = null) - { - try { - //$event = new Doctrine_Event($this, Doctrine_Event::STMT_EXECUTE, $this->getQuery(), $params); - //$this->_conn->getListener()->preStmtExecute($event); - - $result = true; - //if ( ! $event->skipOperation) { - $result = $this->_stmt->execute($params); - //$this->_conn->incrementQueryCount(); - //} - - //$this->_conn->getListener()->postStmtExecute($event); - - return $result; - } catch (PDOException $e) { - $this->_conn->rethrowException($e, $this); - } - - return false; - } - - /** - * fetch - * - * @see Query::HYDRATE_* constants - * @param integer $fetchStyle Controls how the next row will be returned to the caller. - * This value must be one of the Query::HYDRATE_* constants, - * defaulting to Query::HYDRATE_BOTH - * - * @param integer $cursorOrientation For a PDOStatement object representing a scrollable cursor, - * this value determines which row will be returned to the caller. - * This value must be one of the Query::HYDRATE_ORI_* constants, defaulting to - * Query::HYDRATE_ORI_NEXT. To request a scrollable cursor for your - * PDOStatement object, - * you must set the PDO::ATTR_CURSOR attribute to Doctrine::CURSOR_SCROLL when you - * prepare the SQL statement with Doctrine_Adapter_Interface->prepare(). - * - * @param integer $cursorOffset For a PDOStatement object representing a scrollable cursor for which the - * $cursorOrientation parameter is set to Query::HYDRATE_ORI_ABS, this value specifies - * the absolute number of the row in the result set that shall be fetched. - * - * For a PDOStatement object representing a scrollable cursor for - * which the $cursorOrientation parameter is set to Query::HYDRATE_ORI_REL, this value - * specifies the row to fetch relative to the cursor position before - * PDOStatement->fetch() was called. - * - * @return mixed - */ - public function fetch($fetchMode = Query::HYDRATE_BOTH, - $cursorOrientation = Query::HYDRATE_ORI_NEXT, - $cursorOffset = null) - { - //$event = new Doctrine_Event($this, Doctrine_Event::STMT_FETCH, $this->getQuery()); - //$event->fetchMode = $fetchMode; - //$event->cursorOrientation = $cursorOrientation; - //$event->cursorOffset = $cursorOffset; - - //$data = $this->_conn->getListener()->preFetch($event); - - //if ( ! $event->skipOperation) { - $data = $this->_stmt->fetch($fetchMode, $cursorOrientation, $cursorOffset); - //} - - //$this->_conn->getListener()->postFetch($event); - - return $data; - } - - /** - * Returns an array containing all of the result set rows - * - * @param integer $fetchMode Controls how the next row will be returned to the caller. - * This value must be one of the Query::HYDRATE_* constants, - * defaulting to Query::HYDRATE_BOTH - * - * @param integer $columnIndex Returns the indicated 0-indexed column when the value of $fetchStyle is - * Query::HYDRATE_COLUMN. Defaults to 0. - * - * @return array - */ - public function fetchAll($fetchMode = Query::HYDRATE_BOTH, $columnIndex = null) - { - //$event = new Doctrine_Event($this, Doctrine_Event::STMT_FETCHALL, $this->getQuery()); - //$event->fetchMode = $fetchMode; - //$event->columnIndex = $columnIndex; - //$this->_conn->getListener()->preFetchAll($event); - - //if ( ! $event->skipOperation) { - if ($columnIndex !== null) { - $data = $this->_stmt->fetchAll($fetchMode, $columnIndex); - } else { - $data = $this->_stmt->fetchAll($fetchMode); - } - //$event->data = $data; - //} - - //$this->_conn->getListener()->postFetchAll($event); - - return $data; - } - - /** - * Returns a single column from the next row of a - * result set or FALSE if there are no more rows. - * - * @param integer $columnIndex 0-indexed number of the column you wish to retrieve from the row. If no - * value is supplied, PDOStatement->fetchColumn() - * fetches the first column. - * - * @return string returns a single column in the next row of a result set. - */ - public function fetchColumn($columnIndex = 0) - { - return $this->_stmt->fetchColumn($columnIndex); - } - - /** - * Fetches the next row and returns it as an object. - * - * Fetches the next row and returns it as an object. This function is an alternative to - * PDOStatement->fetch() with Query::HYDRATE_CLASS or Query::HYDRATE_OBJ style. - * - * @param string $className Name of the created class, defaults to stdClass. - * @param array $args Elements of this array are passed to the constructor. - * - * @return mixed an instance of the required class with property names that correspond - * to the column names or FALSE in case of an error. - */ - public function fetchObject($className = 'stdClass', $args = array()) - { - return $this->_stmt->fetchObject($className, $args); - } - - /** - * Retrieve a statement attribute - * - * @param integer $attribute - * @see Doctrine::ATTR_* constants - * @return mixed the attribute value - */ - public function getAttribute($attribute) - { - return $this->_stmt->getAttribute($attribute); - } - - /** - * Returns metadata for a column in a result set - * - * @param integer $column The 0-indexed column in the result set. - * - * @return array Associative meta data array with the following structure: - * - * native_type The PHP native type used to represent the column value. - * driver:decl_ type The SQL type used to represent the column value in the database. If the column in the result set is the result of a function, this value is not returned by PDOStatement->getColumnMeta(). - * flags Any flags set for this column. - * name The name of this column as returned by the database. - * len The length of this column. Normally -1 for types other than floating point decimals. - * precision The numeric precision of this column. Normally 0 for types other than floating point decimals. - * pdo_type The type of this column as represented by the PDO::PARAM_* constants. - */ - public function getColumnMeta($column) - { - return $this->_stmt->getColumnMeta($column); - } - - /** - * Advances to the next rowset in a multi-rowset statement handle - * - * Some database servers support stored procedures that return more than one rowset - * (also known as a result set). The nextRowset() method enables you to access the second - * and subsequent rowsets associated with a PDOStatement object. Each rowset can have a - * different set of columns from the preceding rowset. - * - * @return boolean Returns TRUE on success or FALSE on failure. - */ - public function nextRowset() - { - return $this->_stmt->nextRowset(); - } - - /** - * rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement - * executed by the corresponding object. - * - * If the last SQL statement executed by the associated Statement object was a SELECT statement, - * some databases may return the number of rows returned by that statement. However, - * this behaviour is not guaranteed for all databases and should not be - * relied on for portable applications. - * - * @return integer Returns the number of rows. - */ - public function rowCount() - { - return $this->_stmt->rowCount(); - } - - /** - * Set a statement attribute - * - * @param integer $attribute - * @param mixed $value the value of given attribute - * @return boolean Returns TRUE on success or FALSE on failure. - */ - public function setAttribute($attribute, $value) - { - return $this->_stmt->setAttribute($attribute, $value); - } - - /** - * Set the default fetch mode for this statement - * - * @param integer $mode The fetch mode must be one of the Query::HYDRATE_* constants. - * @return boolean Returns 1 on success or FALSE on failure. - */ - public function setFetchMode($mode, $arg1 = null, $arg2 = null) - { - return $this->_stmt->setFetchMode($mode, $arg1, $arg2); - } +. + */ + +namespace Doctrine\DBAL; + +/** + * A thin wrapper around PDOStatement. + * + * @author Konsta Vesterinen + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.org + * @since 1.0 + * @version $Revision: 1532 $ + * @todo Do we seriously need this wrapper? + */ +class Statement +{ + /** + * @var Doctrine_Connection $conn Doctrine_Connection object, every connection + * statement holds an instance of Doctrine_Connection + */ + protected $_conn; + + /** + * @var Doctrine::DBAL::Driver::Statement + */ + protected $_stmt; + + /** + * constructor + * + * @param Doctrine_Connection $conn Doctrine_Connection object, every connection + * statement holds an instance of Doctrine_Connection + * @param mixed $stmt + */ + public function __construct(Connection $conn, $stmt) + { + $this->_conn = $conn; + $this->_stmt = $stmt; + + if ($stmt === false) { + throw \Doctrine\Common\DoctrineException::updateMe('Unknown statement object given.'); + } + } + + /** + * getConnection + * returns the connection object this statement uses + * + * @return Doctrine_Connection + */ + public function getConnection() + { + return $this->_conn; + } + public function getStatement() + { + return $this->_stmt; + } + public function getQuery() + { + return $this->_stmt->queryString; + } + + /** + * Bind a column to a PHP variable + * + * @param mixed $column Number of the column (1-indexed) or name of the column in the result set. + * If using the column name, be aware that the name should match + * the case of the column, as returned by the driver. + * + * @param string $param Name of the PHP variable to which the column will be bound. + * @param integer $type Data type of the parameter, specified by the PDO::PARAM_* constants. + * @return boolean Returns TRUE on success or FALSE on failure + */ + public function bindColumn($column, $param, $type = null) + { + if ($type === null) { + return $this->_stmt->bindColumn($column, $param); + } else { + return $this->_stmt->bindColumn($column, $param, $type); + } + } + + /** + * bindValue + * Binds a value to a corresponding named or question mark + * placeholder in the SQL statement that was use to prepare the statement. + * + * @param mixed $param Parameter identifier. For a prepared statement using named placeholders, + * this will be a parameter name of the form :name. For a prepared statement + * using question mark placeholders, this will be the 1-indexed position of the parameter + * + * @param mixed $value The value to bind to the parameter. + * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. + * + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function bindValue($param, $value, $type = null) + { + if ($type === null) { + return $this->_stmt->bindValue($param, $value); + } else { + return $this->_stmt->bindValue($param, $value, $type); + } + } + + /** + * Binds a PHP variable to a corresponding named or question mark placeholder in the + * SQL statement that was use to prepare the statement. Unlike PDOStatement->bindValue(), + * the variable is bound as a reference and will only be evaluated at the time + * that PDOStatement->execute() is called. + * + * Most parameters are input parameters, that is, parameters that are + * used in a read-only fashion to build up the query. Some drivers support the invocation + * of stored procedures that return data as output parameters, and some also as input/output + * parameters that both send in data and are updated to receive it. + * + * @param mixed $param Parameter identifier. For a prepared statement using named placeholders, + * this will be a parameter name of the form :name. For a prepared statement + * using question mark placeholders, this will be the 1-indexed position of the parameter + * + * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter. + * + * @param integer $type Explicit data type for the parameter using the PDO::PARAM_* constants. To return + * an INOUT parameter from a stored procedure, use the bitwise OR operator to set the + * PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter. + * + * @param integer $length Length of the data type. To indicate that a parameter is an OUT parameter + * from a stored procedure, you must explicitly set the length. + * @param mixed $driverOptions + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function bindParam($column, &$variable, $type = null, $length = null, $driverOptions = array()) + { + if ($type === null) { + return $this->_stmt->bindParam($column, $variable); + } else { + return $this->_stmt->bindParam($column, $variable, $type, $length, $driverOptions); + } + } + + /** + * Closes the cursor, enabling the statement to be executed again. + * + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function closeCursor() + { + return $this->_stmt->closeCursor(); + } + + /** + * Returns the number of columns in the result set + * + * @return integer Returns the number of columns in the result set represented + * by the PDOStatement object. If there is no result set, + * this method should return 0. + */ + public function columnCount() + { + return $this->_stmt->columnCount(); + } + + /** + * Fetch the SQLSTATE associated with the last operation on the statement handle + * + * @see Doctrine_Adapter_Interface::errorCode() + * @return string error code string + */ + public function errorCode() + { + return $this->_stmt->errorCode(); + } + + /** + * Fetch extended error information associated with the last operation on the statement handle + * + * @see Doctrine_Adapter_Interface::errorInfo() + * @return array error info array + */ + public function errorInfo() + { + return $this->_stmt->errorInfo(); + } + + /** + * Executes a prepared statement + * + * If the prepared statement included parameter markers, you must either: + * call PDOStatement->bindParam() to bind PHP variables to the parameter markers: + * bound variables pass their value as input and receive the output value, + * if any, of their associated parameter markers or pass an array of input-only + * parameter values + * + * + * @param array $params An array of values with as many elements as there are + * bound parameters in the SQL statement being executed. + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function execute($params = null) + { + try { + //$event = new Doctrine_Event($this, Doctrine_Event::STMT_EXECUTE, $this->getQuery(), $params); + //$this->_conn->getListener()->preStmtExecute($event); + + $result = true; + //if ( ! $event->skipOperation) { + $result = $this->_stmt->execute($params); + //$this->_conn->incrementQueryCount(); + //} + + //$this->_conn->getListener()->postStmtExecute($event); + + return $result; + } catch (PDOException $e) { + $this->_conn->rethrowException($e, $this); + } + + return false; + } + + /** + * fetch + * + * @see Query::HYDRATE_* constants + * @param integer $fetchStyle Controls how the next row will be returned to the caller. + * This value must be one of the Query::HYDRATE_* constants, + * defaulting to Query::HYDRATE_BOTH + * + * @param integer $cursorOrientation For a PDOStatement object representing a scrollable cursor, + * this value determines which row will be returned to the caller. + * This value must be one of the Query::HYDRATE_ORI_* constants, defaulting to + * Query::HYDRATE_ORI_NEXT. To request a scrollable cursor for your + * PDOStatement object, + * you must set the PDO::ATTR_CURSOR attribute to Doctrine::CURSOR_SCROLL when you + * prepare the SQL statement with Doctrine_Adapter_Interface->prepare(). + * + * @param integer $cursorOffset For a PDOStatement object representing a scrollable cursor for which the + * $cursorOrientation parameter is set to Query::HYDRATE_ORI_ABS, this value specifies + * the absolute number of the row in the result set that shall be fetched. + * + * For a PDOStatement object representing a scrollable cursor for + * which the $cursorOrientation parameter is set to Query::HYDRATE_ORI_REL, this value + * specifies the row to fetch relative to the cursor position before + * PDOStatement->fetch() was called. + * + * @return mixed + */ + public function fetch($fetchMode = Query::HYDRATE_BOTH, + $cursorOrientation = Query::HYDRATE_ORI_NEXT, + $cursorOffset = null) + { + //$event = new Doctrine_Event($this, Doctrine_Event::STMT_FETCH, $this->getQuery()); + //$event->fetchMode = $fetchMode; + //$event->cursorOrientation = $cursorOrientation; + //$event->cursorOffset = $cursorOffset; + + //$data = $this->_conn->getListener()->preFetch($event); + + //if ( ! $event->skipOperation) { + $data = $this->_stmt->fetch($fetchMode, $cursorOrientation, $cursorOffset); + //} + + //$this->_conn->getListener()->postFetch($event); + + return $data; + } + + /** + * Returns an array containing all of the result set rows + * + * @param integer $fetchMode Controls how the next row will be returned to the caller. + * This value must be one of the Query::HYDRATE_* constants, + * defaulting to Query::HYDRATE_BOTH + * + * @param integer $columnIndex Returns the indicated 0-indexed column when the value of $fetchStyle is + * Query::HYDRATE_COLUMN. Defaults to 0. + * + * @return array + */ + public function fetchAll($fetchMode = Query::HYDRATE_BOTH, $columnIndex = null) + { + //$event = new Doctrine_Event($this, Doctrine_Event::STMT_FETCHALL, $this->getQuery()); + //$event->fetchMode = $fetchMode; + //$event->columnIndex = $columnIndex; + //$this->_conn->getListener()->preFetchAll($event); + + //if ( ! $event->skipOperation) { + if ($columnIndex !== null) { + $data = $this->_stmt->fetchAll($fetchMode, $columnIndex); + } else { + $data = $this->_stmt->fetchAll($fetchMode); + } + //$event->data = $data; + //} + + //$this->_conn->getListener()->postFetchAll($event); + + return $data; + } + + /** + * Returns a single column from the next row of a + * result set or FALSE if there are no more rows. + * + * @param integer $columnIndex 0-indexed number of the column you wish to retrieve from the row. If no + * value is supplied, PDOStatement->fetchColumn() + * fetches the first column. + * + * @return string returns a single column in the next row of a result set. + */ + public function fetchColumn($columnIndex = 0) + { + return $this->_stmt->fetchColumn($columnIndex); + } + + /** + * Fetches the next row and returns it as an object. + * + * Fetches the next row and returns it as an object. This function is an alternative to + * PDOStatement->fetch() with Query::HYDRATE_CLASS or Query::HYDRATE_OBJ style. + * + * @param string $className Name of the created class, defaults to stdClass. + * @param array $args Elements of this array are passed to the constructor. + * + * @return mixed an instance of the required class with property names that correspond + * to the column names or FALSE in case of an error. + */ + public function fetchObject($className = 'stdClass', $args = array()) + { + return $this->_stmt->fetchObject($className, $args); + } + + /** + * Retrieve a statement attribute + * + * @param integer $attribute + * @see Doctrine::ATTR_* constants + * @return mixed the attribute value + */ + public function getAttribute($attribute) + { + return $this->_stmt->getAttribute($attribute); + } + + /** + * Returns metadata for a column in a result set + * + * @param integer $column The 0-indexed column in the result set. + * + * @return array Associative meta data array with the following structure: + * + * native_type The PHP native type used to represent the column value. + * driver:decl_ type The SQL type used to represent the column value in the database. If the column in the result set is the result of a function, this value is not returned by PDOStatement->getColumnMeta(). + * flags Any flags set for this column. + * name The name of this column as returned by the database. + * len The length of this column. Normally -1 for types other than floating point decimals. + * precision The numeric precision of this column. Normally 0 for types other than floating point decimals. + * pdo_type The type of this column as represented by the PDO::PARAM_* constants. + */ + public function getColumnMeta($column) + { + return $this->_stmt->getColumnMeta($column); + } + + /** + * Advances to the next rowset in a multi-rowset statement handle + * + * Some database servers support stored procedures that return more than one rowset + * (also known as a result set). The nextRowset() method enables you to access the second + * and subsequent rowsets associated with a PDOStatement object. Each rowset can have a + * different set of columns from the preceding rowset. + * + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function nextRowset() + { + return $this->_stmt->nextRowset(); + } + + /** + * rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement + * executed by the corresponding object. + * + * If the last SQL statement executed by the associated Statement object was a SELECT statement, + * some databases may return the number of rows returned by that statement. However, + * this behaviour is not guaranteed for all databases and should not be + * relied on for portable applications. + * + * @return integer Returns the number of rows. + */ + public function rowCount() + { + return $this->_stmt->rowCount(); + } + + /** + * Set a statement attribute + * + * @param integer $attribute + * @param mixed $value the value of given attribute + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function setAttribute($attribute, $value) + { + return $this->_stmt->setAttribute($attribute, $value); + } + + /** + * Set the default fetch mode for this statement + * + * @param integer $mode The fetch mode must be one of the Query::HYDRATE_* constants. + * @return boolean Returns 1 on success or FALSE on failure. + */ + public function setFetchMode($mode, $arg1 = null, $arg2 = null) + { + return $this->_stmt->setFetchMode($mode, $arg1, $arg2); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Cache/ApcCache.php b/lib/Doctrine/ORM/Cache/ApcCache.php index a9c602b81..f62093e92 100644 --- a/lib/Doctrine/ORM/Cache/ApcCache.php +++ b/lib/Doctrine/ORM/Cache/ApcCache.php @@ -1,77 +1,77 @@ -. - */ - -namespace Doctrine\ORM\Cache; - -/** - * APC cache driver. - * - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.doctrine-project.org - * @since 1.0 - * @version $Revision: 4910 $ - * @author Konsta Vesterinen - * @author Roman Borschel - */ -class ApcCache implements Cache -{ - /** - * {@inheritdoc} - */ - public function __construct() - { - if ( ! extension_loaded('apc')) { - \Doctrine\Common\DoctrineException::updateMe('The apc extension must be loaded in order to use the ApcCache.'); - } - } - - /** - * {@inheritdoc} - */ - public function fetch($id) - { - return apc_fetch($id); - } - - /** - * {@inheritdoc} - */ - public function contains($id) - { - return apc_fetch($id) === false ? false : true; - } - - /** - * {@inheritdoc} - */ - public function save($id, $data, $lifeTime = false) - { - return (bool) apc_store($id, $data, $lifeTime); - } - - /** - * {@inheritdoc} - */ - public function delete($id) - { - return apc_delete($id); - } +. + */ + +namespace Doctrine\ORM\Cache; + +/** + * APC cache driver. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 1.0 + * @version $Revision: 4910 $ + * @author Konsta Vesterinen + * @author Roman Borschel + */ +class ApcCache implements Cache +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + if ( ! extension_loaded('apc')) { + \Doctrine\Common\DoctrineException::updateMe('The apc extension must be loaded in order to use the ApcCache.'); + } + } + + /** + * {@inheritdoc} + */ + public function fetch($id) + { + return apc_fetch($id); + } + + /** + * {@inheritdoc} + */ + public function contains($id) + { + return apc_fetch($id) === false ? false : true; + } + + /** + * {@inheritdoc} + */ + public function save($id, $data, $lifeTime = false) + { + return (bool) apc_store($id, $data, $lifeTime); + } + + /** + * {@inheritdoc} + */ + public function delete($id) + { + return apc_delete($id); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Cache/ArrayCache.php b/lib/Doctrine/ORM/Cache/ArrayCache.php index 6a6d2ff39..010361158 100644 --- a/lib/Doctrine/ORM/Cache/ArrayCache.php +++ b/lib/Doctrine/ORM/Cache/ArrayCache.php @@ -1,92 +1,92 @@ -. - */ - -namespace Doctrine\ORM\Cache; - -/** - * Array cache driver. - * - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.doctrine-project.org - * @since 1.0 - * @version $Revision: 4910 $ - * @author Konsta Vesterinen - */ -class ArrayCache implements Cache -{ - /** - * @var array $data - */ - private $data; - - /** - * {@inheritdoc} - */ - public function fetch($id) - { - if (isset($this->data[$id])) { - return $this->data[$id]; - } - return false; - } - - /** - * {@inheritdoc} - */ - public function contains($id) - { - return isset($this->data[$id]); - } - - /** - * {@inheritdoc} - */ - public function save($id, $data, $lifeTime = false) - { - $this->data[$id] = $data; - } - - /** - * {@inheritdoc} - */ - public function delete($id) - { - unset($this->data[$id]); - } - - /** - * {@inheritdoc} - */ - public function deleteAll() - { - $this->data = array(); - } - - /** - * count - * - * @return integer - */ - public function count() - { - return count($this->data); - } +. + */ + +namespace Doctrine\ORM\Cache; + +/** + * Array cache driver. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 1.0 + * @version $Revision: 4910 $ + * @author Konsta Vesterinen + */ +class ArrayCache implements Cache +{ + /** + * @var array $data + */ + private $data; + + /** + * {@inheritdoc} + */ + public function fetch($id) + { + if (isset($this->data[$id])) { + return $this->data[$id]; + } + return false; + } + + /** + * {@inheritdoc} + */ + public function contains($id) + { + return isset($this->data[$id]); + } + + /** + * {@inheritdoc} + */ + public function save($id, $data, $lifeTime = false) + { + $this->data[$id] = $data; + } + + /** + * {@inheritdoc} + */ + public function delete($id) + { + unset($this->data[$id]); + } + + /** + * {@inheritdoc} + */ + public function deleteAll() + { + $this->data = array(); + } + + /** + * count + * + * @return integer + */ + public function count() + { + return count($this->data); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Cache/Cache.php b/lib/Doctrine/ORM/Cache/Cache.php index e2176b44c..8d00867f8 100644 --- a/lib/Doctrine/ORM/Cache/Cache.php +++ b/lib/Doctrine/ORM/Cache/Cache.php @@ -1,71 +1,71 @@ -. - */ - -namespace Doctrine\ORM\Cache; - -/** - * Interface for cache drivers. - * - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.doctrine-project.org - * @since 1.0 - * @version $Revision: 3931 $ - * @author Konsta Vesterinen - * @author Roman Borschel - */ -interface Cache -{ - /** - * Test if a cache entry is available for the given id and (if yes) return it (false else). - * - * Note : return value is always "string" (unserialization is done by the core not by the backend) - * - * @param string $id cache id - * @return string cached datas (or false) - */ - public function fetch($id); - - /** - * Test if a cache is available or not (for the given id) - * - * @param string $id cache id - * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record - */ - public function contains($id); - - /** - * Puts data into the cache. - * - * @param string $id cache id - * @param string $data data to cache - * @param int $lifeTime if != false, set a specific lifetime for this cache record (null => infinite lifeTime) - * @return boolean true if no problem - */ - public function save($id, $data, $lifeTime = false); - - /** - * Remove a cache record - * - * @param string $id cache id - * @return boolean true if no problem - */ - public function delete($id); +. + */ + +namespace Doctrine\ORM\Cache; + +/** + * Interface for cache drivers. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 1.0 + * @version $Revision: 3931 $ + * @author Konsta Vesterinen + * @author Roman Borschel + */ +interface Cache +{ + /** + * Test if a cache entry is available for the given id and (if yes) return it (false else). + * + * Note : return value is always "string" (unserialization is done by the core not by the backend) + * + * @param string $id cache id + * @return string cached datas (or false) + */ + public function fetch($id); + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id cache id + * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function contains($id); + + /** + * Puts data into the cache. + * + * @param string $id cache id + * @param string $data data to cache + * @param int $lifeTime if != false, set a specific lifetime for this cache record (null => infinite lifeTime) + * @return boolean true if no problem + */ + public function save($id, $data, $lifeTime = false); + + /** + * Remove a cache record + * + * @param string $id cache id + * @return boolean true if no problem + */ + public function delete($id); } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Cache/DbCache.php b/lib/Doctrine/ORM/Cache/DbCache.php index 7ca7eda09..f6fba9720 100644 --- a/lib/Doctrine/ORM/Cache/DbCache.php +++ b/lib/Doctrine/ORM/Cache/DbCache.php @@ -1,181 +1,181 @@ -. - */ - -namespace Doctrine\ORM\Cache; - -/** - * Doctrine_Cache_Db - * - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.doctrine-project.org - * @since 1.0 - * @version $Revision: 3931 $ - * @author Konsta Vesterinen - * @todo Needs some maintenance. Any takers? - */ -class DbCache implements Cache, \Countable -{ - private $_options = array(); - - /** - * {@inheritdoc} - */ - public function __construct($options) - { - if ( ! isset($options['connection']) || - ! ($options['connection'] instanceof Doctrine_DBAL_Connection)) { - - throw \Doctrine\Common\DoctrineException::updateMe('Connection option not set.'); - } - - if ( ! isset($options['tableName']) || - ! is_string($options['tableName'])) { - - throw \Doctrine\Common\DoctrineException::updateMe('Table name option not set.'); - } - - $this->_options = $options; - } - - /** - * getConnection - * returns the connection object associated with this cache driver - * - * @return Doctrine_Connection connection object - */ - public function getConnection() - { - return $this->_options['connection']; - } - - /** - * {@inheritdoc} - */ - public function fetch($id) - { - $sql = 'SELECT data, expire FROM ' . $this->_options['tableName'] - . ' WHERE id = ?'; - - if ($testCacheValidity) { - $sql .= ' AND (expire=0 OR expire > ' . time() . ')'; - } - - $result = $this->getConnection()->fetchAssoc($sql, array($id)); - - if ( ! isset($result[0])) { - return false; - } - - return unserialize($result[0]['data']); - } - - /** - * {@inheritdoc} - */ - public function contains($id) - { - $sql = 'SELECT expire FROM ' . $this->_options['tableName'] - . ' WHERE id = ? AND (expire=0 OR expire > ' . time() . ')'; - - return $this->getConnection()->fetchOne($sql, array($id)); - } - - /** - * {@inheritdoc} - */ - public function save($data, $id, $lifeTime = false) - { - $sql = 'INSERT INTO ' . $this->_options['tableName'] - . ' (id, data, expire) VALUES (?, ?, ?)'; - - if ($lifeTime) { - $expire = time() + $lifeTime; - } else { - $expire = 0; - } - - $params = array($id, serialize($data), $expire); - - return (bool) $this->getConnection()->exec($sql, $params); - } - - /** - * {@inheritdoc} - */ - public function delete($id) - { - $sql = 'DELETE FROM ' . $this->_options['tableName'] . ' WHERE id = ?'; - - return (bool) $this->getConnection()->exec($sql, array($id)); - } - - /** - * Removes all cache records - * - * $return bool true on success, false on failure - */ - public function deleteAll() - { - $sql = 'DELETE FROM ' . $this->_options['tableName']; - - return (bool) $this->getConnection()->exec($sql); - } - - /** - * count - * returns the number of cached elements - * - * @return integer - */ - public function count() - { - $sql = 'SELECT COUNT(*) FROM ' . $this->_options['tableName']; - - return (int) $this->getConnection()->fetchOne($sql); - } - - /** - * Creates the cache table. - */ - public function createTable() - { - $name = $this->_options['tableName']; - - $fields = array( - 'id' => array( - 'type' => 'string', - 'length' => 255 - ), - 'data' => array( - 'type' => 'blob' - ), - 'expire' => array( - 'type' => 'timestamp' - ) - ); - - $options = array( - 'primary' => array('id') - ); - - $this->getConnection()->export->createTable($name, $fields, $options); - } +. + */ + +namespace Doctrine\ORM\Cache; + +/** + * Doctrine_Cache_Db + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.org + * @since 1.0 + * @version $Revision: 3931 $ + * @author Konsta Vesterinen + * @todo Needs some maintenance. Any takers? + */ +class DbCache implements Cache, \Countable +{ + private $_options = array(); + + /** + * {@inheritdoc} + */ + public function __construct($options) + { + if ( ! isset($options['connection']) || + ! ($options['connection'] instanceof Doctrine_DBAL_Connection)) { + + throw \Doctrine\Common\DoctrineException::updateMe('Connection option not set.'); + } + + if ( ! isset($options['tableName']) || + ! is_string($options['tableName'])) { + + throw \Doctrine\Common\DoctrineException::updateMe('Table name option not set.'); + } + + $this->_options = $options; + } + + /** + * getConnection + * returns the connection object associated with this cache driver + * + * @return Doctrine_Connection connection object + */ + public function getConnection() + { + return $this->_options['connection']; + } + + /** + * {@inheritdoc} + */ + public function fetch($id) + { + $sql = 'SELECT data, expire FROM ' . $this->_options['tableName'] + . ' WHERE id = ?'; + + if ($testCacheValidity) { + $sql .= ' AND (expire=0 OR expire > ' . time() . ')'; + } + + $result = $this->getConnection()->fetchAssoc($sql, array($id)); + + if ( ! isset($result[0])) { + return false; + } + + return unserialize($result[0]['data']); + } + + /** + * {@inheritdoc} + */ + public function contains($id) + { + $sql = 'SELECT expire FROM ' . $this->_options['tableName'] + . ' WHERE id = ? AND (expire=0 OR expire > ' . time() . ')'; + + return $this->getConnection()->fetchOne($sql, array($id)); + } + + /** + * {@inheritdoc} + */ + public function save($data, $id, $lifeTime = false) + { + $sql = 'INSERT INTO ' . $this->_options['tableName'] + . ' (id, data, expire) VALUES (?, ?, ?)'; + + if ($lifeTime) { + $expire = time() + $lifeTime; + } else { + $expire = 0; + } + + $params = array($id, serialize($data), $expire); + + return (bool) $this->getConnection()->exec($sql, $params); + } + + /** + * {@inheritdoc} + */ + public function delete($id) + { + $sql = 'DELETE FROM ' . $this->_options['tableName'] . ' WHERE id = ?'; + + return (bool) $this->getConnection()->exec($sql, array($id)); + } + + /** + * Removes all cache records + * + * $return bool true on success, false on failure + */ + public function deleteAll() + { + $sql = 'DELETE FROM ' . $this->_options['tableName']; + + return (bool) $this->getConnection()->exec($sql); + } + + /** + * count + * returns the number of cached elements + * + * @return integer + */ + public function count() + { + $sql = 'SELECT COUNT(*) FROM ' . $this->_options['tableName']; + + return (int) $this->getConnection()->fetchOne($sql); + } + + /** + * Creates the cache table. + */ + public function createTable() + { + $name = $this->_options['tableName']; + + $fields = array( + 'id' => array( + 'type' => 'string', + 'length' => 255 + ), + 'data' => array( + 'type' => 'blob' + ), + 'expire' => array( + 'type' => 'timestamp' + ) + ); + + $options = array( + 'primary' => array('id') + ); + + $this->getConnection()->export->createTable($name, $fields, $options); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Cache/MemcacheCache.php b/lib/Doctrine/ORM/Cache/MemcacheCache.php index f11207479..64d3e7758 100644 --- a/lib/Doctrine/ORM/Cache/MemcacheCache.php +++ b/lib/Doctrine/ORM/Cache/MemcacheCache.php @@ -1,101 +1,101 @@ -. - */ - -namespace Doctrine\ORM\Cache; - -/** - * Memcache cache driver. - * - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.phpdoctrine.org - * @since 1.0 - * @version $Revision: 4910 $ - * @author Konsta Vesterinen - */ -class MemcacheCache implements Cache -{ - /** - * @var Memcache $_memcache memcache object - */ - private $_memcache; - - /** - * {@inheritdoc} - */ - public function __construct() - { - if ( ! extension_loaded('memcache')) { - throw \Doctrine\Common\DoctrineException::updateMe('In order to use Memcache driver, the memcache extension must be loaded.'); - } - } - - /** - * Sets the memcache instance to use. - * - * @param Memcache $memcache - */ - public function setMemcache(Memcache $memcache) - { - $this->_memcache = $memcache; - } - - /** - * Gets the memcache instance used by the cache. - * - * @return Memcache - */ - public function getMemcache() - { - return $this->_memcache; - } - - /** - * {@inheritdoc} - */ - public function fetch($id) - { - return $this->_memcache->get($id); - } - - /** - * {@inheritdoc} - */ - public function contains($id) - { - return (bool) $this->_memcache->get($id); - } - - /** - * {@inheritdoc} - */ - public function save($id, $data, $lifeTime = false) - { - return $this->_memcache->set($id, $data, 0, $lifeTime); - } - - /** - * {@inheritdoc} - */ - public function delete($id) - { - return $this->_memcache->delete($id); - } +. + */ + +namespace Doctrine\ORM\Cache; + +/** + * Memcache cache driver. + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.phpdoctrine.org + * @since 1.0 + * @version $Revision: 4910 $ + * @author Konsta Vesterinen + */ +class MemcacheCache implements Cache +{ + /** + * @var Memcache $_memcache memcache object + */ + private $_memcache; + + /** + * {@inheritdoc} + */ + public function __construct() + { + if ( ! extension_loaded('memcache')) { + throw \Doctrine\Common\DoctrineException::updateMe('In order to use Memcache driver, the memcache extension must be loaded.'); + } + } + + /** + * Sets the memcache instance to use. + * + * @param Memcache $memcache + */ + public function setMemcache(Memcache $memcache) + { + $this->_memcache = $memcache; + } + + /** + * Gets the memcache instance used by the cache. + * + * @return Memcache + */ + public function getMemcache() + { + return $this->_memcache; + } + + /** + * {@inheritdoc} + */ + public function fetch($id) + { + return $this->_memcache->get($id); + } + + /** + * {@inheritdoc} + */ + public function contains($id) + { + return (bool) $this->_memcache->get($id); + } + + /** + * {@inheritdoc} + */ + public function save($id, $data, $lifeTime = false) + { + return $this->_memcache->set($id, $data, 0, $lifeTime); + } + + /** + * {@inheritdoc} + */ + public function delete($id) + { + return $this->_memcache->delete($id); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/DeleteStatement.php b/lib/Doctrine/ORM/Query/AST/DeleteStatement.php index 81f5e9c60..9afaad74b 100644 --- a/lib/Doctrine/ORM/Query/AST/DeleteStatement.php +++ b/lib/Doctrine/ORM/Query/AST/DeleteStatement.php @@ -1,62 +1,62 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * DeleteStatement = DeleteClause [WhereClause] - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.phpdoctrine.org - * @since 2.0 - * @version $Revision$ - */ -class DeleteStatement extends Node -{ - private $_deleteClause; - private $_whereClause; - - public function __construct($deleteClause) - { - $this->_deleteClause = $deleteClause; - } - - public function setWhereClause($whereClause) - { - $this->_whereClause = $whereClause; - } - - public function getDeleteClause() - { - return $this->_deleteClause; - } - - public function getWhereClause() - { - return $this->_whereClause; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkDeleteStatement($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * DeleteStatement = DeleteClause [WhereClause] + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.phpdoctrine.org + * @since 2.0 + * @version $Revision$ + */ +class DeleteStatement extends Node +{ + private $_deleteClause; + private $_whereClause; + + public function __construct($deleteClause) + { + $this->_deleteClause = $deleteClause; + } + + public function setWhereClause($whereClause) + { + $this->_whereClause = $whereClause; + } + + public function getDeleteClause() + { + return $this->_deleteClause; + } + + public function getWhereClause() + { + return $this->_whereClause; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkDeleteStatement($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/FromClause.php b/lib/Doctrine/ORM/Query/AST/FromClause.php index 5732f05d9..10cb58216 100644 --- a/lib/Doctrine/ORM/Query/AST/FromClause.php +++ b/lib/Doctrine/ORM/Query/AST/FromClause.php @@ -1,52 +1,52 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration} - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.phpdoctrine.org - * @since 2.0 - * @version $Revision$ - */ -class FromClause extends Node -{ - protected $_identificationVariableDeclarations = array(); - - public function __construct(array $identificationVariableDeclarations) - { - $this->_identificationVariableDeclarations = $identificationVariableDeclarations; - } - - /* Getters */ - public function getIdentificationVariableDeclarations() - { - return $this->_identificationVariableDeclarations; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkFromClause($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration} + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.phpdoctrine.org + * @since 2.0 + * @version $Revision$ + */ +class FromClause extends Node +{ + protected $_identificationVariableDeclarations = array(); + + public function __construct(array $identificationVariableDeclarations) + { + $this->_identificationVariableDeclarations = $identificationVariableDeclarations; + } + + /* Getters */ + public function getIdentificationVariableDeclarations() + { + return $this->_identificationVariableDeclarations; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkFromClause($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/IdentificationVariableDeclaration.php b/lib/Doctrine/ORM/Query/AST/IdentificationVariableDeclaration.php index 148cf0420..e829a52b0 100644 --- a/lib/Doctrine/ORM/Query/AST/IdentificationVariableDeclaration.php +++ b/lib/Doctrine/ORM/Query/AST/IdentificationVariableDeclaration.php @@ -1,70 +1,70 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}* - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -class IdentificationVariableDeclaration extends Node -{ - protected $_rangeVariableDeclaration = null; - - protected $_indexBy = null; - - protected $_joinVariableDeclarations = array(); - - public function __construct($rangeVariableDecl, $indexBy, array $joinVariableDecls) - { - $this->_rangeVariableDeclaration = $rangeVariableDecl; - $this->_indexBy = $indexBy; - $this->_joinVariableDeclarations = $joinVariableDecls; - } - - /* Getters */ - public function getRangeVariableDeclaration() - { - return $this->_rangeVariableDeclaration; - } - - - public function getIndexBy() - { - return $this->_indexBy; - } - - - public function getJoinVariableDeclarations() - { - return $this->_joinVariableDeclarations; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkIdentificationVariableDeclaration($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}* + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +class IdentificationVariableDeclaration extends Node +{ + protected $_rangeVariableDeclaration = null; + + protected $_indexBy = null; + + protected $_joinVariableDeclarations = array(); + + public function __construct($rangeVariableDecl, $indexBy, array $joinVariableDecls) + { + $this->_rangeVariableDeclaration = $rangeVariableDecl; + $this->_indexBy = $indexBy; + $this->_joinVariableDeclarations = $joinVariableDecls; + } + + /* Getters */ + public function getRangeVariableDeclaration() + { + return $this->_rangeVariableDeclaration; + } + + + public function getIndexBy() + { + return $this->_indexBy; + } + + + public function getJoinVariableDeclarations() + { + return $this->_joinVariableDeclarations; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkIdentificationVariableDeclaration($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/IndexBy.php b/lib/Doctrine/ORM/Query/AST/IndexBy.php index 0aaa00c6a..c2be040df 100644 --- a/lib/Doctrine/ORM/Query/AST/IndexBy.php +++ b/lib/Doctrine/ORM/Query/AST/IndexBy.php @@ -1,52 +1,52 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * IndexBy ::= "INDEX" "BY" SimpleStateFieldPathExpression - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -class IndexBy extends Node -{ - protected $_simpleStateFieldPathExpression = null; - - public function __construct($simpleStateFieldPathExpression) - { - $this->_simpleStateFieldPathExpression = $simpleStateFieldPathExpression; - } - - /* Getters */ - public function getSimpleStateFieldPathExpression() - { - return $this->_simpleStateFieldPathExpression; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkIndexBy($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * IndexBy ::= "INDEX" "BY" SimpleStateFieldPathExpression + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +class IndexBy extends Node +{ + protected $_simpleStateFieldPathExpression = null; + + public function __construct($simpleStateFieldPathExpression) + { + $this->_simpleStateFieldPathExpression = $simpleStateFieldPathExpression; + } + + /* Getters */ + public function getSimpleStateFieldPathExpression() + { + return $this->_simpleStateFieldPathExpression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkIndexBy($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/Join.php b/lib/Doctrine/ORM/Query/AST/Join.php index 0ea93ae9c..3fab1791d 100644 --- a/lib/Doctrine/ORM/Query/AST/Join.php +++ b/lib/Doctrine/ORM/Query/AST/Join.php @@ -1,97 +1,97 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression - * ["AS"] AliasIdentificationVariable [("ON" | "WITH") ConditionalExpression] - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.phpdoctrine.org - * @since 2.0 - * @version $Revision$ - */ -class Join extends Node -{ - const JOIN_TYPE_LEFT = 1; - const JOIN_TYPE_LEFTOUTER = 2; - const JOIN_TYPE_INNER = 3; - const JOIN_WHERE_ON = 1; - const JOIN_WHERE_WITH = 2; - - protected $_joinType = self::JOIN_TYPE_INNER; - protected $_joinAssociationPathExpression = null; - protected $_aliasIdentificationVariable = null; - protected $_whereType = self::JOIN_WHERE_WITH; - protected $_conditionalExpression = null; - - public function __construct($joinType, $joinAssocPathExpr, $aliasIdentVar) - { - $this->_joinType = $joinType; - $this->_joinAssociationPathExpression = $joinAssocPathExpr; - $this->_aliasIdentificationVariable = $aliasIdentVar; - } - - /* Setters */ - - public function setWhereType($whereType) - { - $this->_whereType = $whereType; - } - - public function setConditionalExpression($conditionalExpression) - { - $this->_conditionalExpression = $conditionalExpression; - } - - /* Getters */ - public function getJoinType() - { - return $this->_joinType; - } - - public function getJoinAssociationPathExpression() - { - return $this->_joinAssociationPathExpression; - } - - public function getAliasIdentificationVariable() - { - return $this->_aliasIdentificationVariable; - } - - public function getWhereType() - { - return $this->_whereType; - } - - public function getConditionalExpression() - { - return $this->_conditionalExpression; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkJoin($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression + * ["AS"] AliasIdentificationVariable [("ON" | "WITH") ConditionalExpression] + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.phpdoctrine.org + * @since 2.0 + * @version $Revision$ + */ +class Join extends Node +{ + const JOIN_TYPE_LEFT = 1; + const JOIN_TYPE_LEFTOUTER = 2; + const JOIN_TYPE_INNER = 3; + const JOIN_WHERE_ON = 1; + const JOIN_WHERE_WITH = 2; + + protected $_joinType = self::JOIN_TYPE_INNER; + protected $_joinAssociationPathExpression = null; + protected $_aliasIdentificationVariable = null; + protected $_whereType = self::JOIN_WHERE_WITH; + protected $_conditionalExpression = null; + + public function __construct($joinType, $joinAssocPathExpr, $aliasIdentVar) + { + $this->_joinType = $joinType; + $this->_joinAssociationPathExpression = $joinAssocPathExpr; + $this->_aliasIdentificationVariable = $aliasIdentVar; + } + + /* Setters */ + + public function setWhereType($whereType) + { + $this->_whereType = $whereType; + } + + public function setConditionalExpression($conditionalExpression) + { + $this->_conditionalExpression = $conditionalExpression; + } + + /* Getters */ + public function getJoinType() + { + return $this->_joinType; + } + + public function getJoinAssociationPathExpression() + { + return $this->_joinAssociationPathExpression; + } + + public function getAliasIdentificationVariable() + { + return $this->_aliasIdentificationVariable; + } + + public function getWhereType() + { + return $this->_whereType; + } + + public function getConditionalExpression() + { + return $this->_conditionalExpression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkJoin($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/JoinVariableDeclaration.php b/lib/Doctrine/ORM/Query/AST/JoinVariableDeclaration.php index 50545462a..7d2bf9d29 100644 --- a/lib/Doctrine/ORM/Query/AST/JoinVariableDeclaration.php +++ b/lib/Doctrine/ORM/Query/AST/JoinVariableDeclaration.php @@ -1,59 +1,59 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * JoinVariableDeclaration ::= Join [IndexBy] - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.phpdoctrine.org - * @since 2.0 - * @version $Revision$ - */ -class JoinVariableDeclaration extends Node -{ - protected $_join = null; - protected $_indexBy = null; - - public function __construct($join, $indexBy) - { - $this->_join = $join; - $this->_indexBy = $indexBy; - } - - /* Getters */ - public function getJoin() - { - return $this->_join; - } - - public function getIndexBy() - { - return $this->_indexBy; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkJoinVariableDeclaration($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * JoinVariableDeclaration ::= Join [IndexBy] + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.phpdoctrine.org + * @since 2.0 + * @version $Revision$ + */ +class JoinVariableDeclaration extends Node +{ + protected $_join = null; + protected $_indexBy = null; + + public function __construct($join, $indexBy) + { + $this->_join = $join; + $this->_indexBy = $indexBy; + } + + /* Getters */ + public function getJoin() + { + return $this->_join; + } + + public function getIndexBy() + { + return $this->_indexBy; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkJoinVariableDeclaration($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/Node.php b/lib/Doctrine/ORM/Query/AST/Node.php index 53beb4079..8d5777787 100644 --- a/lib/Doctrine/ORM/Query/AST/Node.php +++ b/lib/Doctrine/ORM/Query/AST/Node.php @@ -1,38 +1,38 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * Abstract class of an AST node - * - * @author Guilherme Blanco - * @author Janne Vanhala - * @author Roman Borschel - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -abstract class Node -{ - abstract public function dispatch($sqlWalker); +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * Abstract class of an AST node + * + * @author Guilherme Blanco + * @author Janne Vanhala + * @author Roman Borschel + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +abstract class Node +{ + abstract public function dispatch($sqlWalker); } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/RangeVariableDeclaration.php b/lib/Doctrine/ORM/Query/AST/RangeVariableDeclaration.php index 639ace1f1..de1f5f61b 100644 --- a/lib/Doctrine/ORM/Query/AST/RangeVariableDeclaration.php +++ b/lib/Doctrine/ORM/Query/AST/RangeVariableDeclaration.php @@ -1,66 +1,66 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -class RangeVariableDeclaration extends Node -{ - private $_classMetadata; - private $_abstractSchemaName; - private $_aliasIdentificationVariable; - - public function __construct($classMetadata, $aliasIdentificationVar) - { - $this->_classMetadata = $classMetadata; - $this->_abstractSchemaName = $classMetadata->name; - $this->_aliasIdentificationVariable = $aliasIdentificationVar; - } - - /* Getters */ - public function getAbstractSchemaName() - { - return $this->_abstractSchemaName; - } - - public function getAliasIdentificationVariable() - { - return $this->_aliasIdentificationVariable; - } - - public function getClassMetadata() - { - return $this->_classMetadata; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkRangeVariableDeclaration($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +class RangeVariableDeclaration extends Node +{ + private $_classMetadata; + private $_abstractSchemaName; + private $_aliasIdentificationVariable; + + public function __construct($classMetadata, $aliasIdentificationVar) + { + $this->_classMetadata = $classMetadata; + $this->_abstractSchemaName = $classMetadata->name; + $this->_aliasIdentificationVariable = $aliasIdentificationVar; + } + + /* Getters */ + public function getAbstractSchemaName() + { + return $this->_abstractSchemaName; + } + + public function getAliasIdentificationVariable() + { + return $this->_aliasIdentificationVariable; + } + + public function getClassMetadata() + { + return $this->_classMetadata; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkRangeVariableDeclaration($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/SelectClause.php b/lib/Doctrine/ORM/Query/AST/SelectClause.php index cbde46c06..be4a0163e 100644 --- a/lib/Doctrine/ORM/Query/AST/SelectClause.php +++ b/lib/Doctrine/ORM/Query/AST/SelectClause.php @@ -1,77 +1,77 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * SelectClause = "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression} - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -class SelectClause extends Node -{ - protected $_isDistinct; - - protected $_selectExpressions = array(); - - public function __construct(array $selectExpressions, $isDistinct) - { - $this->_isDistinct = $isDistinct; - $this->_selectExpressions = $selectExpressions; - } - - /* Getters */ - public function isDistinct() - { - return $this->_isDistinct; - } - - public function getSelectExpressions() - { - return $this->_selectExpressions; - } - - /* REMOVE ME LATER. COPIED METHODS FROM SPLIT OF PRODUCTION INTO "AST" AND "PARSER" */ - public function buildSql() - { - return 'SELECT ' . (($this->_isDistinct) ? 'DISTINCT ' : '') - . implode(', ', $this->_mapSelectExpressions()); - } - - protected function _mapSelectExpressions() - { - return array_map(array(&$this, '_mapSelectExpression'), $this->_selectExpressions); - } - - protected function _mapSelectExpression($value) - { - return is_object($value) ? $value->buildSql() : $value; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkSelectClause($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SelectClause = "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression} + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +class SelectClause extends Node +{ + protected $_isDistinct; + + protected $_selectExpressions = array(); + + public function __construct(array $selectExpressions, $isDistinct) + { + $this->_isDistinct = $isDistinct; + $this->_selectExpressions = $selectExpressions; + } + + /* Getters */ + public function isDistinct() + { + return $this->_isDistinct; + } + + public function getSelectExpressions() + { + return $this->_selectExpressions; + } + + /* REMOVE ME LATER. COPIED METHODS FROM SPLIT OF PRODUCTION INTO "AST" AND "PARSER" */ + public function buildSql() + { + return 'SELECT ' . (($this->_isDistinct) ? 'DISTINCT ' : '') + . implode(', ', $this->_mapSelectExpressions()); + } + + protected function _mapSelectExpressions() + { + return array_map(array(&$this, '_mapSelectExpression'), $this->_selectExpressions); + } + + protected function _mapSelectExpression($value) + { + return is_object($value) ? $value->buildSql() : $value; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSelectClause($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/SelectExpression.php b/lib/Doctrine/ORM/Query/AST/SelectExpression.php index 055517d9e..3b12bc4f1 100644 --- a/lib/Doctrine/ORM/Query/AST/SelectExpression.php +++ b/lib/Doctrine/ORM/Query/AST/SelectExpression.php @@ -1,60 +1,60 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * SelectExpression ::= IdentificationVariable ["." "*"] | StateFieldPathExpression | - * (AggregateExpression | "(" Subselect ")") [["AS"] FieldAliasIdentificationVariable] - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.phpdoctrine.org - * @since 2.0 - * @version $Revision$ - */ -class SelectExpression extends Node -{ - protected $_expression; - protected $_fieldIdentificationVariable; - - public function __construct($expression, $fieldIdentificationVariable) - { - $this->_expression = $expression; - $this->_fieldIdentificationVariable = $fieldIdentificationVariable; - } - - /* Getters */ - public function getExpression() - { - return $this->_expression; - } - - public function getFieldIdentificationVariable() - { - return $this->_fieldIdentificationVariable; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkSelectExpression($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SelectExpression ::= IdentificationVariable ["." "*"] | StateFieldPathExpression | + * (AggregateExpression | "(" Subselect ")") [["AS"] FieldAliasIdentificationVariable] + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.phpdoctrine.org + * @since 2.0 + * @version $Revision$ + */ +class SelectExpression extends Node +{ + protected $_expression; + protected $_fieldIdentificationVariable; + + public function __construct($expression, $fieldIdentificationVariable) + { + $this->_expression = $expression; + $this->_fieldIdentificationVariable = $fieldIdentificationVariable; + } + + /* Getters */ + public function getExpression() + { + return $this->_expression; + } + + public function getFieldIdentificationVariable() + { + return $this->_fieldIdentificationVariable; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSelectExpression($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/SelectStatement.php b/lib/Doctrine/ORM/Query/AST/SelectStatement.php index a9edeb449..3e8c61498 100644 --- a/lib/Doctrine/ORM/Query/AST/SelectStatement.php +++ b/lib/Doctrine/ORM/Query/AST/SelectStatement.php @@ -1,87 +1,87 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * SelectStatement = SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.phpdoctrine.org - * @since 2.0 - * @version $Revision$ - */ -class SelectStatement extends Node -{ - protected $_selectClause; - protected $_fromClause; - protected $_whereClause; - protected $_groupByClause; - protected $_havingClause; - protected $_orderByClause; - - public function __construct($selectClause, $fromClause, $whereClause, $groupByClause, - $havingClause, $orderByClause) { - $this->_selectClause = $selectClause; - $this->_fromClause = $fromClause; - $this->_whereClause = $whereClause; - $this->_groupByClause = $groupByClause; - $this->_havingClause = $havingClause; - $this->_orderByClause = $orderByClause; - } - - /* Getters */ - public function getSelectClause() - { - return $this->_selectClause; - } - - public function getFromClause() - { - return $this->_fromClause; - } - - public function getWhereClause() - { - return $this->_whereClause; - } - - public function getGroupByClause() - { - return $this->_groupByClause; - } - - public function getHavingClause() - { - return $this->_havingClause; - } - - public function getOrderByClause() - { - return $this->_orderByClause; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkSelectStatement($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SelectStatement = SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.phpdoctrine.org + * @since 2.0 + * @version $Revision$ + */ +class SelectStatement extends Node +{ + protected $_selectClause; + protected $_fromClause; + protected $_whereClause; + protected $_groupByClause; + protected $_havingClause; + protected $_orderByClause; + + public function __construct($selectClause, $fromClause, $whereClause, $groupByClause, + $havingClause, $orderByClause) { + $this->_selectClause = $selectClause; + $this->_fromClause = $fromClause; + $this->_whereClause = $whereClause; + $this->_groupByClause = $groupByClause; + $this->_havingClause = $havingClause; + $this->_orderByClause = $orderByClause; + } + + /* Getters */ + public function getSelectClause() + { + return $this->_selectClause; + } + + public function getFromClause() + { + return $this->_fromClause; + } + + public function getWhereClause() + { + return $this->_whereClause; + } + + public function getGroupByClause() + { + return $this->_groupByClause; + } + + public function getHavingClause() + { + return $this->_havingClause; + } + + public function getOrderByClause() + { + return $this->_orderByClause; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSelectStatement($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/SimpleSelectClause.php b/lib/Doctrine/ORM/Query/AST/SimpleSelectClause.php index da41a5e02..7e03127bb 100644 --- a/lib/Doctrine/ORM/Query/AST/SimpleSelectClause.php +++ b/lib/Doctrine/ORM/Query/AST/SimpleSelectClause.php @@ -1,63 +1,63 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -class SimpleSelectClause extends Node -{ - private $_isDistinct = false; - private $_simpleSelectExpression; - - public function __construct($simpleSelectExpression) - { - $this->_simpleSelectExpression = $simpleSelectExpression; - } - - /* Getters */ - public function isDistinct() - { - return $this->_isDistinct; - } - - public function setDistinct($bool) - { - $this->_isDistinct = $bool; - } - - public function getSimpleSelectExpression() - { - return $this->_simpleSelectExpression; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkSimpleSelectClause($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +class SimpleSelectClause extends Node +{ + private $_isDistinct = false; + private $_simpleSelectExpression; + + public function __construct($simpleSelectExpression) + { + $this->_simpleSelectExpression = $simpleSelectExpression; + } + + /* Getters */ + public function isDistinct() + { + return $this->_isDistinct; + } + + public function setDistinct($bool) + { + $this->_isDistinct = $bool; + } + + public function getSimpleSelectExpression() + { + return $this->_simpleSelectExpression; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSimpleSelectClause($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/SimpleSelectExpression.php b/lib/Doctrine/ORM/Query/AST/SimpleSelectExpression.php index 0cb90e37c..5ebe42ed8 100644 --- a/lib/Doctrine/ORM/Query/AST/SimpleSelectExpression.php +++ b/lib/Doctrine/ORM/Query/AST/SimpleSelectExpression.php @@ -1,63 +1,63 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * SimpleSelectExpression ::= StateFieldPathExpression | IdentificationVariable - * | (AggregateExpression [["AS"] FieldAliasIdentificationVariable]) - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -class SimpleSelectExpression extends Node -{ - private $_expression; - private $_fieldIdentificationVariable; - - public function __construct($expression) - { - $this->_expression = $expression; - } - - public function getExpression() - { - return $this->_expression; - } - - public function getFieldIdentificationVariable() - { - return $this->_fieldIdentificationVariable; - } - - public function setFieldIdentificationVariable($fieldAlias) - { - $this->_fieldIdentificationVariable = $fieldAlias; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkSimpleSelectExpression($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SimpleSelectExpression ::= StateFieldPathExpression | IdentificationVariable + * | (AggregateExpression [["AS"] FieldAliasIdentificationVariable]) + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +class SimpleSelectExpression extends Node +{ + private $_expression; + private $_fieldIdentificationVariable; + + public function __construct($expression) + { + $this->_expression = $expression; + } + + public function getExpression() + { + return $this->_expression; + } + + public function getFieldIdentificationVariable() + { + return $this->_fieldIdentificationVariable; + } + + public function setFieldIdentificationVariable($fieldAlias) + { + $this->_fieldIdentificationVariable = $fieldAlias; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSimpleSelectExpression($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/SimpleStateFieldPathExpression.php b/lib/Doctrine/ORM/Query/AST/SimpleStateFieldPathExpression.php index f8a0628bb..b962af9da 100644 --- a/lib/Doctrine/ORM/Query/AST/SimpleStateFieldPathExpression.php +++ b/lib/Doctrine/ORM/Query/AST/SimpleStateFieldPathExpression.php @@ -1,59 +1,59 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * SimpleStateFieldPathExpression ::= IdentificationVariable "." SimpleStateField - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -class SimpleStateFieldPathExpression extends Node -{ - private $_identificationVariable = null; - private $_simpleStateField = null; - - public function __construct($identificationVariable, $simpleStateField) - { - $this->_identificationVariable = $identificationVariable; - $this->_simpleStateField = $simpleStateField; - } - - /* Getters */ - public function getIdentificationVariable() - { - return $this->_identificationVariable; - } - - public function getSimpleStateField() - { - return $this->_simpleStateField; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkSimpleStateFieldPathExpression($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SimpleStateFieldPathExpression ::= IdentificationVariable "." SimpleStateField + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +class SimpleStateFieldPathExpression extends Node +{ + private $_identificationVariable = null; + private $_simpleStateField = null; + + public function __construct($identificationVariable, $simpleStateField) + { + $this->_identificationVariable = $identificationVariable; + $this->_simpleStateField = $simpleStateField; + } + + /* Getters */ + public function getIdentificationVariable() + { + return $this->_identificationVariable; + } + + public function getSimpleStateField() + { + return $this->_simpleStateField; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSimpleStateFieldPathExpression($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/Subselect.php b/lib/Doctrine/ORM/Query/AST/Subselect.php index 5be8c03ce..05b635b7d 100644 --- a/lib/Doctrine/ORM/Query/AST/Subselect.php +++ b/lib/Doctrine/ORM/Query/AST/Subselect.php @@ -1,103 +1,103 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -class Subselect extends Node -{ - private $_simpleSelectClause; - private $_subselectFromClause; - private $_whereClause; - private $_groupByClause; - private $_havingClause; - private $_orderByClause; - - public function __construct($simpleSelectClause, $subselectFromClause) - { - $this->_simpleSelectClause = $simpleSelectClause; - $this->_subselectFromClause = $subselectFromClause; - } - - /* Getters */ - public function getSimpleSelectClause() - { - return $this->_simpleSelectClause; - } - - public function getSubselectFromClause() - { - return $this->_subselectFromClause; - } - - public function getWhereClause() - { - return $this->_whereClause; - } - - public function setWhereClause($whereClause) - { - $this->_whereClause = $whereClause; - } - - public function getGroupByClause() - { - return $this->_groupByClause; - } - - public function setGroupByClause($groupByClause) - { - $this->_groupByClause = $groupByClause; - } - - public function getHavingClause() - { - return $this->_havingClause; - } - - public function setHavingClause($havingClause) - { - $this->_havingClause = $havingClause; - } - - public function getOrderByClause() - { - return $this->_orderByClause; - } - - public function setOrderByClause($orderByClause) - { - $this->_orderByClause = $orderByClause; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkSubselect($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +class Subselect extends Node +{ + private $_simpleSelectClause; + private $_subselectFromClause; + private $_whereClause; + private $_groupByClause; + private $_havingClause; + private $_orderByClause; + + public function __construct($simpleSelectClause, $subselectFromClause) + { + $this->_simpleSelectClause = $simpleSelectClause; + $this->_subselectFromClause = $subselectFromClause; + } + + /* Getters */ + public function getSimpleSelectClause() + { + return $this->_simpleSelectClause; + } + + public function getSubselectFromClause() + { + return $this->_subselectFromClause; + } + + public function getWhereClause() + { + return $this->_whereClause; + } + + public function setWhereClause($whereClause) + { + $this->_whereClause = $whereClause; + } + + public function getGroupByClause() + { + return $this->_groupByClause; + } + + public function setGroupByClause($groupByClause) + { + $this->_groupByClause = $groupByClause; + } + + public function getHavingClause() + { + return $this->_havingClause; + } + + public function setHavingClause($havingClause) + { + $this->_havingClause = $havingClause; + } + + public function getOrderByClause() + { + return $this->_orderByClause; + } + + public function setOrderByClause($orderByClause) + { + $this->_orderByClause = $orderByClause; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSubselect($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/SubselectFromClause.php b/lib/Doctrine/ORM/Query/AST/SubselectFromClause.php index c7b055978..07d0d7745 100644 --- a/lib/Doctrine/ORM/Query/AST/SubselectFromClause.php +++ b/lib/Doctrine/ORM/Query/AST/SubselectFromClause.php @@ -1,52 +1,52 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}* - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -class SubselectFromClause extends Node -{ - private $_identificationVariableDeclarations = array(); - - public function __construct(array $identificationVariableDeclarations) - { - $this->_identificationVariableDeclarations = $identificationVariableDeclarations; - } - - /* Getters */ - public function getSubselectIdentificationVariableDeclarations() - { - return $this->_identificationVariableDeclarations; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkSubselectFromClause($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}* + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +class SubselectFromClause extends Node +{ + private $_identificationVariableDeclarations = array(); + + public function __construct(array $identificationVariableDeclarations) + { + $this->_identificationVariableDeclarations = $identificationVariableDeclarations; + } + + /* Getters */ + public function getSubselectIdentificationVariableDeclarations() + { + return $this->_identificationVariableDeclarations; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkSubselectFromClause($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/AST/UpdateStatement.php b/lib/Doctrine/ORM/Query/AST/UpdateStatement.php index 3f1399db2..32b8871b6 100644 --- a/lib/Doctrine/ORM/Query/AST/UpdateStatement.php +++ b/lib/Doctrine/ORM/Query/AST/UpdateStatement.php @@ -1,62 +1,62 @@ -. - */ - -namespace Doctrine\ORM\Query\AST; - -/** - * UpdateStatement = UpdateClause [WhereClause] - * - * @author Guilherme Blanco - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -class UpdateStatement extends Node -{ - private $_updateClause; - private $_whereClause; - - public function __construct($updateClause) - { - $this->_updateClause = $updateClause; - } - - public function setWhereClause($whereClause) - { - $this->_whereClause = $whereClause; - } - - public function getUpdateClause() - { - return $this->_updateClause; - } - - public function getWhereClause() - { - return $this->_whereClause; - } - - public function dispatch($sqlWalker) - { - return $sqlWalker->walkUpdateStatement($this); - } +. + */ + +namespace Doctrine\ORM\Query\AST; + +/** + * UpdateStatement = UpdateClause [WhereClause] + * + * @author Guilherme Blanco + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +class UpdateStatement extends Node +{ + private $_updateClause; + private $_whereClause; + + public function __construct($updateClause) + { + $this->_updateClause = $updateClause; + } + + public function setWhereClause($whereClause) + { + $this->_whereClause = $whereClause; + } + + public function getUpdateClause() + { + return $this->_updateClause; + } + + public function getWhereClause() + { + return $this->_whereClause; + } + + public function dispatch($sqlWalker) + { + return $sqlWalker->walkUpdateStatement($this); + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/CacheHandler.php b/lib/Doctrine/ORM/Query/CacheHandler.php index 7333c8cae..46eb93cde 100644 --- a/lib/Doctrine/ORM/Query/CacheHandler.php +++ b/lib/Doctrine/ORM/Query/CacheHandler.php @@ -1,146 +1,146 @@ -. - */ - -namespace Doctrine\ORM\Query; - -/** - * Doctrine\ORM\Query\CacheHandler - * - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link www.doctrine-project.com - * @since 2.0 - * @version $Revision: 1393 $ - * @author Guilherme Blanco - * @author Konsta Vesterinen - * - * @todo Re-document this class - */ -abstract class CacheHandler -{ - /** - * Static factory method. Receives a Doctrine_ORM_Query object and generates - * the object after processing queryComponents. Table aliases are retrieved - * directly from Doctrine_ORM_Query_Parser. - * - * @param mixed $result Data to be stored. - * @param Doctrine_ORM_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 QueryResult( - $result, - $queryComponents, - $parserResult->getTableAliasMap(), - $parserResult->getEnumParams() - ); - } - - /** - * Static factory method. Receives a Doctrine_ORM_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_ORM_Query $query Doctrine_ORM_Query_Object related to this cache item. - * @param mixed $cached Cached data. - */ - public static function fromCachedResult($query, $cached = false) - { - $cached = unserialize($cached); - - return new QueryResult( - $cached[0], - self::_getQueryComponents($cached[1]), - $cached[2], - $cached[3] - ); - } - - /** - * Static factory method. Receives a Doctrine_ORM_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_ORM_Query $query Doctrine_ORM_Query_Object related to this cache item. - * @param mixed $cached Cached data. - */ - public static function fromCachedQuery($query, $cached = false) - { - $cached = unserialize($cached); - - return new 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']->getAssociation($e[1]); - $queryComponents[$alias]['mapper'] = $query->getConnection()->getMapper($queryComponents[$alias]['relation']->getTargetEntityName()); - $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; - } +. + */ + +namespace Doctrine\ORM\Query; + +/** + * Doctrine\ORM\Query\CacheHandler + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 2.0 + * @version $Revision: 1393 $ + * @author Guilherme Blanco + * @author Konsta Vesterinen + * + * @todo Re-document this class + */ +abstract class CacheHandler +{ + /** + * Static factory method. Receives a Doctrine_ORM_Query object and generates + * the object after processing queryComponents. Table aliases are retrieved + * directly from Doctrine_ORM_Query_Parser. + * + * @param mixed $result Data to be stored. + * @param Doctrine_ORM_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 QueryResult( + $result, + $queryComponents, + $parserResult->getTableAliasMap(), + $parserResult->getEnumParams() + ); + } + + /** + * Static factory method. Receives a Doctrine_ORM_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_ORM_Query $query Doctrine_ORM_Query_Object related to this cache item. + * @param mixed $cached Cached data. + */ + public static function fromCachedResult($query, $cached = false) + { + $cached = unserialize($cached); + + return new QueryResult( + $cached[0], + self::_getQueryComponents($cached[1]), + $cached[2], + $cached[3] + ); + } + + /** + * Static factory method. Receives a Doctrine_ORM_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_ORM_Query $query Doctrine_ORM_Query_Object related to this cache item. + * @param mixed $cached Cached data. + */ + public static function fromCachedQuery($query, $cached = false) + { + $cached = unserialize($cached); + + return new 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']->getAssociation($e[1]); + $queryComponents[$alias]['mapper'] = $query->getConnection()->getMapper($queryComponents[$alias]['relation']->getTargetEntityName()); + $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; + } } \ No newline at end of file diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php index b2d8acef8..66a3d3f4e 100644 --- a/lib/Doctrine/ORM/Query/Parser.php +++ b/lib/Doctrine/ORM/Query/Parser.php @@ -1,1891 +1,1891 @@ -. - */ - -namespace Doctrine\ORM\Query; - -use Doctrine\Common\DoctrineException; -use Doctrine\ORM\Query; -use Doctrine\ORM\Query\AST; -use Doctrine\ORM\Query\Exec; - -/** - * An LL(*) parser for the context-free grammar of the Doctrine Query Language. - * Parses a DQL query, reports any errors in it, and generates an AST. - * - * @author Guilherme Blanco - * @author Janne Vanhala - * @author Roman Borschel - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.doctrine-project.org - * @since 2.0 - * @version $Revision$ - */ -class Parser -{ - /** Maps registered string function names to class names. */ - private static $_STRING_FUNCTIONS = array( - 'concat' => 'Doctrine\ORM\Query\AST\Functions\ConcatFunction', - 'substring' => 'Doctrine\ORM\Query\AST\Functions\SubstringFunction', - 'trim' => 'Doctrine\ORM\Query\AST\Functions\TrimFunction', - 'lower' => 'Doctrine\ORM\Query\AST\Functions\LowerFunction', - 'upper' => 'Doctrine\ORM\Query\AST\Functions\UpperFunction' - ); - - /** Maps registered numeric function names to class names. */ - private static $_NUMERIC_FUNCTIONS = array( - 'length' => 'Doctrine\ORM\Query\AST\Functions\LengthFunction', - 'locate' => 'Doctrine\ORM\Query\AST\Functions\LocateFunction', - 'abs' => 'Doctrine\ORM\Query\AST\Functions\AbsFunction', - 'sqrt' => 'Doctrine\ORM\Query\AST\Functions\SqrtFunction', - 'mod' => 'Doctrine\ORM\Query\AST\Functions\ModFunction', - 'size' => 'Doctrine\ORM\Query\AST\Functions\SizeFunction' - ); - - /** Maps registered datetime function names to class names. */ - private static $_DATETIME_FUNCTIONS = array( - 'current_date' => 'Doctrine\ORM\Query\AST\Functions\CurrentDateFunction', - 'current_time' => 'Doctrine\ORM\Query\AST\Functions\CurrentTimeFunction', - 'current_timestamp' => 'Doctrine\ORM\Query\AST\Functions\CurrentTimestampFunction' - ); - - /** - * The minimum number of tokens read after last detected error before - * another error can be reported. - * - * @var int - */ - //const MIN_ERROR_DISTANCE = 2; - - /** - * Path expressions that were encountered during parsing of SelectExpressions - * and still need to be validated. - * - * @var array - */ - private $_deferredPathExpressionStacks = array(); - - /** - * A scanner object. - * - * @var Doctrine\ORM\Query\Lexer - */ - private $_lexer; - - /** - * The Parser Result object. - * - * @var Doctrine\ORM\Query\ParserResult - */ - private $_parserResult; - - /** - * The EntityManager. - * - * @var EnityManager - */ - private $_em; - - /** - * The Query to parse. - * - * @var Query - */ - private $_query; - - /** - * Map of declared classes in the parsed query. - * Maps the declared DQL alias (key) to the class name (value). - * - * @var array - */ - private $_queryComponents = array(); - - /** - * Creates a new query parser object. - * - * @param Query $query The Query to parse. - */ - public function __construct(Query $query) - { - $this->_query = $query; - $this->_em = $query->getEntityManager(); - $this->_lexer = new Lexer($query->getDql()); - $this->_parserResult = new ParserResult; - //$this->_parserResult->setEntityManager($this->_em); - } - - /** - * 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->_lexer->lookahead['value'] === $token); - } else { - $isMatch = ($this->_lexer->lookahead['type'] === $token); - } - - if ( ! $isMatch) { - $this->syntaxError($this->_lexer->getLiteral($token)); - } - - $this->_lexer->moveNext(); - } - - /** - * Free this parser enabling it to be reused - * - * @param boolean $deep Whether to clean peek and reset errors - * @param integer $position Position to reset - */ - public function free($deep = false, $position = 0) - { - // WARNING! Use this method with care. It resets the scanner! - $this->_lexer->resetPosition($position); - - // Deep = true cleans peek and also any previously defined errors - if ($deep) { - $this->_lexer->resetPeek(); - //$this->_errors = array(); - } - - $this->_lexer->token = null; - $this->_lexer->lookahead = null; - //$this->_errorDistance = self::MIN_ERROR_DISTANCE; - } - - /** - * Parses a query string. - * - * @return ParserResult - */ - public function parse() - { - // Parse & build AST - $AST = $this->_QueryLanguage(); - - // Check for end of string - if ($this->_lexer->lookahead !== null) { - //var_dump($this->_lexer->lookahead); - $this->syntaxError('end of string'); - } - - // Create SqlWalker who creates the SQL from the AST - $sqlWalker = new SqlWalker($this->_query, $this->_parserResult, $this->_queryComponents); - - // Assign an SQL executor to the parser result - $this->_parserResult->setSqlExecutor(Exec\AbstractExecutor::create($AST, $sqlWalker)); - - return $this->_parserResult; - } - - /** - * Gets the lexer used by the parser. - * - * @return Doctrine\ORM\Query\Lexer - */ - public function getLexer() - { - return $this->_lexer; - } - - /** - * Gets the ParserResult that is being filled with information during parsing. - * - * @return Doctrine\ORM\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->_lexer->lookahead; - } - - $message = 'line 0, col ' . (isset($token['position']) ? $token['position'] : '-1') . ': Error: '; - - if ($expected !== '') { - $message .= "Expected '$expected', got "; - } else { - $message .= 'Unexpected '; - } - - if ($this->_lexer->lookahead === null) { - $message .= 'end of string.'; - } else { - $message .= "'{$this->_lexer->lookahead['value']}'"; - } - - throw DoctrineException::updateMe($message); - } - - /** - * Generates a new semantical error. - * - * @param string $message Optional message. - * @param array $token Optional token. - */ - public function semanticalError($message = '', $token = null) - { - if ($token === null) { - $token = $this->_lexer->token; - } - //TODO: Include $token in $message - throw DoctrineException::updateMe($message); - } - - /** - * Logs new error entry. - * - * @param string $message Message to log. - * @param array $token Token that it was processing. - */ - /*protected function _logError($message = '', $token) - { - if ($this->_errorDistance >= self::MIN_ERROR_DISTANCE) { - $message = 'line 0, col ' . $token['position'] . ': ' . $message; - $this->_errors[] = $message; - } - - $this->_errorDistance = 0; - }*/ - - /** - * Gets the EntityManager used by the parser. - * - * @return EntityManager - */ - public function getEntityManager() - { - return $this->_em; - } - - /** - * Checks if the next-next (after lookahead) token starts a function. - * - * @return boolean - */ - private function _isFunction() - { - $next = $this->_lexer->glimpse(); - return $next['value'] === '('; - } - - /** - * Checks whether the next 2 tokens start a subselect. - * - * @return boolean TRUE if the next 2 tokens start a subselect, FALSE otherwise. - */ - private function _isSubselect() - { - $la = $this->_lexer->lookahead; - $next = $this->_lexer->glimpse(); - return ($la['value'] === '(' && $next['type'] === Lexer::T_SELECT); - } - - /** - * QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement - */ - public function _QueryLanguage() - { - $this->_lexer->moveNext(); - switch ($this->_lexer->lookahead['type']) { - case Lexer::T_SELECT: - return $this->_SelectStatement(); - case Lexer::T_UPDATE: - return $this->_UpdateStatement(); - case Lexer::T_DELETE: - return $this->_DeleteStatement(); - default: - $this->syntaxError('SELECT, UPDATE or DELETE'); - break; - } - } - - /** - * SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] - */ - public function _SelectStatement() - { - $this->_beginDeferredPathExpressionStack(); - $selectClause = $this->_SelectClause(); - $fromClause = $this->_FromClause(); - $this->_processDeferredPathExpressionStack(); - - $whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) ? - $this->_WhereClause() : null; - - $groupByClause = $this->_lexer->isNextToken(Lexer::T_GROUP) ? - $this->_GroupByClause() : null; - - $havingClause = $this->_lexer->isNextToken(Lexer::T_HAVING) ? - $this->_HavingClause() : null; - - $orderByClause = $this->_lexer->isNextToken(Lexer::T_ORDER) ? - $this->_OrderByClause() : null; - - return new AST\SelectStatement( - $selectClause, $fromClause, $whereClause, $groupByClause, $havingClause, $orderByClause - ); - } - - /** - * Begins a new stack of deferred path expressions. - */ - private function _beginDeferredPathExpressionStack() - { - $this->_deferredPathExpressionStacks[] = array(); - } - - /** - * Processes the topmost stack of deferred path expressions. - * These will be validated to make sure they are indeed - * valid StateFieldPathExpressions and additional information - * is attached to their AST nodes. - */ - private function _processDeferredPathExpressionStack() - { - $exprStack = array_pop($this->_deferredPathExpressionStacks); - $qComps = $this->_queryComponents; - foreach ($exprStack as $expr) { - $parts = $expr->getParts(); - $numParts = count($parts); - $dqlAlias = $parts[0]; - if (count($parts) == 2) { - $expr->setIsSimpleStateFieldPathExpression(true); - if ( ! $qComps[$dqlAlias]['metadata']->hasField($parts[1])) { - $this->semanticalError('The class ' . $qComps[$dqlAlias]['metadata']->name - . ' has no simple state field named ' . $parts[1]); - } - } else { - $embeddedClassFieldSeen = false; - $assocSeen = false; - for ($i = 1; $i < $numParts - 1; ++$i) { - if ($qComps[$dqlAlias]['metadata']->hasAssociation($parts[$i])) { - if ($embeddedClassFieldSeen) { - $this->semanticalError('Invalid navigation path.'); - } - // Indirect join - $assoc = $qComps[$dqlAlias]['metadata']->getAssociationMapping($parts[$i]); - if ( ! $assoc->isOneToOne()) { - $this->semanticalError('Single-valued association expected.'); - } - $expr->setIsSingleValuedAssociationPart($parts[$i]); - //TODO... - $assocSeen = true; - } else if ($qComps[$dqlAlias]['metadata']->hasEmbeddedClassField($parts[$i])) { - //TODO... - $expr->setIsEmbeddedClassPart($parts[$i]); - $this->syntaxError(); - } else { - $this->syntaxError(); - } - } - if ( ! $assocSeen) { - $expr->setIsSimpleStateFieldPathExpression(true); - } else { - $expr->setIsSimpleStateFieldAssociationPathExpression(true); - } - // Last part MUST be a simple state field - if ( ! $qComps[$dqlAlias]['metadata']->hasField($parts[$numParts-1])) { - $this->semanticalError('The class ' . $qComps[$dqlAlias]['metadata']->name - . ' has no simple state field named ' . $parts[$numParts-1]); - } - } - } - } - - /** - * UpdateStatement ::= UpdateClause [WhereClause] - */ - public function _UpdateStatement() - { - $updateStatement = new AST\UpdateStatement($this->_UpdateClause()); - $updateStatement->setWhereClause( - $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->_WhereClause() : null - ); - return $updateStatement; - } - - /** - * UpdateClause ::= "UPDATE" AbstractSchemaName [["AS"] AliasIdentificationVariable] "SET" UpdateItem {"," UpdateItem}* - */ - public function _UpdateClause() - { - $this->match(Lexer::T_UPDATE); - $abstractSchemaName = $this->_AbstractSchemaName(); - $aliasIdentificationVariable = null; - if ($this->_lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); - } - if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { - $this->match(Lexer::T_IDENTIFIER); - $aliasIdentificationVariable = $this->_lexer->token['value']; - } else { - $aliasIdentificationVariable = $abstractSchemaName; - } - $this->match(Lexer::T_SET); - $updateItems = array(); - $updateItems[] = $this->_UpdateItem(); - while ($this->_lexer->isNextToken(',')) { - $this->match(','); - $updateItems[] = $this->_UpdateItem(); - } - - $classMetadata = $this->_em->getClassMetadata($abstractSchemaName); - // Building queryComponent - $queryComponent = array( - 'metadata' => $classMetadata, - 'parent' => null, - 'relation' => null, - 'map' => null - ); - $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; - - $updateClause = new AST\UpdateClause($abstractSchemaName, $updateItems); - $updateClause->setAliasIdentificationVariable($aliasIdentificationVariable); - - return $updateClause; - } - - /** - * UpdateItem ::= [IdentificationVariable "."] {StateField | SingleValuedAssociationField} "=" NewValue - */ - public function _UpdateItem() - { - $peek = $this->_lexer->glimpse(); - $identVariable = null; - if ($peek['value'] == '.') { - $this->match(Lexer::T_IDENTIFIER); - $identVariable = $this->_lexer->token['value']; - $this->match('.'); - } else { - throw QueryException::missingAliasQualifier(); - } - $this->match(Lexer::T_IDENTIFIER); - $field = $this->_lexer->token['value']; - $this->match('='); - $newValue = $this->_NewValue(); - - $updateItem = new AST\UpdateItem($field, $newValue); - $updateItem->setIdentificationVariable($identVariable); - - return $updateItem; - } - - /** - * NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary | - * EnumPrimary | SimpleEntityExpression | "NULL" - * @todo Implementation still incomplete. - */ - public function _NewValue() - { - if ($this->_lexer->isNextToken(Lexer::T_NULL)) { - $this->match(Lexer::T_NULL); - return null; - } else if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { - $this->match(Lexer::T_INPUT_PARAMETER); - return new AST\InputParameter($this->_lexer->token['value']); - } else if ($this->_lexer->isNextToken(Lexer::T_STRING)) { - //TODO: Can be StringPrimary or EnumPrimary - return $this->_StringPrimary(); - } else { - $this->syntaxError('Not yet implemented-1.'); - } - } - - /** - * DeleteStatement ::= DeleteClause [WhereClause] - */ - public function _DeleteStatement() - { - $deleteStatement = new AST\DeleteStatement($this->_DeleteClause()); - $deleteStatement->setWhereClause( - $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->_WhereClause() : null - ); - return $deleteStatement; - } - - /** - * DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName [["AS"] AliasIdentificationVariable] - */ - public function _DeleteClause() - { - $this->match(Lexer::T_DELETE); - if ($this->_lexer->isNextToken(Lexer::T_FROM)) { - $this->match(Lexer::T_FROM); - } - $deleteClause = new AST\DeleteClause($this->_AbstractSchemaName()); - if ($this->_lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); - } - if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { - $this->match(Lexer::T_IDENTIFIER); - $deleteClause->setAliasIdentificationVariable($this->_lexer->token['value']); - } else { - $deleteClause->setAliasIdentificationVariable($deleteClause->getAbstractSchemaName()); - } - - $classMetadata = $this->_em->getClassMetadata($deleteClause->getAbstractSchemaName()); - $queryComponent = array( - 'metadata' => $classMetadata - ); - $this->_queryComponents[$deleteClause->getAliasIdentificationVariable()] = $queryComponent; - - return $deleteClause; - } - - /** - * SelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression} - */ - public function _SelectClause() - { - $isDistinct = false; - $this->match(Lexer::T_SELECT); - - // Check for DISTINCT - if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) { - $this->match(Lexer::T_DISTINCT); - $isDistinct = true; - } - - // Process SelectExpressions (1..N) - $selectExpressions = array(); - $selectExpressions[] = $this->_SelectExpression(); - while ($this->_lexer->isNextToken(',')) { - $this->match(','); - $selectExpressions[] = $this->_SelectExpression(); - } - - return new AST\SelectClause($selectExpressions, $isDistinct); - } - - /** - * FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}* - */ - public function _FromClause() - { - $this->match(Lexer::T_FROM); - $identificationVariableDeclarations = array(); - $identificationVariableDeclarations[] = $this->_IdentificationVariableDeclaration(); - - while ($this->_lexer->isNextToken(',')) { - $this->match(','); - $identificationVariableDeclarations[] = $this->_IdentificationVariableDeclaration(); - } - - return new AST\FromClause($identificationVariableDeclarations); - } - - /** - * SelectExpression ::= - * IdentificationVariable | StateFieldPathExpression | - * (AggregateExpression | "(" Subselect ")") [["AS"] FieldAliasIdentificationVariable] | - * Function - */ - public function _SelectExpression() - { - $expression = null; - $fieldIdentificationVariable = null; - $peek = $this->_lexer->glimpse(); - // First we recognize for an IdentificationVariable (DQL class alias) - if ($peek['value'] != '.' && $peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) { - $expression = $this->_IdentificationVariable(); - } else if (($isFunction = $this->_isFunction()) !== false || $this->_isSubselect()) { - if ($isFunction) { - if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { - $expression = $this->_AggregateExpression(); - } else { - $expression = $this->_Function(); - } - } else { - $this->match('('); - $expression = $this->_Subselect(); - $this->match(')'); - } - if ($this->_lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); - } - if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { - $this->match(Lexer::T_IDENTIFIER); - $fieldIdentificationVariable = $this->_lexer->token['value']; - } - } else { - //TODO: If hydration mode is OBJECT throw an exception ("partial object dangerous...") - // unless the doctrine.forcePartialLoad query hint is set - $expression = $this->_StateFieldPathExpression(); - } - return new AST\SelectExpression($expression, $fieldIdentificationVariable); - } - - /** - * IdentificationVariable ::= identifier - */ - public function _IdentificationVariable() - { - $this->match(Lexer::T_IDENTIFIER); - return $this->_lexer->token['value']; - } - - /** - * IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}* - */ - public function _IdentificationVariableDeclaration() - { - $rangeVariableDeclaration = $this->_RangeVariableDeclaration(); - $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->_IndexBy() : null; - $joinVariableDeclarations = array(); - while ( - $this->_lexer->isNextToken(Lexer::T_LEFT) || - $this->_lexer->isNextToken(Lexer::T_INNER) || - $this->_lexer->isNextToken(Lexer::T_JOIN) - ) { - $joinVariableDeclarations[] = $this->_JoinVariableDeclaration(); - } - - return new AST\IdentificationVariableDeclaration( - $rangeVariableDeclaration, $indexBy, $joinVariableDeclarations - ); - } - - /** - * RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable - */ - public function _RangeVariableDeclaration() - { - $abstractSchemaName = $this->_AbstractSchemaName(); - - if ($this->_lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); - } - $aliasIdentificationVariable = $this->_AliasIdentificationVariable(); - $classMetadata = $this->_em->getClassMetadata($abstractSchemaName); - - // Building queryComponent - $queryComponent = array( - 'metadata' => $classMetadata, - 'parent' => null, - 'relation' => null, - 'map' => null - ); - $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; - - return new AST\RangeVariableDeclaration( - $classMetadata, $aliasIdentificationVariable - ); - } - - /** - * AbstractSchemaName ::= identifier - */ - public function _AbstractSchemaName() - { - $this->match(Lexer::T_IDENTIFIER); - return $this->_lexer->token['value']; - } - - /** - * AliasIdentificationVariable = identifier - */ - public function _AliasIdentificationVariable() - { - $this->match(Lexer::T_IDENTIFIER); - return $this->_lexer->token['value']; - } - - /** - * JoinVariableDeclaration ::= Join [IndexBy] - */ - public function _JoinVariableDeclaration() - { - $join = $this->_Join(); - $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? - $this->_IndexBy() : null; - return new AST\JoinVariableDeclaration($join, $indexBy); - } - - /** - * Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression - * ["AS"] AliasIdentificationVariable [("ON" | "WITH") ConditionalExpression] - */ - public function _Join() - { - // Check Join type - $joinType = AST\Join::JOIN_TYPE_INNER; - if ($this->_lexer->isNextToken(Lexer::T_LEFT)) { - $this->match(Lexer::T_LEFT); - // Possible LEFT OUTER join - if ($this->_lexer->isNextToken(Lexer::T_OUTER)) { - $this->match(Lexer::T_OUTER); - $joinType = AST\Join::JOIN_TYPE_LEFTOUTER; - } else { - $joinType = AST\Join::JOIN_TYPE_LEFT; - } - } else if ($this->_lexer->isNextToken(Lexer::T_INNER)) { - $this->match(Lexer::T_INNER); - } - - $this->match(Lexer::T_JOIN); - - $joinPathExpression = $this->_JoinPathExpression(); - if ($this->_lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); - } - - $aliasIdentificationVariable = $this->_AliasIdentificationVariable(); - - // Verify that the association exists. - $parentClass = $this->_queryComponents[$joinPathExpression->getIdentificationVariable()]['metadata']; - $assocField = $joinPathExpression->getAssociationField(); - if ( ! $parentClass->hasAssociation($assocField)) { - $this->semanticalError("Class " . $parentClass->name . - " has no association named '$assocField'."); - } - $targetClassName = $parentClass->getAssociationMapping($assocField)->getTargetEntityName(); - - // Building queryComponent - $joinQueryComponent = array( - 'metadata' => $this->_em->getClassMetadata($targetClassName), - 'parent' => $joinPathExpression->getIdentificationVariable(), - 'relation' => $parentClass->getAssociationMapping($assocField), - 'map' => null - ); - $this->_queryComponents[$aliasIdentificationVariable] = $joinQueryComponent; - - // Create AST node - $join = new AST\Join($joinType, $joinPathExpression, $aliasIdentificationVariable); - - // Check for ad-hoc Join conditions - if ($this->_lexer->isNextToken(Lexer::T_ON) || $this->_lexer->isNextToken(Lexer::T_WITH)) { - if ($this->_lexer->isNextToken(Lexer::T_ON)) { - $this->match(Lexer::T_ON); - $join->setWhereType(AST\Join::JOIN_WHERE_ON); - } else { - $this->match(Lexer::T_WITH); - } - $join->setConditionalExpression($this->_ConditionalExpression()); - } - - return $join; - } - - /** - * JoinPathExpression ::= IdentificationVariable "." (CollectionValuedAssociationField | SingleValuedAssociationField) - */ - public function _JoinPathExpression() - { - $identificationVariable = $this->_IdentificationVariable(); - $this->match('.'); - $this->match(Lexer::T_IDENTIFIER); - return new AST\JoinPathExpression( - $identificationVariable, $this->_lexer->token['value'] - ); - } - - /** - * IndexBy ::= "INDEX" "BY" SimpleStateFieldPathExpression - */ - public function _IndexBy() - { - $this->match(Lexer::T_INDEX); - $this->match(Lexer::T_BY); - $pathExp = $this->_SimpleStateFieldPathExpression(); - // Add the INDEX BY info to the query component - $this->_queryComponents[$pathExp->getIdentificationVariable()]['map'] = $pathExp->getSimpleStateField(); - return $pathExp; - } - - /** - * SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField - * @todo Implementation incomplete. Recognize StateField properly (see EBNF). - */ - public function _SimpleStateFieldPathExpression() - { - $identificationVariable = $this->_IdentificationVariable(); - $this->match('.'); - $this->match(Lexer::T_IDENTIFIER); - $simpleStateField = $this->_lexer->token['value']; - return new AST\SimpleStateFieldPathExpression($identificationVariable, $simpleStateField); - } - - /** - * StateFieldPathExpression ::= SimpleStateFieldPathExpression | SimpleStateFieldAssociationPathExpression - */ - public function _StateFieldPathExpression() - { - if ( ! empty($this->_deferredPathExpressionStacks)) { - $exprStack = array_pop($this->_deferredPathExpressionStacks); - $this->match(Lexer::T_IDENTIFIER); - $parts = array($this->_lexer->token['value']); - while ($this->_lexer->isNextToken('.')) { - $this->match('.'); - $this->match(Lexer::T_IDENTIFIER); - $parts[] = $this->_lexer->token['value']; - } - $expr = new AST\StateFieldPathExpression($parts); - $exprStack[] = $expr; - array_push($this->_deferredPathExpressionStacks, $exprStack); - return $expr; // EARLY EXIT! - } - - $parts = array(); - $stateFieldSeen = false; - $assocSeen = false; - - $identificationVariable = $this->_IdentificationVariable(); - if ( ! isset($this->_queryComponents[$identificationVariable])) { - $this->syntaxError("IdentificationVariable '$identificationVariable' was not declared."); - } - - $qComp = $this->_queryComponents[$identificationVariable]; - $parts[] = $identificationVariable; - - $class = $qComp['metadata']; - - if ( ! $this->_lexer->isNextToken('.')) { - if ($class->isIdentifierComposite) { - $this->syntaxError(); - } - $parts[] = $class->identifier[0]; - } - - while ($this->_lexer->isNextToken('.')) { - if ($stateFieldSeen) { - $this->syntaxError(); - } - $this->match('.'); - $part = $this->_IdentificationVariable(); - if ($class->hasField($part)) { - $stateFieldSeen = true; - } else if ($class->hasAssociation($part)) { - $assoc = $class->getAssociationMapping($part); - $class = $this->_em->getClassMetadata($assoc->getTargetEntityName()); - $assocSeen = true; - } else { - $this->semanticalError('The class ' . $class->name . - ' has no field or association named ' . $part); - } - $parts[] = $part; - } - - $pathExpr = new AST\StateFieldPathExpression($parts); - - if ($assocSeen) { - $pathExpr->setIsSimpleStateFieldAssociationPathExpression(true); - } else { - $pathExpr->setIsSimpleStateFieldPathExpression(true); - } - - return $pathExpr; - } - - /** - * NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL" - * @todo Implementation incomplete for SingleValuedPathExpression. - */ - public function _NullComparisonExpression() - { - if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { - $this->match(Lexer::T_INPUT_PARAMETER); - $expr = new AST\InputParameter($this->_lexer->token['value']); - } else { - //TODO: Support SingleValuedAssociationPathExpression - $expr = $this->_StateFieldPathExpression(); - } - $nullCompExpr = new AST\NullComparisonExpression($expr); - $this->match(Lexer::T_IS); - if ($this->_lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); - $nullCompExpr->setNot(true); - } - $this->match(Lexer::T_NULL); - - return $nullCompExpr; - } - - /** - * AggregateExpression ::= - * ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" | - * "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedAssociationPathExpression | StateFieldPathExpression) ")" - * @todo Implementation incomplete. Support for SingleValuedAssociationPathExpression. - */ - public function _AggregateExpression() - { - $isDistinct = false; - $functionName = ''; - if ($this->_lexer->isNextToken(Lexer::T_COUNT)) { - $this->match(Lexer::T_COUNT); - $functionName = $this->_lexer->token['value']; - $this->match('('); - if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) { - $this->match(Lexer::T_DISTINCT); - $isDistinct = true; - } - // For now we only support a PathExpression here... - $pathExp = $this->_StateFieldPathExpression(); - $this->match(')'); - } else { - if ($this->_lexer->isNextToken(Lexer::T_AVG)) { - $this->match(Lexer::T_AVG); - } else if ($this->_lexer->isNextToken(Lexer::T_MAX)) { - $this->match(Lexer::T_MAX); - } else if ($this->_lexer->isNextToken(Lexer::T_MIN)) { - $this->match(Lexer::T_MIN); - } else if ($this->_lexer->isNextToken(Lexer::T_SUM)) { - $this->match(Lexer::T_SUM); - } else { - $this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT'); - } - $functionName = $this->_lexer->token['value']; - $this->match('('); - $pathExp = $this->_StateFieldPathExpression(); - $this->match(')'); - } - - return new AST\AggregateExpression($functionName, $pathExp, $isDistinct); - } - - /** - * GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}* - * GroupByItem ::= IdentificationVariable | SingleValuedPathExpression - * @todo Implementation incomplete for GroupByItem. - */ - public function _GroupByClause() - { - $this->match(Lexer::T_GROUP); - $this->match(Lexer::T_BY); - $groupByItems = array(); - $groupByItems[] = $this->_StateFieldPathExpression(); - while ($this->_lexer->isNextToken(',')) { - $this->match(','); - $groupByItems[] = $this->_StateFieldPathExpression(); - } - return new AST\GroupByClause($groupByItems); - } - - /** - * HavingClause ::= "HAVING" ConditionalExpression - */ - public function _HavingClause() - { - $this->match(Lexer::T_HAVING); - return new AST\HavingClause($this->_ConditionalExpression()); - } - - /** - * OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}* - */ - public function _OrderByClause() - { - $this->match(Lexer::T_ORDER); - $this->match(Lexer::T_BY); - $orderByItems = array(); - $orderByItems[] = $this->_OrderByItem(); - while ($this->_lexer->isNextToken(',')) { - $this->match(','); - $orderByItems[] = $this->_OrderByItem(); - } - return new AST\OrderByClause($orderByItems); - } - - /** - * OrderByItem ::= ResultVariable | StateFieldPathExpression ["ASC" | "DESC"] - * @todo Implementation incomplete for OrderByItem. - */ - public function _OrderByItem() - { - $item = new AST\OrderByItem($this->_StateFieldPathExpression()); - if ($this->_lexer->isNextToken(Lexer::T_ASC)) { - $this->match(Lexer::T_ASC); - $item->setAsc(true); - } else if ($this->_lexer->isNextToken(Lexer::T_DESC)) { - $this->match(Lexer::T_DESC); - $item->setDesc(true); - } else { - $item->setDesc(true); - } - return $item; - } - - /** - * WhereClause ::= "WHERE" ConditionalExpression - */ - public function _WhereClause() - { - $this->match(Lexer::T_WHERE); - return new AST\WhereClause($this->_ConditionalExpression()); - } - - /** - * ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}* - */ - public function _ConditionalExpression() - { - $conditionalTerms = array(); - $conditionalTerms[] = $this->_ConditionalTerm(); - while ($this->_lexer->isNextToken(Lexer::T_OR)) { - $this->match(Lexer::T_OR); - $conditionalTerms[] = $this->_ConditionalTerm(); - } - return new AST\ConditionalExpression($conditionalTerms); - } - - /** - * ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}* - */ - public function _ConditionalTerm() - { - $conditionalFactors = array(); - $conditionalFactors[] = $this->_ConditionalFactor(); - while ($this->_lexer->isNextToken(Lexer::T_AND)) { - $this->match(Lexer::T_AND); - $conditionalFactors[] = $this->_ConditionalFactor(); - } - return new AST\ConditionalTerm($conditionalFactors); - } - - /** - * ConditionalFactor ::= ["NOT"] ConditionalPrimary - */ - public function _ConditionalFactor() - { - $not = false; - if ($this->_lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); - $not = true; - } - return new AST\ConditionalFactor($this->_ConditionalPrimary(), $not); - } - - /** - * ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")" - * @todo Implementation incomplete: Recognition of SimpleConditionalExpression is incomplete. - */ - public function _ConditionalPrimary() - { - $condPrimary = new AST\ConditionalPrimary; - if ($this->_lexer->isNextToken('(')) { - // Peek beyond the matching closing paranthesis ')' - $numUnmatched = 1; - $peek = $this->_lexer->peek(); - while ($numUnmatched > 0) { - if ($peek['value'] == ')') { - --$numUnmatched; - } else if ($peek['value'] == '(') { - ++$numUnmatched; - } - $peek = $this->_lexer->peek(); - } - $this->_lexer->resetPeek(); - - //TODO: This is not complete, what about LIKE/BETWEEN/...etc? - $comparisonOps = array("=", "<", "<=", "<>", ">", ">=", "!="); - - if (in_array($peek['value'], $comparisonOps)) { - $condPrimary->setSimpleConditionalExpression($this->_SimpleConditionalExpression()); - } else { - $this->match('('); - $conditionalExpression = $this->_ConditionalExpression(); - $this->match(')'); - $condPrimary->setConditionalExpression($conditionalExpression); - } - } else { - $condPrimary->setSimpleConditionalExpression($this->_SimpleConditionalExpression()); - } - - return $condPrimary; - } - - /** - * SimpleConditionalExpression ::= - * ComparisonExpression | BetweenExpression | LikeExpression | - * InExpression | NullComparisonExpression | ExistsExpression | - * EmptyCollectionComparisonExpression | CollectionMemberExpression - * - * @todo Implementation incomplete. This is difficult and a strict recognition may - * even require backtracking. - */ - public function _SimpleConditionalExpression() - { - if ($this->_lexer->isNextToken(Lexer::T_NOT)) { - $token = $this->_lexer->glimpse(); - } else { - $token = $this->_lexer->lookahead; - } - if ($token['type'] === Lexer::T_EXISTS) { - return $this->_ExistsExpression(); - } - - $stateFieldPathExpr = false; - if ($token['type'] === Lexer::T_IDENTIFIER) { - // Peek beyond the PathExpression - $stateFieldPathExpr = true; - $peek = $this->_lexer->peek(); - while ($peek['value'] === '.') { - $this->_lexer->peek(); - $peek = $this->_lexer->peek(); - } - - // Also peek beyond a NOT if there is one - if ($peek['type'] === Lexer::T_NOT) { - $peek = $this->_lexer->peek(); - } - - $this->_lexer->resetPeek(); - $token = $peek; - } - - if ($stateFieldPathExpr) { - switch ($token['type']) { - case Lexer::T_BETWEEN: - return $this->_BetweenExpression(); - case Lexer::T_LIKE: - return $this->_LikeExpression(); - case Lexer::T_IN: - return $this->_InExpression(); - case Lexer::T_IS: - return $this->_NullComparisonExpression(); - case Lexer::T_NONE: - return $this->_ComparisonExpression(); - default: - $this->syntaxError(); - } - } else { - return $this->_ComparisonExpression(); - } - } - - /** - * ComparisonExpression ::= - * ArithmeticExpression ComparisonOperator (QuantifiedExpression | ArithmeticExpression) | - * StringExpression ComparisonOperator (StringExpression | QuantifiedExpression) | - * BooleanExpression ("=" | "<>" | "!=") (BooleanExpression | QuantifiedExpression) | - * EnumExpression ("=" | "<>" | "!=") (EnumExpression | QuantifiedExpression) | - * DatetimeExpression ComparisonOperator (DatetimeExpression | QuantifiedExpression) | - * EntityExpression ("=" | "<>") (EntityExpression | QuantifiedExpression) - * - * @todo Implementation incomplete. Seems difficult. - */ - public function _ComparisonExpression() - { - $peek = $this->_lexer->glimpse(); - - if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { - if ($this->_isComparisonOperator($peek)) { - $this->match(Lexer::T_INPUT_PARAMETER); - $leftExpr = new AST\InputParameter($this->_lexer->token['value']); - } else { - $leftExpr = $this->_ArithmeticExpression(); - } - $operator = $this->_ComparisonOperator(); - $rightExpr = $this->_ArithmeticExpression(); - //... - } - else if ($this->_lexer->isNextToken('(') && $peek['type'] == Lexer::T_SELECT) { - $leftExpr = $this->_Subselect(); - //... - } - else if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER) && $peek['value'] == '(') { - $peek2 = $this->_peekBeyond(')'); - if ($this->_isComparisonOperator($peek2)) { - if ($this->_isStringFunction($this->_lexer->lookahead['value'])) { - $leftExpr = $this->_FunctionsReturningStrings(); - $operator = $this->_ComparisonOperator(); - if ($this->_isNextAllAnySome()) { - $rightExpr = $this->_QuantifiedExpression(); - } else { - $rightExpr = $this->_StringPrimary(); - } - } else if ($this->_isNumericFunction($this->_lexer->lookahead['value'])) { - $leftExpr = $this->_FunctionsReturningNumerics(); - $operator = $this->_ComparisonOperator(); - if ($this->_isNextAllAnySome()) { - $rightExpr = $this->_QuantifiedExpression(); - } else { - $rightExpr = $this->_ArithmeticExpression(); - } - } else { - $leftExpr = $this->_FunctionsReturningDatetime(); - $operator = $this->_ComparisonOperator(); - if ($this->_isNextAllAnySome()) { - $rightExpr = $this->_QuantifiedExpression(); - } else { - $rightExpr = $this->_DatetimePrimary(); - } - } - } else { - $leftExpr = $this->_ArithmeticExpression(); - $operator = $this->_ComparisonOperator(); - if ($this->_isNextAllAnySome()) { - $rightExpr = $this->_QuantifiedExpression(); - } else { - $rightExpr = $this->_StringExpression(); - } - } - } else { - $leftExpr = $this->_ArithmeticExpression(); - $operator = $this->_ComparisonOperator(); - if ($this->_isNextAllAnySome()) { - $rightExpr = $this->_QuantifiedExpression(); - } else { - $rightExpr = $this->_ArithmeticExpression(); - } - } - - return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr); - } - - /** - * Checks whether the current lookahead token of the lexer has the type - * T_ALL, T_ANY or T_SOME. - * - * @return boolean - */ - private function _isNextAllAnySome() - { - return $this->_lexer->lookahead['type'] === Lexer::T_ALL || - $this->_lexer->lookahead['type'] === Lexer::T_ANY || - $this->_lexer->lookahead['type'] === Lexer::T_SOME; - } - - /** - * Function ::= FunctionsReturningStrings | FunctionsReturningNumerics | FunctionsReturningDatetime - */ - public function _Function() - { - $funcName = $this->_lexer->lookahead['value']; - if ($this->_isStringFunction($funcName)) { - return $this->_FunctionsReturningStrings(); - } else if ($this->_isNumericFunction($funcName)) { - return $this->_FunctionsReturningNumerics(); - } else if ($this->_isDatetimeFunction($funcName)) { - return $this->_FunctionsReturningDatetime(); - } else { - $this->syntaxError('Known function.'); - } - } - - /** - * Checks whether the function with the given name is a string function - * (a function that returns strings). - */ - public function _isStringFunction($funcName) - { - return isset(self::$_STRING_FUNCTIONS[strtolower($funcName)]); - } - - /** - * Checks whether the function with the given name is a numeric function - * (a function that returns numerics). - */ - public function _isNumericFunction($funcName) - { - return isset(self::$_NUMERIC_FUNCTIONS[strtolower($funcName)]); - } - - /** - * Checks whether the function with the given name is a datetime function - * (a function that returns date/time values). - */ - public function _isDatetimeFunction($funcName) - { - return isset(self::$_DATETIME_FUNCTIONS[strtolower($funcName)]); - } - - /** - * Peeks beyond the specified token and returns the first token after that one. - */ - private function _peekBeyond($token) - { - $peek = $this->_lexer->peek(); - while ($peek['value'] != $token) { - $peek = $this->_lexer->peek(); - } - $peek = $this->_lexer->peek(); - $this->_lexer->resetPeek(); - - return $peek; - } - - /** - * Checks whether the given token is a comparison operator. - */ - public function _isComparisonOperator($token) - { - $value = $token['value']; - return $value == '=' || $value == '<' || $value == '<=' || $value == '<>' || - $value == '>' || $value == '>=' || $value == '!='; - } - - /** - * ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")" - */ - public function _ArithmeticExpression() - { - $expr = new AST\ArithmeticExpression; - if ($this->_lexer->lookahead['value'] === '(') { - $peek = $this->_lexer->glimpse(); - if ($peek['type'] === Lexer::T_SELECT) { - $this->match('('); - $expr->setSubselect($this->_Subselect()); - $this->match(')'); - return $expr; - } - } - $expr->setSimpleArithmeticExpression($this->_SimpleArithmeticExpression()); - return $expr; - } - - /** - * SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}* - */ - public function _SimpleArithmeticExpression() - { - $terms = array(); - $terms[] = $this->_ArithmeticTerm(); - while ($this->_lexer->lookahead['value'] == '+' || $this->_lexer->lookahead['value'] == '-') { - if ($this->_lexer->lookahead['value'] == '+') { - $this->match('+'); - } else { - $this->match('-'); - } - $terms[] = $this->_lexer->token['value']; - $terms[] = $this->_ArithmeticTerm(); - } - return new AST\SimpleArithmeticExpression($terms); - } - - /** - * ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}* - */ - public function _ArithmeticTerm() - { - $factors = array(); - $factors[] = $this->_ArithmeticFactor(); - while ($this->_lexer->lookahead['value'] == '*' || $this->_lexer->lookahead['value'] == '/') { - if ($this->_lexer->lookahead['value'] == '*') { - $this->match('*'); - } else { - $this->match('/'); - } - $factors[] = $this->_lexer->token['value']; - $factors[] = $this->_ArithmeticFactor(); - } - return new AST\ArithmeticTerm($factors); - } - - /** - * ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary - */ - public function _ArithmeticFactor() - { - $pSign = $nSign = false; - if ($this->_lexer->lookahead['value'] == '+') { - $this->match('+'); - $pSign = true; - } else if ($this->_lexer->lookahead['value'] == '-') { - $this->match('-'); - $nSign = true; - } - return new AST\ArithmeticFactor($this->_ArithmeticPrimary(), $pSign, $nSign); - } - - /** - * InExpression ::= StateFieldPathExpression ["NOT"] "IN" "(" (Literal {"," Literal}* | Subselect) ")" - */ - public function _InExpression() - { - $inExpression = new AST\InExpression($this->_StateFieldPathExpression()); - if ($this->_lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); - $inExpression->setNot(true); - } - $this->match(Lexer::T_IN); - $this->match('('); - if ($this->_lexer->isNextToken(Lexer::T_SELECT)) { - $inExpression->setSubselect($this->_Subselect()); - } else { - $literals = array(); - $literals[] = $this->_Literal(); - while ($this->_lexer->isNextToken(',')) { - $this->match(','); - $literals[] = $this->_Literal(); - } - $inExpression->setLiterals($literals); - } - $this->match(')'); - - return $inExpression; - } - - /** - * ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")" - */ - public function _ExistsExpression() - { - $not = false; - if ($this->_lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); - $not = true; - } - $this->match(Lexer::T_EXISTS); - $this->match('('); - $existsExpression = new AST\ExistsExpression($this->_Subselect()); - $this->match(')'); - $existsExpression->setNot($not); - - return $existsExpression; - } - - /** - * QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")" - */ - public function _QuantifiedExpression() - { - $all = $any = $some = false; - if ($this->_lexer->isNextToken(Lexer::T_ALL)) { - $this->match(Lexer::T_ALL); - $all = true; - } else if ($this->_lexer->isNextToken(Lexer::T_ANY)) { - $this->match(Lexer::T_ANY); - $any = true; - } else if ($this->_lexer->isNextToken(Lexer::T_SOME)) { - $this->match(Lexer::T_SOME); - $some = true; - } else { - $this->syntaxError('ALL, ANY or SOME'); - } - $this->match('('); - $qExpr = new AST\QuantifiedExpression($this->_Subselect()); - $this->match(')'); - $qExpr->setAll($all); - $qExpr->setAny($any); - $qExpr->setSome($some); - - return $qExpr; - } - - /** - * Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] - */ - public function _Subselect() - { - $this->_beginDeferredPathExpressionStack(); - $subselect = new AST\Subselect($this->_SimpleSelectClause(), $this->_SubselectFromClause()); - $this->_processDeferredPathExpressionStack(); - - $subselect->setWhereClause( - $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->_WhereClause() : null - ); - - $subselect->setGroupByClause( - $this->_lexer->isNextToken(Lexer::T_GROUP) ? $this->_GroupByClause() : null - ); - - $subselect->setHavingClause( - $this->_lexer->isNextToken(Lexer::T_HAVING) ? $this->_HavingClause() : null - ); - - $subselect->setOrderByClause( - $this->_lexer->isNextToken(Lexer::T_ORDER) ? $this->_OrderByClause() : null - ); - - return $subselect; - } - - /** - * SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression - */ - public function _SimpleSelectClause() - { - $distinct = false; - $this->match(Lexer::T_SELECT); - if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) { - $this->match(Lexer::T_DISTINCT); - $distinct = true; - } - $simpleSelectClause = new AST\SimpleSelectClause($this->_SimpleSelectExpression()); - $simpleSelectClause->setDistinct($distinct); - - return $simpleSelectClause; - } - - /** - * SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}* - */ - public function _SubselectFromClause() - { - $this->match(Lexer::T_FROM); - $identificationVariables = array(); - $identificationVariables[] = $this->_SubselectIdentificationVariableDeclaration(); - while ($this->_lexer->isNextToken(',')) { - $this->match(','); - $identificationVariables[] = $this->_SubselectIdentificationVariableDeclaration(); - } - - return new AST\SubselectFromClause($identificationVariables); - } - - /** - * SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | (AssociationPathExpression ["AS"] AliasIdentificationVariable) - */ - public function _SubselectIdentificationVariableDeclaration() - { - $peek = $this->_lexer->glimpse(); - if ($peek['value'] == '.') { - $subselectIdentificationVarDecl = new AST\SubselectIdentificationVariableDeclaration; - $subselectIdentificationVarDecl->setAssociationPathExpression($this->_AssociationPathExpression()); - $this->match(Lexer::T_AS); - $this->match(Lexer::T_IDENTIFIER); - $subselectIdentificationVarDecl->setAliasIdentificationVariable($this->_lexer->token['value']); - return $subselectIdentificationVarDecl; - } else { - return $this->_IdentificationVariableDeclaration(); - } - } - - /** - * SimpleSelectExpression ::= StateFieldPathExpression | IdentificationVariable | (AggregateExpression [["AS"] FieldAliasIdentificationVariable]) - */ - public function _SimpleSelectExpression() - { - if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { - // SingleValuedPathExpression | IdentificationVariable - $peek = $this->_lexer->glimpse(); - if ($peek['value'] == '.') { - return new AST\SimpleSelectExpression($this->_StateFieldPathExpression()); - } else { - $this->match($this->_lexer->lookahead['value']); - return new AST\SimpleSelectExpression($this->_lexer->token['value']); - } - } else { - $expr = new AST\SimpleSelectExpression($this->_AggregateExpression()); - if ($this->_lexer->isNextToken(Lexer::T_AS)) { - $this->match(Lexer::T_AS); - } - if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { - $this->match(Lexer::T_IDENTIFIER); - $expr->setFieldIdentificationVariable($this->_lexer->token['value']); - } - return $expr; - } - } - - /** - * Literal ::= string | char | integer | float | boolean | InputParameter - */ - public function _Literal() - { - switch ($this->_lexer->lookahead['type']) { - case Lexer::T_INPUT_PARAMETER: - $this->match($this->_lexer->lookahead['value']); - return new AST\InputParameter($this->_lexer->token['value']); - case Lexer::T_STRING: - case Lexer::T_INTEGER: - case Lexer::T_FLOAT: - $this->match($this->_lexer->lookahead['value']); - return $this->_lexer->token['value']; - default: - $this->syntaxError('Literal'); - } - } - - /** - * BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression - */ - public function _BetweenExpression() - { - $not = false; - $arithExpr1 = $this->_ArithmeticExpression(); - if ($this->_lexer->isNextToken(Lexer::T_NOT)) { - $this->match(Lexer::T_NOT); - $not = true; - } - $this->match(Lexer::T_BETWEEN); - $arithExpr2 = $this->_ArithmeticExpression(); - $this->match(Lexer::T_AND); - $arithExpr3 = $this->_ArithmeticExpression(); - - $betweenExpr = new AST\BetweenExpression($arithExpr1, $arithExpr2, $arithExpr3); - $betweenExpr->setNot($not); - - return $betweenExpr; - } - - /** - * ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")" | Function | AggregateExpression - * @todo Implementation incomplete. - */ - public function _ArithmeticPrimary() - { - if ($this->_lexer->lookahead['value'] === '(') { - $this->match('('); - $expr = $this->_SimpleArithmeticExpression(); - $this->match(')'); - return $expr; - } - - switch ($this->_lexer->lookahead['type']) { - case Lexer::T_IDENTIFIER: - $peek = $this->_lexer->glimpse(); - if ($peek['value'] == '(') { - return $this->_FunctionsReturningNumerics(); - } - return $this->_StateFieldPathExpression(); - case Lexer::T_INPUT_PARAMETER: - $this->match($this->_lexer->lookahead['value']); - return new AST\InputParameter($this->_lexer->token['value']); - case Lexer::T_STRING: - case Lexer::T_INTEGER: - case Lexer::T_FLOAT: - $this->match($this->_lexer->lookahead['value']); - return $this->_lexer->token['value']; - default: - $peek = $this->_lexer->glimpse(); - if ($peek['value'] == '(') { - if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { - return $this->_AggregateExpression(); - } - return $this->_FunctionsReturningStrings(); - } else { - $this->syntaxError(); - } - } - throw DoctrineException::updateMe("Not yet implemented2."); - //TODO... - } - - /** - * FunctionsReturningStrings ::= - * "CONCAT" "(" StringPrimary "," StringPrimary ")" | - * "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | - * "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" | - * "LOWER" "(" StringPrimary ")" | - * "UPPER" "(" StringPrimary ")" - */ - public function _FunctionsReturningStrings() - { - $funcNameLower = strtolower($this->_lexer->lookahead['value']); - $funcClass = self::$_STRING_FUNCTIONS[$funcNameLower]; - $function = new $funcClass($funcNameLower); - $function->parse($this); - return $function; - } - - /** - * FunctionsReturningNumerics ::= - * "LENGTH" "(" StringPrimary ")" | - * "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" | - * "ABS" "(" SimpleArithmeticExpression ")" | - * "SQRT" "(" SimpleArithmeticExpression ")" | - * "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | - * "SIZE" "(" CollectionValuedPathExpression ")" - */ - public function _FunctionsReturningNumerics() - { - $funcNameLower = strtolower($this->_lexer->lookahead['value']); - $funcClass = self::$_NUMERIC_FUNCTIONS[$funcNameLower]; - $function = new $funcClass($funcNameLower); - $function->parse($this); - return $function; - } - - /** - * FunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP" - */ - public function _FunctionsReturningDatetime() - { - $funcNameLower = strtolower($this->_lexer->lookahead['value']); - $funcClass = self::$_DATETIME_FUNCTIONS[$funcNameLower]; - $function = new $funcClass($funcNameLower); - $function->parse($this); - return $function; - } - - /** - * Checks whether the given token type indicates an aggregate function. - */ - public function _isAggregateFunction($tokenType) - { - return $tokenType == Lexer::T_AVG || $tokenType == Lexer::T_MIN || - $tokenType == Lexer::T_MAX || $tokenType == Lexer::T_SUM || - $tokenType == Lexer::T_COUNT; - } - - /** - * ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!=" - */ - public function _ComparisonOperator() - { - switch ($this->_lexer->lookahead['value']) { - case '=': - $this->match('='); - return '='; - case '<': - $this->match('<'); - $operator = '<'; - if ($this->_lexer->isNextToken('=')) { - $this->match('='); - $operator .= '='; - } else if ($this->_lexer->isNextToken('>')) { - $this->match('>'); - $operator .= '>'; - } - return $operator; - case '>': - $this->match('>'); - $operator = '>'; - if ($this->_lexer->isNextToken('=')) { - $this->match('='); - $operator .= '='; - } - return $operator; - case '!': - $this->match('!'); - $this->match('='); - return '<>'; - default: - $this->syntaxError('=, <, <=, <>, >, >=, !='); - break; - } - } - - /** - * LikeExpression ::= StringExpression ["NOT"] "LIKE" (string | input_parameter) ["ESCAPE" char] - */ - public function _LikeExpression() - { - $stringExpr = $this->_StringExpression(); - $isNot = false; - if ($this->_lexer->lookahead['type'] === Lexer::T_NOT) { - $this->match(Lexer::T_NOT); - $isNot = true; - } - $this->match(Lexer::T_LIKE); - if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { - $this->match(Lexer::T_INPUT_PARAMETER); - $stringPattern = new AST\InputParameter($this->_lexer->token['value']); - } else { - $this->match(Lexer::T_STRING); - $stringPattern = $this->_lexer->token['value']; - } - $escapeChar = null; - if ($this->_lexer->lookahead['type'] === Lexer::T_ESCAPE) { - $this->match(Lexer::T_ESCAPE); - $this->match(Lexer::T_STRING); - $escapeChar = $this->_lexer->token['value']; - } - - return new AST\LikeExpression($stringExpr, $stringPattern, $isNot, $escapeChar); - } - - /** - * StringExpression ::= StringPrimary | "(" Subselect ")" - */ - public function _StringExpression() - { - if ($this->_lexer->lookahead['value'] === '(') { - $peek = $this->_lexer->glimpse(); - if ($peek['type'] === Lexer::T_SELECT) { - $this->match('('); - $expr = $this->_Subselect(); - $this->match(')'); - return $expr; - } - } - return $this->_StringPrimary(); - } - - /** - * StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression - */ - public function _StringPrimary() - { - if ($this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) { - $peek = $this->_lexer->glimpse(); - if ($peek['value'] == '.') { - return $this->_StateFieldPathExpression(); - } else if ($peek['value'] == '(') { - return $this->_FunctionsReturningStrings(); - } else { - $this->syntaxError("'.' or '('"); - } - } else if ($this->_lexer->lookahead['type'] === Lexer::T_STRING) { - $this->match(Lexer::T_STRING); - return $this->_lexer->token['value']; - } else if ($this->_lexer->lookahead['type'] === Lexer::T_INPUT_PARAMETER) { - $this->match(Lexer::T_INPUT_PARAMETER); - return new AST\InputParameter($this->_lexer->token['value']); - } else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { - return $this->_AggregateExpression(); - } else { - $this->syntaxError('StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression'); - } - } - - /** - * Registers a custom function that returns strings. - * - * @param string $name The function name. - * @param string $class The class name of the function implementation. - */ - public static function registerStringFunction($name, $class) - { - self::$_STRING_FUNCTIONS[$name] = $class; - } - - /** - * Registers a custom function that returns numerics. - * - * @param string $name The function name. - * @param string $class The class name of the function implementation. - */ - public static function registerNumericFunction($name, $class) - { - self::$_NUMERIC_FUNCTIONS[$name] = $class; - } - - /** - * Registers a custom function that returns date/time values. - * - * @param string $name The function name. - * @param string $class The class name of the function implementation. - */ - public static function registerDatetimeFunction($name, $class) - { - self::$_DATETIME_FUNCTIONS[$name] = $class; - } +. + */ + +namespace Doctrine\ORM\Query; + +use Doctrine\Common\DoctrineException; +use Doctrine\ORM\Query; +use Doctrine\ORM\Query\AST; +use Doctrine\ORM\Query\Exec; + +/** + * An LL(*) parser for the context-free grammar of the Doctrine Query Language. + * Parses a DQL query, reports any errors in it, and generates an AST. + * + * @author Guilherme Blanco + * @author Janne Vanhala + * @author Roman Borschel + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.doctrine-project.org + * @since 2.0 + * @version $Revision$ + */ +class Parser +{ + /** Maps registered string function names to class names. */ + private static $_STRING_FUNCTIONS = array( + 'concat' => 'Doctrine\ORM\Query\AST\Functions\ConcatFunction', + 'substring' => 'Doctrine\ORM\Query\AST\Functions\SubstringFunction', + 'trim' => 'Doctrine\ORM\Query\AST\Functions\TrimFunction', + 'lower' => 'Doctrine\ORM\Query\AST\Functions\LowerFunction', + 'upper' => 'Doctrine\ORM\Query\AST\Functions\UpperFunction' + ); + + /** Maps registered numeric function names to class names. */ + private static $_NUMERIC_FUNCTIONS = array( + 'length' => 'Doctrine\ORM\Query\AST\Functions\LengthFunction', + 'locate' => 'Doctrine\ORM\Query\AST\Functions\LocateFunction', + 'abs' => 'Doctrine\ORM\Query\AST\Functions\AbsFunction', + 'sqrt' => 'Doctrine\ORM\Query\AST\Functions\SqrtFunction', + 'mod' => 'Doctrine\ORM\Query\AST\Functions\ModFunction', + 'size' => 'Doctrine\ORM\Query\AST\Functions\SizeFunction' + ); + + /** Maps registered datetime function names to class names. */ + private static $_DATETIME_FUNCTIONS = array( + 'current_date' => 'Doctrine\ORM\Query\AST\Functions\CurrentDateFunction', + 'current_time' => 'Doctrine\ORM\Query\AST\Functions\CurrentTimeFunction', + 'current_timestamp' => 'Doctrine\ORM\Query\AST\Functions\CurrentTimestampFunction' + ); + + /** + * The minimum number of tokens read after last detected error before + * another error can be reported. + * + * @var int + */ + //const MIN_ERROR_DISTANCE = 2; + + /** + * Path expressions that were encountered during parsing of SelectExpressions + * and still need to be validated. + * + * @var array + */ + private $_deferredPathExpressionStacks = array(); + + /** + * A scanner object. + * + * @var Doctrine\ORM\Query\Lexer + */ + private $_lexer; + + /** + * The Parser Result object. + * + * @var Doctrine\ORM\Query\ParserResult + */ + private $_parserResult; + + /** + * The EntityManager. + * + * @var EnityManager + */ + private $_em; + + /** + * The Query to parse. + * + * @var Query + */ + private $_query; + + /** + * Map of declared classes in the parsed query. + * Maps the declared DQL alias (key) to the class name (value). + * + * @var array + */ + private $_queryComponents = array(); + + /** + * Creates a new query parser object. + * + * @param Query $query The Query to parse. + */ + public function __construct(Query $query) + { + $this->_query = $query; + $this->_em = $query->getEntityManager(); + $this->_lexer = new Lexer($query->getDql()); + $this->_parserResult = new ParserResult; + //$this->_parserResult->setEntityManager($this->_em); + } + + /** + * 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->_lexer->lookahead['value'] === $token); + } else { + $isMatch = ($this->_lexer->lookahead['type'] === $token); + } + + if ( ! $isMatch) { + $this->syntaxError($this->_lexer->getLiteral($token)); + } + + $this->_lexer->moveNext(); + } + + /** + * Free this parser enabling it to be reused + * + * @param boolean $deep Whether to clean peek and reset errors + * @param integer $position Position to reset + */ + public function free($deep = false, $position = 0) + { + // WARNING! Use this method with care. It resets the scanner! + $this->_lexer->resetPosition($position); + + // Deep = true cleans peek and also any previously defined errors + if ($deep) { + $this->_lexer->resetPeek(); + //$this->_errors = array(); + } + + $this->_lexer->token = null; + $this->_lexer->lookahead = null; + //$this->_errorDistance = self::MIN_ERROR_DISTANCE; + } + + /** + * Parses a query string. + * + * @return ParserResult + */ + public function parse() + { + // Parse & build AST + $AST = $this->_QueryLanguage(); + + // Check for end of string + if ($this->_lexer->lookahead !== null) { + //var_dump($this->_lexer->lookahead); + $this->syntaxError('end of string'); + } + + // Create SqlWalker who creates the SQL from the AST + $sqlWalker = new SqlWalker($this->_query, $this->_parserResult, $this->_queryComponents); + + // Assign an SQL executor to the parser result + $this->_parserResult->setSqlExecutor(Exec\AbstractExecutor::create($AST, $sqlWalker)); + + return $this->_parserResult; + } + + /** + * Gets the lexer used by the parser. + * + * @return Doctrine\ORM\Query\Lexer + */ + public function getLexer() + { + return $this->_lexer; + } + + /** + * Gets the ParserResult that is being filled with information during parsing. + * + * @return Doctrine\ORM\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->_lexer->lookahead; + } + + $message = 'line 0, col ' . (isset($token['position']) ? $token['position'] : '-1') . ': Error: '; + + if ($expected !== '') { + $message .= "Expected '$expected', got "; + } else { + $message .= 'Unexpected '; + } + + if ($this->_lexer->lookahead === null) { + $message .= 'end of string.'; + } else { + $message .= "'{$this->_lexer->lookahead['value']}'"; + } + + throw DoctrineException::updateMe($message); + } + + /** + * Generates a new semantical error. + * + * @param string $message Optional message. + * @param array $token Optional token. + */ + public function semanticalError($message = '', $token = null) + { + if ($token === null) { + $token = $this->_lexer->token; + } + //TODO: Include $token in $message + throw DoctrineException::updateMe($message); + } + + /** + * Logs new error entry. + * + * @param string $message Message to log. + * @param array $token Token that it was processing. + */ + /*protected function _logError($message = '', $token) + { + if ($this->_errorDistance >= self::MIN_ERROR_DISTANCE) { + $message = 'line 0, col ' . $token['position'] . ': ' . $message; + $this->_errors[] = $message; + } + + $this->_errorDistance = 0; + }*/ + + /** + * Gets the EntityManager used by the parser. + * + * @return EntityManager + */ + public function getEntityManager() + { + return $this->_em; + } + + /** + * Checks if the next-next (after lookahead) token starts a function. + * + * @return boolean + */ + private function _isFunction() + { + $next = $this->_lexer->glimpse(); + return $next['value'] === '('; + } + + /** + * Checks whether the next 2 tokens start a subselect. + * + * @return boolean TRUE if the next 2 tokens start a subselect, FALSE otherwise. + */ + private function _isSubselect() + { + $la = $this->_lexer->lookahead; + $next = $this->_lexer->glimpse(); + return ($la['value'] === '(' && $next['type'] === Lexer::T_SELECT); + } + + /** + * QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement + */ + public function _QueryLanguage() + { + $this->_lexer->moveNext(); + switch ($this->_lexer->lookahead['type']) { + case Lexer::T_SELECT: + return $this->_SelectStatement(); + case Lexer::T_UPDATE: + return $this->_UpdateStatement(); + case Lexer::T_DELETE: + return $this->_DeleteStatement(); + default: + $this->syntaxError('SELECT, UPDATE or DELETE'); + break; + } + } + + /** + * SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] + */ + public function _SelectStatement() + { + $this->_beginDeferredPathExpressionStack(); + $selectClause = $this->_SelectClause(); + $fromClause = $this->_FromClause(); + $this->_processDeferredPathExpressionStack(); + + $whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) ? + $this->_WhereClause() : null; + + $groupByClause = $this->_lexer->isNextToken(Lexer::T_GROUP) ? + $this->_GroupByClause() : null; + + $havingClause = $this->_lexer->isNextToken(Lexer::T_HAVING) ? + $this->_HavingClause() : null; + + $orderByClause = $this->_lexer->isNextToken(Lexer::T_ORDER) ? + $this->_OrderByClause() : null; + + return new AST\SelectStatement( + $selectClause, $fromClause, $whereClause, $groupByClause, $havingClause, $orderByClause + ); + } + + /** + * Begins a new stack of deferred path expressions. + */ + private function _beginDeferredPathExpressionStack() + { + $this->_deferredPathExpressionStacks[] = array(); + } + + /** + * Processes the topmost stack of deferred path expressions. + * These will be validated to make sure they are indeed + * valid StateFieldPathExpressions and additional information + * is attached to their AST nodes. + */ + private function _processDeferredPathExpressionStack() + { + $exprStack = array_pop($this->_deferredPathExpressionStacks); + $qComps = $this->_queryComponents; + foreach ($exprStack as $expr) { + $parts = $expr->getParts(); + $numParts = count($parts); + $dqlAlias = $parts[0]; + if (count($parts) == 2) { + $expr->setIsSimpleStateFieldPathExpression(true); + if ( ! $qComps[$dqlAlias]['metadata']->hasField($parts[1])) { + $this->semanticalError('The class ' . $qComps[$dqlAlias]['metadata']->name + . ' has no simple state field named ' . $parts[1]); + } + } else { + $embeddedClassFieldSeen = false; + $assocSeen = false; + for ($i = 1; $i < $numParts - 1; ++$i) { + if ($qComps[$dqlAlias]['metadata']->hasAssociation($parts[$i])) { + if ($embeddedClassFieldSeen) { + $this->semanticalError('Invalid navigation path.'); + } + // Indirect join + $assoc = $qComps[$dqlAlias]['metadata']->getAssociationMapping($parts[$i]); + if ( ! $assoc->isOneToOne()) { + $this->semanticalError('Single-valued association expected.'); + } + $expr->setIsSingleValuedAssociationPart($parts[$i]); + //TODO... + $assocSeen = true; + } else if ($qComps[$dqlAlias]['metadata']->hasEmbeddedClassField($parts[$i])) { + //TODO... + $expr->setIsEmbeddedClassPart($parts[$i]); + $this->syntaxError(); + } else { + $this->syntaxError(); + } + } + if ( ! $assocSeen) { + $expr->setIsSimpleStateFieldPathExpression(true); + } else { + $expr->setIsSimpleStateFieldAssociationPathExpression(true); + } + // Last part MUST be a simple state field + if ( ! $qComps[$dqlAlias]['metadata']->hasField($parts[$numParts-1])) { + $this->semanticalError('The class ' . $qComps[$dqlAlias]['metadata']->name + . ' has no simple state field named ' . $parts[$numParts-1]); + } + } + } + } + + /** + * UpdateStatement ::= UpdateClause [WhereClause] + */ + public function _UpdateStatement() + { + $updateStatement = new AST\UpdateStatement($this->_UpdateClause()); + $updateStatement->setWhereClause( + $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->_WhereClause() : null + ); + return $updateStatement; + } + + /** + * UpdateClause ::= "UPDATE" AbstractSchemaName [["AS"] AliasIdentificationVariable] "SET" UpdateItem {"," UpdateItem}* + */ + public function _UpdateClause() + { + $this->match(Lexer::T_UPDATE); + $abstractSchemaName = $this->_AbstractSchemaName(); + $aliasIdentificationVariable = null; + if ($this->_lexer->isNextToken(Lexer::T_AS)) { + $this->match(Lexer::T_AS); + } + if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { + $this->match(Lexer::T_IDENTIFIER); + $aliasIdentificationVariable = $this->_lexer->token['value']; + } else { + $aliasIdentificationVariable = $abstractSchemaName; + } + $this->match(Lexer::T_SET); + $updateItems = array(); + $updateItems[] = $this->_UpdateItem(); + while ($this->_lexer->isNextToken(',')) { + $this->match(','); + $updateItems[] = $this->_UpdateItem(); + } + + $classMetadata = $this->_em->getClassMetadata($abstractSchemaName); + // Building queryComponent + $queryComponent = array( + 'metadata' => $classMetadata, + 'parent' => null, + 'relation' => null, + 'map' => null + ); + $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; + + $updateClause = new AST\UpdateClause($abstractSchemaName, $updateItems); + $updateClause->setAliasIdentificationVariable($aliasIdentificationVariable); + + return $updateClause; + } + + /** + * UpdateItem ::= [IdentificationVariable "."] {StateField | SingleValuedAssociationField} "=" NewValue + */ + public function _UpdateItem() + { + $peek = $this->_lexer->glimpse(); + $identVariable = null; + if ($peek['value'] == '.') { + $this->match(Lexer::T_IDENTIFIER); + $identVariable = $this->_lexer->token['value']; + $this->match('.'); + } else { + throw QueryException::missingAliasQualifier(); + } + $this->match(Lexer::T_IDENTIFIER); + $field = $this->_lexer->token['value']; + $this->match('='); + $newValue = $this->_NewValue(); + + $updateItem = new AST\UpdateItem($field, $newValue); + $updateItem->setIdentificationVariable($identVariable); + + return $updateItem; + } + + /** + * NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary | + * EnumPrimary | SimpleEntityExpression | "NULL" + * @todo Implementation still incomplete. + */ + public function _NewValue() + { + if ($this->_lexer->isNextToken(Lexer::T_NULL)) { + $this->match(Lexer::T_NULL); + return null; + } else if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { + $this->match(Lexer::T_INPUT_PARAMETER); + return new AST\InputParameter($this->_lexer->token['value']); + } else if ($this->_lexer->isNextToken(Lexer::T_STRING)) { + //TODO: Can be StringPrimary or EnumPrimary + return $this->_StringPrimary(); + } else { + $this->syntaxError('Not yet implemented-1.'); + } + } + + /** + * DeleteStatement ::= DeleteClause [WhereClause] + */ + public function _DeleteStatement() + { + $deleteStatement = new AST\DeleteStatement($this->_DeleteClause()); + $deleteStatement->setWhereClause( + $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->_WhereClause() : null + ); + return $deleteStatement; + } + + /** + * DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName [["AS"] AliasIdentificationVariable] + */ + public function _DeleteClause() + { + $this->match(Lexer::T_DELETE); + if ($this->_lexer->isNextToken(Lexer::T_FROM)) { + $this->match(Lexer::T_FROM); + } + $deleteClause = new AST\DeleteClause($this->_AbstractSchemaName()); + if ($this->_lexer->isNextToken(Lexer::T_AS)) { + $this->match(Lexer::T_AS); + } + if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { + $this->match(Lexer::T_IDENTIFIER); + $deleteClause->setAliasIdentificationVariable($this->_lexer->token['value']); + } else { + $deleteClause->setAliasIdentificationVariable($deleteClause->getAbstractSchemaName()); + } + + $classMetadata = $this->_em->getClassMetadata($deleteClause->getAbstractSchemaName()); + $queryComponent = array( + 'metadata' => $classMetadata + ); + $this->_queryComponents[$deleteClause->getAliasIdentificationVariable()] = $queryComponent; + + return $deleteClause; + } + + /** + * SelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression} + */ + public function _SelectClause() + { + $isDistinct = false; + $this->match(Lexer::T_SELECT); + + // Check for DISTINCT + if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) { + $this->match(Lexer::T_DISTINCT); + $isDistinct = true; + } + + // Process SelectExpressions (1..N) + $selectExpressions = array(); + $selectExpressions[] = $this->_SelectExpression(); + while ($this->_lexer->isNextToken(',')) { + $this->match(','); + $selectExpressions[] = $this->_SelectExpression(); + } + + return new AST\SelectClause($selectExpressions, $isDistinct); + } + + /** + * FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}* + */ + public function _FromClause() + { + $this->match(Lexer::T_FROM); + $identificationVariableDeclarations = array(); + $identificationVariableDeclarations[] = $this->_IdentificationVariableDeclaration(); + + while ($this->_lexer->isNextToken(',')) { + $this->match(','); + $identificationVariableDeclarations[] = $this->_IdentificationVariableDeclaration(); + } + + return new AST\FromClause($identificationVariableDeclarations); + } + + /** + * SelectExpression ::= + * IdentificationVariable | StateFieldPathExpression | + * (AggregateExpression | "(" Subselect ")") [["AS"] FieldAliasIdentificationVariable] | + * Function + */ + public function _SelectExpression() + { + $expression = null; + $fieldIdentificationVariable = null; + $peek = $this->_lexer->glimpse(); + // First we recognize for an IdentificationVariable (DQL class alias) + if ($peek['value'] != '.' && $peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) { + $expression = $this->_IdentificationVariable(); + } else if (($isFunction = $this->_isFunction()) !== false || $this->_isSubselect()) { + if ($isFunction) { + if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { + $expression = $this->_AggregateExpression(); + } else { + $expression = $this->_Function(); + } + } else { + $this->match('('); + $expression = $this->_Subselect(); + $this->match(')'); + } + if ($this->_lexer->isNextToken(Lexer::T_AS)) { + $this->match(Lexer::T_AS); + } + if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { + $this->match(Lexer::T_IDENTIFIER); + $fieldIdentificationVariable = $this->_lexer->token['value']; + } + } else { + //TODO: If hydration mode is OBJECT throw an exception ("partial object dangerous...") + // unless the doctrine.forcePartialLoad query hint is set + $expression = $this->_StateFieldPathExpression(); + } + return new AST\SelectExpression($expression, $fieldIdentificationVariable); + } + + /** + * IdentificationVariable ::= identifier + */ + public function _IdentificationVariable() + { + $this->match(Lexer::T_IDENTIFIER); + return $this->_lexer->token['value']; + } + + /** + * IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}* + */ + public function _IdentificationVariableDeclaration() + { + $rangeVariableDeclaration = $this->_RangeVariableDeclaration(); + $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->_IndexBy() : null; + $joinVariableDeclarations = array(); + while ( + $this->_lexer->isNextToken(Lexer::T_LEFT) || + $this->_lexer->isNextToken(Lexer::T_INNER) || + $this->_lexer->isNextToken(Lexer::T_JOIN) + ) { + $joinVariableDeclarations[] = $this->_JoinVariableDeclaration(); + } + + return new AST\IdentificationVariableDeclaration( + $rangeVariableDeclaration, $indexBy, $joinVariableDeclarations + ); + } + + /** + * RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable + */ + public function _RangeVariableDeclaration() + { + $abstractSchemaName = $this->_AbstractSchemaName(); + + if ($this->_lexer->isNextToken(Lexer::T_AS)) { + $this->match(Lexer::T_AS); + } + $aliasIdentificationVariable = $this->_AliasIdentificationVariable(); + $classMetadata = $this->_em->getClassMetadata($abstractSchemaName); + + // Building queryComponent + $queryComponent = array( + 'metadata' => $classMetadata, + 'parent' => null, + 'relation' => null, + 'map' => null + ); + $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent; + + return new AST\RangeVariableDeclaration( + $classMetadata, $aliasIdentificationVariable + ); + } + + /** + * AbstractSchemaName ::= identifier + */ + public function _AbstractSchemaName() + { + $this->match(Lexer::T_IDENTIFIER); + return $this->_lexer->token['value']; + } + + /** + * AliasIdentificationVariable = identifier + */ + public function _AliasIdentificationVariable() + { + $this->match(Lexer::T_IDENTIFIER); + return $this->_lexer->token['value']; + } + + /** + * JoinVariableDeclaration ::= Join [IndexBy] + */ + public function _JoinVariableDeclaration() + { + $join = $this->_Join(); + $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? + $this->_IndexBy() : null; + return new AST\JoinVariableDeclaration($join, $indexBy); + } + + /** + * Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression + * ["AS"] AliasIdentificationVariable [("ON" | "WITH") ConditionalExpression] + */ + public function _Join() + { + // Check Join type + $joinType = AST\Join::JOIN_TYPE_INNER; + if ($this->_lexer->isNextToken(Lexer::T_LEFT)) { + $this->match(Lexer::T_LEFT); + // Possible LEFT OUTER join + if ($this->_lexer->isNextToken(Lexer::T_OUTER)) { + $this->match(Lexer::T_OUTER); + $joinType = AST\Join::JOIN_TYPE_LEFTOUTER; + } else { + $joinType = AST\Join::JOIN_TYPE_LEFT; + } + } else if ($this->_lexer->isNextToken(Lexer::T_INNER)) { + $this->match(Lexer::T_INNER); + } + + $this->match(Lexer::T_JOIN); + + $joinPathExpression = $this->_JoinPathExpression(); + if ($this->_lexer->isNextToken(Lexer::T_AS)) { + $this->match(Lexer::T_AS); + } + + $aliasIdentificationVariable = $this->_AliasIdentificationVariable(); + + // Verify that the association exists. + $parentClass = $this->_queryComponents[$joinPathExpression->getIdentificationVariable()]['metadata']; + $assocField = $joinPathExpression->getAssociationField(); + if ( ! $parentClass->hasAssociation($assocField)) { + $this->semanticalError("Class " . $parentClass->name . + " has no association named '$assocField'."); + } + $targetClassName = $parentClass->getAssociationMapping($assocField)->getTargetEntityName(); + + // Building queryComponent + $joinQueryComponent = array( + 'metadata' => $this->_em->getClassMetadata($targetClassName), + 'parent' => $joinPathExpression->getIdentificationVariable(), + 'relation' => $parentClass->getAssociationMapping($assocField), + 'map' => null + ); + $this->_queryComponents[$aliasIdentificationVariable] = $joinQueryComponent; + + // Create AST node + $join = new AST\Join($joinType, $joinPathExpression, $aliasIdentificationVariable); + + // Check for ad-hoc Join conditions + if ($this->_lexer->isNextToken(Lexer::T_ON) || $this->_lexer->isNextToken(Lexer::T_WITH)) { + if ($this->_lexer->isNextToken(Lexer::T_ON)) { + $this->match(Lexer::T_ON); + $join->setWhereType(AST\Join::JOIN_WHERE_ON); + } else { + $this->match(Lexer::T_WITH); + } + $join->setConditionalExpression($this->_ConditionalExpression()); + } + + return $join; + } + + /** + * JoinPathExpression ::= IdentificationVariable "." (CollectionValuedAssociationField | SingleValuedAssociationField) + */ + public function _JoinPathExpression() + { + $identificationVariable = $this->_IdentificationVariable(); + $this->match('.'); + $this->match(Lexer::T_IDENTIFIER); + return new AST\JoinPathExpression( + $identificationVariable, $this->_lexer->token['value'] + ); + } + + /** + * IndexBy ::= "INDEX" "BY" SimpleStateFieldPathExpression + */ + public function _IndexBy() + { + $this->match(Lexer::T_INDEX); + $this->match(Lexer::T_BY); + $pathExp = $this->_SimpleStateFieldPathExpression(); + // Add the INDEX BY info to the query component + $this->_queryComponents[$pathExp->getIdentificationVariable()]['map'] = $pathExp->getSimpleStateField(); + return $pathExp; + } + + /** + * SimpleStateFieldPathExpression ::= IdentificationVariable "." StateField + * @todo Implementation incomplete. Recognize StateField properly (see EBNF). + */ + public function _SimpleStateFieldPathExpression() + { + $identificationVariable = $this->_IdentificationVariable(); + $this->match('.'); + $this->match(Lexer::T_IDENTIFIER); + $simpleStateField = $this->_lexer->token['value']; + return new AST\SimpleStateFieldPathExpression($identificationVariable, $simpleStateField); + } + + /** + * StateFieldPathExpression ::= SimpleStateFieldPathExpression | SimpleStateFieldAssociationPathExpression + */ + public function _StateFieldPathExpression() + { + if ( ! empty($this->_deferredPathExpressionStacks)) { + $exprStack = array_pop($this->_deferredPathExpressionStacks); + $this->match(Lexer::T_IDENTIFIER); + $parts = array($this->_lexer->token['value']); + while ($this->_lexer->isNextToken('.')) { + $this->match('.'); + $this->match(Lexer::T_IDENTIFIER); + $parts[] = $this->_lexer->token['value']; + } + $expr = new AST\StateFieldPathExpression($parts); + $exprStack[] = $expr; + array_push($this->_deferredPathExpressionStacks, $exprStack); + return $expr; // EARLY EXIT! + } + + $parts = array(); + $stateFieldSeen = false; + $assocSeen = false; + + $identificationVariable = $this->_IdentificationVariable(); + if ( ! isset($this->_queryComponents[$identificationVariable])) { + $this->syntaxError("IdentificationVariable '$identificationVariable' was not declared."); + } + + $qComp = $this->_queryComponents[$identificationVariable]; + $parts[] = $identificationVariable; + + $class = $qComp['metadata']; + + if ( ! $this->_lexer->isNextToken('.')) { + if ($class->isIdentifierComposite) { + $this->syntaxError(); + } + $parts[] = $class->identifier[0]; + } + + while ($this->_lexer->isNextToken('.')) { + if ($stateFieldSeen) { + $this->syntaxError(); + } + $this->match('.'); + $part = $this->_IdentificationVariable(); + if ($class->hasField($part)) { + $stateFieldSeen = true; + } else if ($class->hasAssociation($part)) { + $assoc = $class->getAssociationMapping($part); + $class = $this->_em->getClassMetadata($assoc->getTargetEntityName()); + $assocSeen = true; + } else { + $this->semanticalError('The class ' . $class->name . + ' has no field or association named ' . $part); + } + $parts[] = $part; + } + + $pathExpr = new AST\StateFieldPathExpression($parts); + + if ($assocSeen) { + $pathExpr->setIsSimpleStateFieldAssociationPathExpression(true); + } else { + $pathExpr->setIsSimpleStateFieldPathExpression(true); + } + + return $pathExpr; + } + + /** + * NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL" + * @todo Implementation incomplete for SingleValuedPathExpression. + */ + public function _NullComparisonExpression() + { + if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { + $this->match(Lexer::T_INPUT_PARAMETER); + $expr = new AST\InputParameter($this->_lexer->token['value']); + } else { + //TODO: Support SingleValuedAssociationPathExpression + $expr = $this->_StateFieldPathExpression(); + } + $nullCompExpr = new AST\NullComparisonExpression($expr); + $this->match(Lexer::T_IS); + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + $nullCompExpr->setNot(true); + } + $this->match(Lexer::T_NULL); + + return $nullCompExpr; + } + + /** + * AggregateExpression ::= + * ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" | + * "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedAssociationPathExpression | StateFieldPathExpression) ")" + * @todo Implementation incomplete. Support for SingleValuedAssociationPathExpression. + */ + public function _AggregateExpression() + { + $isDistinct = false; + $functionName = ''; + if ($this->_lexer->isNextToken(Lexer::T_COUNT)) { + $this->match(Lexer::T_COUNT); + $functionName = $this->_lexer->token['value']; + $this->match('('); + if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) { + $this->match(Lexer::T_DISTINCT); + $isDistinct = true; + } + // For now we only support a PathExpression here... + $pathExp = $this->_StateFieldPathExpression(); + $this->match(')'); + } else { + if ($this->_lexer->isNextToken(Lexer::T_AVG)) { + $this->match(Lexer::T_AVG); + } else if ($this->_lexer->isNextToken(Lexer::T_MAX)) { + $this->match(Lexer::T_MAX); + } else if ($this->_lexer->isNextToken(Lexer::T_MIN)) { + $this->match(Lexer::T_MIN); + } else if ($this->_lexer->isNextToken(Lexer::T_SUM)) { + $this->match(Lexer::T_SUM); + } else { + $this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT'); + } + $functionName = $this->_lexer->token['value']; + $this->match('('); + $pathExp = $this->_StateFieldPathExpression(); + $this->match(')'); + } + + return new AST\AggregateExpression($functionName, $pathExp, $isDistinct); + } + + /** + * GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}* + * GroupByItem ::= IdentificationVariable | SingleValuedPathExpression + * @todo Implementation incomplete for GroupByItem. + */ + public function _GroupByClause() + { + $this->match(Lexer::T_GROUP); + $this->match(Lexer::T_BY); + $groupByItems = array(); + $groupByItems[] = $this->_StateFieldPathExpression(); + while ($this->_lexer->isNextToken(',')) { + $this->match(','); + $groupByItems[] = $this->_StateFieldPathExpression(); + } + return new AST\GroupByClause($groupByItems); + } + + /** + * HavingClause ::= "HAVING" ConditionalExpression + */ + public function _HavingClause() + { + $this->match(Lexer::T_HAVING); + return new AST\HavingClause($this->_ConditionalExpression()); + } + + /** + * OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}* + */ + public function _OrderByClause() + { + $this->match(Lexer::T_ORDER); + $this->match(Lexer::T_BY); + $orderByItems = array(); + $orderByItems[] = $this->_OrderByItem(); + while ($this->_lexer->isNextToken(',')) { + $this->match(','); + $orderByItems[] = $this->_OrderByItem(); + } + return new AST\OrderByClause($orderByItems); + } + + /** + * OrderByItem ::= ResultVariable | StateFieldPathExpression ["ASC" | "DESC"] + * @todo Implementation incomplete for OrderByItem. + */ + public function _OrderByItem() + { + $item = new AST\OrderByItem($this->_StateFieldPathExpression()); + if ($this->_lexer->isNextToken(Lexer::T_ASC)) { + $this->match(Lexer::T_ASC); + $item->setAsc(true); + } else if ($this->_lexer->isNextToken(Lexer::T_DESC)) { + $this->match(Lexer::T_DESC); + $item->setDesc(true); + } else { + $item->setDesc(true); + } + return $item; + } + + /** + * WhereClause ::= "WHERE" ConditionalExpression + */ + public function _WhereClause() + { + $this->match(Lexer::T_WHERE); + return new AST\WhereClause($this->_ConditionalExpression()); + } + + /** + * ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}* + */ + public function _ConditionalExpression() + { + $conditionalTerms = array(); + $conditionalTerms[] = $this->_ConditionalTerm(); + while ($this->_lexer->isNextToken(Lexer::T_OR)) { + $this->match(Lexer::T_OR); + $conditionalTerms[] = $this->_ConditionalTerm(); + } + return new AST\ConditionalExpression($conditionalTerms); + } + + /** + * ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}* + */ + public function _ConditionalTerm() + { + $conditionalFactors = array(); + $conditionalFactors[] = $this->_ConditionalFactor(); + while ($this->_lexer->isNextToken(Lexer::T_AND)) { + $this->match(Lexer::T_AND); + $conditionalFactors[] = $this->_ConditionalFactor(); + } + return new AST\ConditionalTerm($conditionalFactors); + } + + /** + * ConditionalFactor ::= ["NOT"] ConditionalPrimary + */ + public function _ConditionalFactor() + { + $not = false; + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + $not = true; + } + return new AST\ConditionalFactor($this->_ConditionalPrimary(), $not); + } + + /** + * ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")" + * @todo Implementation incomplete: Recognition of SimpleConditionalExpression is incomplete. + */ + public function _ConditionalPrimary() + { + $condPrimary = new AST\ConditionalPrimary; + if ($this->_lexer->isNextToken('(')) { + // Peek beyond the matching closing paranthesis ')' + $numUnmatched = 1; + $peek = $this->_lexer->peek(); + while ($numUnmatched > 0) { + if ($peek['value'] == ')') { + --$numUnmatched; + } else if ($peek['value'] == '(') { + ++$numUnmatched; + } + $peek = $this->_lexer->peek(); + } + $this->_lexer->resetPeek(); + + //TODO: This is not complete, what about LIKE/BETWEEN/...etc? + $comparisonOps = array("=", "<", "<=", "<>", ">", ">=", "!="); + + if (in_array($peek['value'], $comparisonOps)) { + $condPrimary->setSimpleConditionalExpression($this->_SimpleConditionalExpression()); + } else { + $this->match('('); + $conditionalExpression = $this->_ConditionalExpression(); + $this->match(')'); + $condPrimary->setConditionalExpression($conditionalExpression); + } + } else { + $condPrimary->setSimpleConditionalExpression($this->_SimpleConditionalExpression()); + } + + return $condPrimary; + } + + /** + * SimpleConditionalExpression ::= + * ComparisonExpression | BetweenExpression | LikeExpression | + * InExpression | NullComparisonExpression | ExistsExpression | + * EmptyCollectionComparisonExpression | CollectionMemberExpression + * + * @todo Implementation incomplete. This is difficult and a strict recognition may + * even require backtracking. + */ + public function _SimpleConditionalExpression() + { + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $token = $this->_lexer->glimpse(); + } else { + $token = $this->_lexer->lookahead; + } + if ($token['type'] === Lexer::T_EXISTS) { + return $this->_ExistsExpression(); + } + + $stateFieldPathExpr = false; + if ($token['type'] === Lexer::T_IDENTIFIER) { + // Peek beyond the PathExpression + $stateFieldPathExpr = true; + $peek = $this->_lexer->peek(); + while ($peek['value'] === '.') { + $this->_lexer->peek(); + $peek = $this->_lexer->peek(); + } + + // Also peek beyond a NOT if there is one + if ($peek['type'] === Lexer::T_NOT) { + $peek = $this->_lexer->peek(); + } + + $this->_lexer->resetPeek(); + $token = $peek; + } + + if ($stateFieldPathExpr) { + switch ($token['type']) { + case Lexer::T_BETWEEN: + return $this->_BetweenExpression(); + case Lexer::T_LIKE: + return $this->_LikeExpression(); + case Lexer::T_IN: + return $this->_InExpression(); + case Lexer::T_IS: + return $this->_NullComparisonExpression(); + case Lexer::T_NONE: + return $this->_ComparisonExpression(); + default: + $this->syntaxError(); + } + } else { + return $this->_ComparisonExpression(); + } + } + + /** + * ComparisonExpression ::= + * ArithmeticExpression ComparisonOperator (QuantifiedExpression | ArithmeticExpression) | + * StringExpression ComparisonOperator (StringExpression | QuantifiedExpression) | + * BooleanExpression ("=" | "<>" | "!=") (BooleanExpression | QuantifiedExpression) | + * EnumExpression ("=" | "<>" | "!=") (EnumExpression | QuantifiedExpression) | + * DatetimeExpression ComparisonOperator (DatetimeExpression | QuantifiedExpression) | + * EntityExpression ("=" | "<>") (EntityExpression | QuantifiedExpression) + * + * @todo Implementation incomplete. Seems difficult. + */ + public function _ComparisonExpression() + { + $peek = $this->_lexer->glimpse(); + + if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { + if ($this->_isComparisonOperator($peek)) { + $this->match(Lexer::T_INPUT_PARAMETER); + $leftExpr = new AST\InputParameter($this->_lexer->token['value']); + } else { + $leftExpr = $this->_ArithmeticExpression(); + } + $operator = $this->_ComparisonOperator(); + $rightExpr = $this->_ArithmeticExpression(); + //... + } + else if ($this->_lexer->isNextToken('(') && $peek['type'] == Lexer::T_SELECT) { + $leftExpr = $this->_Subselect(); + //... + } + else if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER) && $peek['value'] == '(') { + $peek2 = $this->_peekBeyond(')'); + if ($this->_isComparisonOperator($peek2)) { + if ($this->_isStringFunction($this->_lexer->lookahead['value'])) { + $leftExpr = $this->_FunctionsReturningStrings(); + $operator = $this->_ComparisonOperator(); + if ($this->_isNextAllAnySome()) { + $rightExpr = $this->_QuantifiedExpression(); + } else { + $rightExpr = $this->_StringPrimary(); + } + } else if ($this->_isNumericFunction($this->_lexer->lookahead['value'])) { + $leftExpr = $this->_FunctionsReturningNumerics(); + $operator = $this->_ComparisonOperator(); + if ($this->_isNextAllAnySome()) { + $rightExpr = $this->_QuantifiedExpression(); + } else { + $rightExpr = $this->_ArithmeticExpression(); + } + } else { + $leftExpr = $this->_FunctionsReturningDatetime(); + $operator = $this->_ComparisonOperator(); + if ($this->_isNextAllAnySome()) { + $rightExpr = $this->_QuantifiedExpression(); + } else { + $rightExpr = $this->_DatetimePrimary(); + } + } + } else { + $leftExpr = $this->_ArithmeticExpression(); + $operator = $this->_ComparisonOperator(); + if ($this->_isNextAllAnySome()) { + $rightExpr = $this->_QuantifiedExpression(); + } else { + $rightExpr = $this->_StringExpression(); + } + } + } else { + $leftExpr = $this->_ArithmeticExpression(); + $operator = $this->_ComparisonOperator(); + if ($this->_isNextAllAnySome()) { + $rightExpr = $this->_QuantifiedExpression(); + } else { + $rightExpr = $this->_ArithmeticExpression(); + } + } + + return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr); + } + + /** + * Checks whether the current lookahead token of the lexer has the type + * T_ALL, T_ANY or T_SOME. + * + * @return boolean + */ + private function _isNextAllAnySome() + { + return $this->_lexer->lookahead['type'] === Lexer::T_ALL || + $this->_lexer->lookahead['type'] === Lexer::T_ANY || + $this->_lexer->lookahead['type'] === Lexer::T_SOME; + } + + /** + * Function ::= FunctionsReturningStrings | FunctionsReturningNumerics | FunctionsReturningDatetime + */ + public function _Function() + { + $funcName = $this->_lexer->lookahead['value']; + if ($this->_isStringFunction($funcName)) { + return $this->_FunctionsReturningStrings(); + } else if ($this->_isNumericFunction($funcName)) { + return $this->_FunctionsReturningNumerics(); + } else if ($this->_isDatetimeFunction($funcName)) { + return $this->_FunctionsReturningDatetime(); + } else { + $this->syntaxError('Known function.'); + } + } + + /** + * Checks whether the function with the given name is a string function + * (a function that returns strings). + */ + public function _isStringFunction($funcName) + { + return isset(self::$_STRING_FUNCTIONS[strtolower($funcName)]); + } + + /** + * Checks whether the function with the given name is a numeric function + * (a function that returns numerics). + */ + public function _isNumericFunction($funcName) + { + return isset(self::$_NUMERIC_FUNCTIONS[strtolower($funcName)]); + } + + /** + * Checks whether the function with the given name is a datetime function + * (a function that returns date/time values). + */ + public function _isDatetimeFunction($funcName) + { + return isset(self::$_DATETIME_FUNCTIONS[strtolower($funcName)]); + } + + /** + * Peeks beyond the specified token and returns the first token after that one. + */ + private function _peekBeyond($token) + { + $peek = $this->_lexer->peek(); + while ($peek['value'] != $token) { + $peek = $this->_lexer->peek(); + } + $peek = $this->_lexer->peek(); + $this->_lexer->resetPeek(); + + return $peek; + } + + /** + * Checks whether the given token is a comparison operator. + */ + public function _isComparisonOperator($token) + { + $value = $token['value']; + return $value == '=' || $value == '<' || $value == '<=' || $value == '<>' || + $value == '>' || $value == '>=' || $value == '!='; + } + + /** + * ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")" + */ + public function _ArithmeticExpression() + { + $expr = new AST\ArithmeticExpression; + if ($this->_lexer->lookahead['value'] === '(') { + $peek = $this->_lexer->glimpse(); + if ($peek['type'] === Lexer::T_SELECT) { + $this->match('('); + $expr->setSubselect($this->_Subselect()); + $this->match(')'); + return $expr; + } + } + $expr->setSimpleArithmeticExpression($this->_SimpleArithmeticExpression()); + return $expr; + } + + /** + * SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}* + */ + public function _SimpleArithmeticExpression() + { + $terms = array(); + $terms[] = $this->_ArithmeticTerm(); + while ($this->_lexer->lookahead['value'] == '+' || $this->_lexer->lookahead['value'] == '-') { + if ($this->_lexer->lookahead['value'] == '+') { + $this->match('+'); + } else { + $this->match('-'); + } + $terms[] = $this->_lexer->token['value']; + $terms[] = $this->_ArithmeticTerm(); + } + return new AST\SimpleArithmeticExpression($terms); + } + + /** + * ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}* + */ + public function _ArithmeticTerm() + { + $factors = array(); + $factors[] = $this->_ArithmeticFactor(); + while ($this->_lexer->lookahead['value'] == '*' || $this->_lexer->lookahead['value'] == '/') { + if ($this->_lexer->lookahead['value'] == '*') { + $this->match('*'); + } else { + $this->match('/'); + } + $factors[] = $this->_lexer->token['value']; + $factors[] = $this->_ArithmeticFactor(); + } + return new AST\ArithmeticTerm($factors); + } + + /** + * ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary + */ + public function _ArithmeticFactor() + { + $pSign = $nSign = false; + if ($this->_lexer->lookahead['value'] == '+') { + $this->match('+'); + $pSign = true; + } else if ($this->_lexer->lookahead['value'] == '-') { + $this->match('-'); + $nSign = true; + } + return new AST\ArithmeticFactor($this->_ArithmeticPrimary(), $pSign, $nSign); + } + + /** + * InExpression ::= StateFieldPathExpression ["NOT"] "IN" "(" (Literal {"," Literal}* | Subselect) ")" + */ + public function _InExpression() + { + $inExpression = new AST\InExpression($this->_StateFieldPathExpression()); + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + $inExpression->setNot(true); + } + $this->match(Lexer::T_IN); + $this->match('('); + if ($this->_lexer->isNextToken(Lexer::T_SELECT)) { + $inExpression->setSubselect($this->_Subselect()); + } else { + $literals = array(); + $literals[] = $this->_Literal(); + while ($this->_lexer->isNextToken(',')) { + $this->match(','); + $literals[] = $this->_Literal(); + } + $inExpression->setLiterals($literals); + } + $this->match(')'); + + return $inExpression; + } + + /** + * ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")" + */ + public function _ExistsExpression() + { + $not = false; + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + $not = true; + } + $this->match(Lexer::T_EXISTS); + $this->match('('); + $existsExpression = new AST\ExistsExpression($this->_Subselect()); + $this->match(')'); + $existsExpression->setNot($not); + + return $existsExpression; + } + + /** + * QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")" + */ + public function _QuantifiedExpression() + { + $all = $any = $some = false; + if ($this->_lexer->isNextToken(Lexer::T_ALL)) { + $this->match(Lexer::T_ALL); + $all = true; + } else if ($this->_lexer->isNextToken(Lexer::T_ANY)) { + $this->match(Lexer::T_ANY); + $any = true; + } else if ($this->_lexer->isNextToken(Lexer::T_SOME)) { + $this->match(Lexer::T_SOME); + $some = true; + } else { + $this->syntaxError('ALL, ANY or SOME'); + } + $this->match('('); + $qExpr = new AST\QuantifiedExpression($this->_Subselect()); + $this->match(')'); + $qExpr->setAll($all); + $qExpr->setAny($any); + $qExpr->setSome($some); + + return $qExpr; + } + + /** + * Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] + */ + public function _Subselect() + { + $this->_beginDeferredPathExpressionStack(); + $subselect = new AST\Subselect($this->_SimpleSelectClause(), $this->_SubselectFromClause()); + $this->_processDeferredPathExpressionStack(); + + $subselect->setWhereClause( + $this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->_WhereClause() : null + ); + + $subselect->setGroupByClause( + $this->_lexer->isNextToken(Lexer::T_GROUP) ? $this->_GroupByClause() : null + ); + + $subselect->setHavingClause( + $this->_lexer->isNextToken(Lexer::T_HAVING) ? $this->_HavingClause() : null + ); + + $subselect->setOrderByClause( + $this->_lexer->isNextToken(Lexer::T_ORDER) ? $this->_OrderByClause() : null + ); + + return $subselect; + } + + /** + * SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression + */ + public function _SimpleSelectClause() + { + $distinct = false; + $this->match(Lexer::T_SELECT); + if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) { + $this->match(Lexer::T_DISTINCT); + $distinct = true; + } + $simpleSelectClause = new AST\SimpleSelectClause($this->_SimpleSelectExpression()); + $simpleSelectClause->setDistinct($distinct); + + return $simpleSelectClause; + } + + /** + * SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}* + */ + public function _SubselectFromClause() + { + $this->match(Lexer::T_FROM); + $identificationVariables = array(); + $identificationVariables[] = $this->_SubselectIdentificationVariableDeclaration(); + while ($this->_lexer->isNextToken(',')) { + $this->match(','); + $identificationVariables[] = $this->_SubselectIdentificationVariableDeclaration(); + } + + return new AST\SubselectFromClause($identificationVariables); + } + + /** + * SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | (AssociationPathExpression ["AS"] AliasIdentificationVariable) + */ + public function _SubselectIdentificationVariableDeclaration() + { + $peek = $this->_lexer->glimpse(); + if ($peek['value'] == '.') { + $subselectIdentificationVarDecl = new AST\SubselectIdentificationVariableDeclaration; + $subselectIdentificationVarDecl->setAssociationPathExpression($this->_AssociationPathExpression()); + $this->match(Lexer::T_AS); + $this->match(Lexer::T_IDENTIFIER); + $subselectIdentificationVarDecl->setAliasIdentificationVariable($this->_lexer->token['value']); + return $subselectIdentificationVarDecl; + } else { + return $this->_IdentificationVariableDeclaration(); + } + } + + /** + * SimpleSelectExpression ::= StateFieldPathExpression | IdentificationVariable | (AggregateExpression [["AS"] FieldAliasIdentificationVariable]) + */ + public function _SimpleSelectExpression() + { + if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { + // SingleValuedPathExpression | IdentificationVariable + $peek = $this->_lexer->glimpse(); + if ($peek['value'] == '.') { + return new AST\SimpleSelectExpression($this->_StateFieldPathExpression()); + } else { + $this->match($this->_lexer->lookahead['value']); + return new AST\SimpleSelectExpression($this->_lexer->token['value']); + } + } else { + $expr = new AST\SimpleSelectExpression($this->_AggregateExpression()); + if ($this->_lexer->isNextToken(Lexer::T_AS)) { + $this->match(Lexer::T_AS); + } + if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { + $this->match(Lexer::T_IDENTIFIER); + $expr->setFieldIdentificationVariable($this->_lexer->token['value']); + } + return $expr; + } + } + + /** + * Literal ::= string | char | integer | float | boolean | InputParameter + */ + public function _Literal() + { + switch ($this->_lexer->lookahead['type']) { + case Lexer::T_INPUT_PARAMETER: + $this->match($this->_lexer->lookahead['value']); + return new AST\InputParameter($this->_lexer->token['value']); + case Lexer::T_STRING: + case Lexer::T_INTEGER: + case Lexer::T_FLOAT: + $this->match($this->_lexer->lookahead['value']); + return $this->_lexer->token['value']; + default: + $this->syntaxError('Literal'); + } + } + + /** + * BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression + */ + public function _BetweenExpression() + { + $not = false; + $arithExpr1 = $this->_ArithmeticExpression(); + if ($this->_lexer->isNextToken(Lexer::T_NOT)) { + $this->match(Lexer::T_NOT); + $not = true; + } + $this->match(Lexer::T_BETWEEN); + $arithExpr2 = $this->_ArithmeticExpression(); + $this->match(Lexer::T_AND); + $arithExpr3 = $this->_ArithmeticExpression(); + + $betweenExpr = new AST\BetweenExpression($arithExpr1, $arithExpr2, $arithExpr3); + $betweenExpr->setNot($not); + + return $betweenExpr; + } + + /** + * ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")" | Function | AggregateExpression + * @todo Implementation incomplete. + */ + public function _ArithmeticPrimary() + { + if ($this->_lexer->lookahead['value'] === '(') { + $this->match('('); + $expr = $this->_SimpleArithmeticExpression(); + $this->match(')'); + return $expr; + } + + switch ($this->_lexer->lookahead['type']) { + case Lexer::T_IDENTIFIER: + $peek = $this->_lexer->glimpse(); + if ($peek['value'] == '(') { + return $this->_FunctionsReturningNumerics(); + } + return $this->_StateFieldPathExpression(); + case Lexer::T_INPUT_PARAMETER: + $this->match($this->_lexer->lookahead['value']); + return new AST\InputParameter($this->_lexer->token['value']); + case Lexer::T_STRING: + case Lexer::T_INTEGER: + case Lexer::T_FLOAT: + $this->match($this->_lexer->lookahead['value']); + return $this->_lexer->token['value']; + default: + $peek = $this->_lexer->glimpse(); + if ($peek['value'] == '(') { + if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { + return $this->_AggregateExpression(); + } + return $this->_FunctionsReturningStrings(); + } else { + $this->syntaxError(); + } + } + throw DoctrineException::updateMe("Not yet implemented2."); + //TODO... + } + + /** + * FunctionsReturningStrings ::= + * "CONCAT" "(" StringPrimary "," StringPrimary ")" | + * "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | + * "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" | + * "LOWER" "(" StringPrimary ")" | + * "UPPER" "(" StringPrimary ")" + */ + public function _FunctionsReturningStrings() + { + $funcNameLower = strtolower($this->_lexer->lookahead['value']); + $funcClass = self::$_STRING_FUNCTIONS[$funcNameLower]; + $function = new $funcClass($funcNameLower); + $function->parse($this); + return $function; + } + + /** + * FunctionsReturningNumerics ::= + * "LENGTH" "(" StringPrimary ")" | + * "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" | + * "ABS" "(" SimpleArithmeticExpression ")" | + * "SQRT" "(" SimpleArithmeticExpression ")" | + * "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" | + * "SIZE" "(" CollectionValuedPathExpression ")" + */ + public function _FunctionsReturningNumerics() + { + $funcNameLower = strtolower($this->_lexer->lookahead['value']); + $funcClass = self::$_NUMERIC_FUNCTIONS[$funcNameLower]; + $function = new $funcClass($funcNameLower); + $function->parse($this); + return $function; + } + + /** + * FunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP" + */ + public function _FunctionsReturningDatetime() + { + $funcNameLower = strtolower($this->_lexer->lookahead['value']); + $funcClass = self::$_DATETIME_FUNCTIONS[$funcNameLower]; + $function = new $funcClass($funcNameLower); + $function->parse($this); + return $function; + } + + /** + * Checks whether the given token type indicates an aggregate function. + */ + public function _isAggregateFunction($tokenType) + { + return $tokenType == Lexer::T_AVG || $tokenType == Lexer::T_MIN || + $tokenType == Lexer::T_MAX || $tokenType == Lexer::T_SUM || + $tokenType == Lexer::T_COUNT; + } + + /** + * ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!=" + */ + public function _ComparisonOperator() + { + switch ($this->_lexer->lookahead['value']) { + case '=': + $this->match('='); + return '='; + case '<': + $this->match('<'); + $operator = '<'; + if ($this->_lexer->isNextToken('=')) { + $this->match('='); + $operator .= '='; + } else if ($this->_lexer->isNextToken('>')) { + $this->match('>'); + $operator .= '>'; + } + return $operator; + case '>': + $this->match('>'); + $operator = '>'; + if ($this->_lexer->isNextToken('=')) { + $this->match('='); + $operator .= '='; + } + return $operator; + case '!': + $this->match('!'); + $this->match('='); + return '<>'; + default: + $this->syntaxError('=, <, <=, <>, >, >=, !='); + break; + } + } + + /** + * LikeExpression ::= StringExpression ["NOT"] "LIKE" (string | input_parameter) ["ESCAPE" char] + */ + public function _LikeExpression() + { + $stringExpr = $this->_StringExpression(); + $isNot = false; + if ($this->_lexer->lookahead['type'] === Lexer::T_NOT) { + $this->match(Lexer::T_NOT); + $isNot = true; + } + $this->match(Lexer::T_LIKE); + if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) { + $this->match(Lexer::T_INPUT_PARAMETER); + $stringPattern = new AST\InputParameter($this->_lexer->token['value']); + } else { + $this->match(Lexer::T_STRING); + $stringPattern = $this->_lexer->token['value']; + } + $escapeChar = null; + if ($this->_lexer->lookahead['type'] === Lexer::T_ESCAPE) { + $this->match(Lexer::T_ESCAPE); + $this->match(Lexer::T_STRING); + $escapeChar = $this->_lexer->token['value']; + } + + return new AST\LikeExpression($stringExpr, $stringPattern, $isNot, $escapeChar); + } + + /** + * StringExpression ::= StringPrimary | "(" Subselect ")" + */ + public function _StringExpression() + { + if ($this->_lexer->lookahead['value'] === '(') { + $peek = $this->_lexer->glimpse(); + if ($peek['type'] === Lexer::T_SELECT) { + $this->match('('); + $expr = $this->_Subselect(); + $this->match(')'); + return $expr; + } + } + return $this->_StringPrimary(); + } + + /** + * StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression + */ + public function _StringPrimary() + { + if ($this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) { + $peek = $this->_lexer->glimpse(); + if ($peek['value'] == '.') { + return $this->_StateFieldPathExpression(); + } else if ($peek['value'] == '(') { + return $this->_FunctionsReturningStrings(); + } else { + $this->syntaxError("'.' or '('"); + } + } else if ($this->_lexer->lookahead['type'] === Lexer::T_STRING) { + $this->match(Lexer::T_STRING); + return $this->_lexer->token['value']; + } else if ($this->_lexer->lookahead['type'] === Lexer::T_INPUT_PARAMETER) { + $this->match(Lexer::T_INPUT_PARAMETER); + return new AST\InputParameter($this->_lexer->token['value']); + } else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { + return $this->_AggregateExpression(); + } else { + $this->syntaxError('StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression'); + } + } + + /** + * Registers a custom function that returns strings. + * + * @param string $name The function name. + * @param string $class The class name of the function implementation. + */ + public static function registerStringFunction($name, $class) + { + self::$_STRING_FUNCTIONS[$name] = $class; + } + + /** + * Registers a custom function that returns numerics. + * + * @param string $name The function name. + * @param string $class The class name of the function implementation. + */ + public static function registerNumericFunction($name, $class) + { + self::$_NUMERIC_FUNCTIONS[$name] = $class; + } + + /** + * Registers a custom function that returns date/time values. + * + * @param string $name The function name. + * @param string $class The class name of the function implementation. + */ + public static function registerDatetimeFunction($name, $class) + { + self::$_DATETIME_FUNCTIONS[$name] = $class; + } } \ No newline at end of file diff --git a/lib/vendor/addendum/annotations.php b/lib/vendor/addendum/annotations.php index 06cafe912..9728950d7 100755 --- a/lib/vendor/addendum/annotations.php +++ b/lib/vendor/addendum/annotations.php @@ -1,341 +1,341 @@ - - - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - **/ - - require_once(dirname(__FILE__).'/annotations/annotation_parser.php'); - - class Annotation { - public $value; - - public final function __construct($data, $target) { - $reflection = new ReflectionClass($this); - foreach($data as $key => $value) { - if($reflection->hasProperty($key)) { - $this->$key = $value; - } else { - $class = $reflection->getName(); - trigger_error("Property '$key' not defined for annotation '$class'"); - } - } - $this->checkTargetConstraints($target); - $this->checkConstraints($target); - } - - private function checkTargetConstraints($target) { - $reflection = new ReflectionAnnotatedClass($this); - if($reflection->hasAnnotation('Target')) { - $value = $reflection->getAnnotation('Target')->value; - $values = is_array($value) ? $value : array($value); - foreach($values as $value) { - if($value == 'class' && $target instanceof ReflectionClass) return; - if($value == 'method' && $target instanceof ReflectionMethod) return; - if($value == 'property' && $target instanceof ReflectionProperty) return; - } - trigger_error("Annotation '".get_class($this)."' not allowed on ".$this->createName($target), E_USER_ERROR); - } - } - - private function createName($target) { - if($target instanceof ReflectionMethod) { - return $target->getDeclaringClass()->getName().'::'.$target->getName(); - } elseif($target instanceof ReflectionProperty) { - return $target->getDeclaringClass()->getName().'::$'.$target->getName(); - } else { - return $target->getName(); - } - } - - protected function checkConstraints($target) {} - } - - class Target extends Annotation {} - - class AnnotationsBuilder { - private static $cache = array(); - - public function build($targetReflection) { - $data = $this->parse($targetReflection); - $annotations = array(); - foreach($data as $class => $parameters) { - if(!Addendum::ignores($class)) { - foreach($parameters as $params) { - $annotationReflection = new ReflectionClass($class); - $annotations[$class][] = $annotationReflection->newInstance($params, $targetReflection); - } - } - } - return $annotations; - } - - private function parse($reflection) { - $key = $this->createName($reflection); - if(!isset(self::$cache[$key])) { - $parser = new AnnotationsMatcher; - $parser->matches($this->getDocComment($reflection), $data); - self::$cache[$key] = $data; - } - return self::$cache[$key]; - } - - private function createName($target) { - if($target instanceof ReflectionMethod) { - return $target->getDeclaringClass()->getName().'::'.$target->getName(); - } elseif($target instanceof ReflectionProperty) { - return $target->getDeclaringClass()->getName().'::$'.$target->getName(); - } else { - return $target->getName(); - } - } - - protected function getDocComment($reflection) { - return Addendum::getDocComment($reflection); - } - - public static function clearCache() { - self::$cache = array(); - } - } - - class ReflectionAnnotatedClass extends ReflectionClass { - private $annotations; - - public function __construct($class) { - parent::__construct($class); - $this->annotations = $this->createAnnotationBuilder()->build($this); - } - - public function hasAnnotation($annotation) { - return isset($this->annotations[$annotation]); - } - - public function getAnnotation($annotation) { - return $this->hasAnnotation($annotation) ? end($this->annotations[$annotation]) : false; - } - - public function getAnnotations() { - $result = array(); - foreach($this->annotations as $instances) { - $result[] = end($instances); - } - return $result; - } - - public function getAllAnnotations($restriction = false) { - $result = array(); - foreach($this->annotations as $class => $instances) { - if(!$restriction || $restriction == $class) { - $result = array_merge($result, $instances); - } - } - return $result; - } - - public function getConstructor() { - return $this->createReflectionAnnotatedMethod(parent::getConstructor()); - } - - public function getMethod($name) { - return $this->createReflectionAnnotatedMethod(parent::getMethod($name)); - } - - public function getMethods($filter = -1) { - $result = array(); - foreach(parent::getMethods($filter) as $method) { - $result[] = $this->createReflectionAnnotatedMethod($method); - } - return $result; - } - - public function getProperty($name) { - return $this->createReflectionAnnotatedProperty(parent::getProperty($name)); - } - - public function getProperties($filter = -1) { - $result = array(); - foreach(parent::getProperties($filter) as $property) { - $result[] = $this->createReflectionAnnotatedProperty($property); - } - return $result; - } - - public function getInterfaces() { - $result = array(); - foreach(parent::getInterfaces() as $interface) { - $result[] = $this->createReflectionAnnotatedClass($interface); - } - return $result; - } - - public function getParentClass() { - $class = parent::getParentClass(); - return $this->createReflectionAnnotatedClass($class); - } - - protected function createAnnotationBuilder() { - return new AnnotationsBuilder(); - } - - private function createReflectionAnnotatedClass($class) { - return ($class !== false) ? new ReflectionAnnotatedClass($class->getName()) : false; - } - - private function createReflectionAnnotatedMethod($method) { - return ($method !== null) ? new ReflectionAnnotatedMethod($this->getName(), $method->getName()) : null; - } - - private function createReflectionAnnotatedProperty($property) { - return ($property !== null) ? new ReflectionAnnotatedProperty($this->getName(), $property->getName()) : null; - } - } - - class ReflectionAnnotatedMethod extends ReflectionMethod { - private $annotations; - - public function __construct($class, $name) { - parent::__construct($class, $name); - $this->annotations = $this->createAnnotationBuilder()->build($this); - } - - public function hasAnnotation($annotation) { - return isset($this->annotations[$annotation]); - } - - public function getAnnotation($annotation) { - return ($this->hasAnnotation($annotation)) ? end($this->annotations[$annotation]) : false; - } - - public function getAnnotations() { - $result = array(); - foreach($this->annotations as $instances) { - $result[] = end($instances); - } - return $result; - } - - public function getAllAnnotations($restriction = false) { - $result = array(); - foreach($this->annotations as $class => $instances) { - if(!$restriction || $restriction == $class) { - $result = array_merge($result, $instances); - } - } - return $result; - } - - public function getDeclaringClass() { - $class = parent::getDeclaringClass(); - return new ReflectionAnnotatedClass($class->getName()); - } - - protected function createAnnotationBuilder() { - return new AnnotationsBuilder(); - } - } - - class ReflectionAnnotatedProperty extends ReflectionProperty { - private $annotations; - - public function __construct($class, $name) { - parent::__construct($class, $name); - $this->annotations = $this->createAnnotationBuilder()->build($this); - } - - public function hasAnnotation($annotation) { - return isset($this->annotations[$annotation]); - } - - public function getAnnotation($annotation) { - return ($this->hasAnnotation($annotation)) ? end($this->annotations[$annotation]) : false; - } - - public function getAnnotations() { - $result = array(); - foreach($this->annotations as $instances) { - $result[] = end($instances); - } - return $result; - } - - public function getAllAnnotations($restriction = false) { - $result = array(); - foreach($this->annotations as $class => $instances) { - if(!$restriction || $restriction == $class) { - $result = array_merge($result, $instances); - } - } - return $result; - } - - public function getDeclaringClass() { - $class = parent::getDeclaringClass(); - return new ReflectionAnnotatedClass($class->getName()); - } - - protected function createAnnotationBuilder() { - return new AnnotationsBuilder(); - } - } - - class Addendum { - private static $rawMode; - private static $ignore; - - public static function getDocComment($reflection) { - if(self::checkRawDocCommentParsingNeeded()) { - $docComment = new DocComment(); - return $docComment->get($reflection); - } else { - return $reflection->getDocComment(); - } - } - - /** Raw mode test */ - private static function checkRawDocCommentParsingNeeded() { - if(self::$rawMode === null) { - $reflection = new ReflectionClass('Addendum'); - $method = $reflection->getMethod('checkRawDocCommentParsingNeeded'); - self::setRawMode($method->getDocComment() === false); - } - return self::$rawMode; - } - - public static function setRawMode($enabled = true) { - if($enabled) { - require_once(dirname(__FILE__).'/annotations/doc_comment.php'); - } - self::$rawMode = $enabled; - } - - public static function resetIgnoredAnnotations() { - self::$ignore = array(); - } - - public static function ignores($class) { - return isset(self::$ignore[$class]); - } - - public static function ignore() { - foreach(func_get_args() as $class) { - self::$ignore[$class] = true; - } - } - } -?> + + + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + **/ + + require_once(dirname(__FILE__).'/annotations/annotation_parser.php'); + + class Annotation { + public $value; + + public final function __construct($data, $target) { + $reflection = new ReflectionClass($this); + foreach($data as $key => $value) { + if($reflection->hasProperty($key)) { + $this->$key = $value; + } else { + $class = $reflection->getName(); + trigger_error("Property '$key' not defined for annotation '$class'"); + } + } + $this->checkTargetConstraints($target); + $this->checkConstraints($target); + } + + private function checkTargetConstraints($target) { + $reflection = new ReflectionAnnotatedClass($this); + if($reflection->hasAnnotation('Target')) { + $value = $reflection->getAnnotation('Target')->value; + $values = is_array($value) ? $value : array($value); + foreach($values as $value) { + if($value == 'class' && $target instanceof ReflectionClass) return; + if($value == 'method' && $target instanceof ReflectionMethod) return; + if($value == 'property' && $target instanceof ReflectionProperty) return; + } + trigger_error("Annotation '".get_class($this)."' not allowed on ".$this->createName($target), E_USER_ERROR); + } + } + + private function createName($target) { + if($target instanceof ReflectionMethod) { + return $target->getDeclaringClass()->getName().'::'.$target->getName(); + } elseif($target instanceof ReflectionProperty) { + return $target->getDeclaringClass()->getName().'::$'.$target->getName(); + } else { + return $target->getName(); + } + } + + protected function checkConstraints($target) {} + } + + class Target extends Annotation {} + + class AnnotationsBuilder { + private static $cache = array(); + + public function build($targetReflection) { + $data = $this->parse($targetReflection); + $annotations = array(); + foreach($data as $class => $parameters) { + if(!Addendum::ignores($class)) { + foreach($parameters as $params) { + $annotationReflection = new ReflectionClass($class); + $annotations[$class][] = $annotationReflection->newInstance($params, $targetReflection); + } + } + } + return $annotations; + } + + private function parse($reflection) { + $key = $this->createName($reflection); + if(!isset(self::$cache[$key])) { + $parser = new AnnotationsMatcher; + $parser->matches($this->getDocComment($reflection), $data); + self::$cache[$key] = $data; + } + return self::$cache[$key]; + } + + private function createName($target) { + if($target instanceof ReflectionMethod) { + return $target->getDeclaringClass()->getName().'::'.$target->getName(); + } elseif($target instanceof ReflectionProperty) { + return $target->getDeclaringClass()->getName().'::$'.$target->getName(); + } else { + return $target->getName(); + } + } + + protected function getDocComment($reflection) { + return Addendum::getDocComment($reflection); + } + + public static function clearCache() { + self::$cache = array(); + } + } + + class ReflectionAnnotatedClass extends ReflectionClass { + private $annotations; + + public function __construct($class) { + parent::__construct($class); + $this->annotations = $this->createAnnotationBuilder()->build($this); + } + + public function hasAnnotation($annotation) { + return isset($this->annotations[$annotation]); + } + + public function getAnnotation($annotation) { + return $this->hasAnnotation($annotation) ? end($this->annotations[$annotation]) : false; + } + + public function getAnnotations() { + $result = array(); + foreach($this->annotations as $instances) { + $result[] = end($instances); + } + return $result; + } + + public function getAllAnnotations($restriction = false) { + $result = array(); + foreach($this->annotations as $class => $instances) { + if(!$restriction || $restriction == $class) { + $result = array_merge($result, $instances); + } + } + return $result; + } + + public function getConstructor() { + return $this->createReflectionAnnotatedMethod(parent::getConstructor()); + } + + public function getMethod($name) { + return $this->createReflectionAnnotatedMethod(parent::getMethod($name)); + } + + public function getMethods($filter = -1) { + $result = array(); + foreach(parent::getMethods($filter) as $method) { + $result[] = $this->createReflectionAnnotatedMethod($method); + } + return $result; + } + + public function getProperty($name) { + return $this->createReflectionAnnotatedProperty(parent::getProperty($name)); + } + + public function getProperties($filter = -1) { + $result = array(); + foreach(parent::getProperties($filter) as $property) { + $result[] = $this->createReflectionAnnotatedProperty($property); + } + return $result; + } + + public function getInterfaces() { + $result = array(); + foreach(parent::getInterfaces() as $interface) { + $result[] = $this->createReflectionAnnotatedClass($interface); + } + return $result; + } + + public function getParentClass() { + $class = parent::getParentClass(); + return $this->createReflectionAnnotatedClass($class); + } + + protected function createAnnotationBuilder() { + return new AnnotationsBuilder(); + } + + private function createReflectionAnnotatedClass($class) { + return ($class !== false) ? new ReflectionAnnotatedClass($class->getName()) : false; + } + + private function createReflectionAnnotatedMethod($method) { + return ($method !== null) ? new ReflectionAnnotatedMethod($this->getName(), $method->getName()) : null; + } + + private function createReflectionAnnotatedProperty($property) { + return ($property !== null) ? new ReflectionAnnotatedProperty($this->getName(), $property->getName()) : null; + } + } + + class ReflectionAnnotatedMethod extends ReflectionMethod { + private $annotations; + + public function __construct($class, $name) { + parent::__construct($class, $name); + $this->annotations = $this->createAnnotationBuilder()->build($this); + } + + public function hasAnnotation($annotation) { + return isset($this->annotations[$annotation]); + } + + public function getAnnotation($annotation) { + return ($this->hasAnnotation($annotation)) ? end($this->annotations[$annotation]) : false; + } + + public function getAnnotations() { + $result = array(); + foreach($this->annotations as $instances) { + $result[] = end($instances); + } + return $result; + } + + public function getAllAnnotations($restriction = false) { + $result = array(); + foreach($this->annotations as $class => $instances) { + if(!$restriction || $restriction == $class) { + $result = array_merge($result, $instances); + } + } + return $result; + } + + public function getDeclaringClass() { + $class = parent::getDeclaringClass(); + return new ReflectionAnnotatedClass($class->getName()); + } + + protected function createAnnotationBuilder() { + return new AnnotationsBuilder(); + } + } + + class ReflectionAnnotatedProperty extends ReflectionProperty { + private $annotations; + + public function __construct($class, $name) { + parent::__construct($class, $name); + $this->annotations = $this->createAnnotationBuilder()->build($this); + } + + public function hasAnnotation($annotation) { + return isset($this->annotations[$annotation]); + } + + public function getAnnotation($annotation) { + return ($this->hasAnnotation($annotation)) ? end($this->annotations[$annotation]) : false; + } + + public function getAnnotations() { + $result = array(); + foreach($this->annotations as $instances) { + $result[] = end($instances); + } + return $result; + } + + public function getAllAnnotations($restriction = false) { + $result = array(); + foreach($this->annotations as $class => $instances) { + if(!$restriction || $restriction == $class) { + $result = array_merge($result, $instances); + } + } + return $result; + } + + public function getDeclaringClass() { + $class = parent::getDeclaringClass(); + return new ReflectionAnnotatedClass($class->getName()); + } + + protected function createAnnotationBuilder() { + return new AnnotationsBuilder(); + } + } + + class Addendum { + private static $rawMode; + private static $ignore; + + public static function getDocComment($reflection) { + if(self::checkRawDocCommentParsingNeeded()) { + $docComment = new DocComment(); + return $docComment->get($reflection); + } else { + return $reflection->getDocComment(); + } + } + + /** Raw mode test */ + private static function checkRawDocCommentParsingNeeded() { + if(self::$rawMode === null) { + $reflection = new ReflectionClass('Addendum'); + $method = $reflection->getMethod('checkRawDocCommentParsingNeeded'); + self::setRawMode($method->getDocComment() === false); + } + return self::$rawMode; + } + + public static function setRawMode($enabled = true) { + if($enabled) { + require_once(dirname(__FILE__).'/annotations/doc_comment.php'); + } + self::$rawMode = $enabled; + } + + public static function resetIgnoredAnnotations() { + self::$ignore = array(); + } + + public static function ignores($class) { + return isset(self::$ignore[$class]); + } + + public static function ignore() { + foreach(func_get_args() as $class) { + self::$ignore[$class] = true; + } + } + } +?> diff --git a/lib/vendor/addendum/annotations/annotation_parser.php b/lib/vendor/addendum/annotations/annotation_parser.php index a951ceaff..5d7c41d9c 100755 --- a/lib/vendor/addendum/annotations/annotation_parser.php +++ b/lib/vendor/addendum/annotations/annotation_parser.php @@ -1,335 +1,335 @@ - - - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - **/ - - class CompositeMatcher { - protected $matchers = array(); - private $wasConstructed = false; - - public function add($matcher) { - $this->matchers[] = $matcher; - } - - public function matches($string, &$value) { - if(!$this->wasConstructed) { - $this->build(); - $this->wasConstructed = true; - } - return $this->match($string, $value); - } - - protected function build() {} - } - - class ParallelMatcher extends CompositeMatcher { - protected function match($string, &$value) { - $maxLength = false; - $result = null; - foreach($this->matchers as $matcher) { - $length = $matcher->matches($string, $subvalue); - if($maxLength === false || $length > $maxLength) { - $maxLength = $length; - $result = $subvalue; - } - } - $value = $this->process($result); - return $maxLength; - } - - protected function process($value) { - return $value; - } - } - - class SerialMatcher extends CompositeMatcher { - protected function match($string, &$value) { - $results = array(); - $total_length = 0; - foreach($this->matchers as $matcher) { - if(($length = $matcher->matches($string, $result)) === false) return false; - $total_length += $length; - $results[] = $result; - $string = substr($string, $length); - } - $value = $this->process($results); - return $total_length; - } - - protected function process($results) { - return implode('', $results); - } - } - - class SimpleSerialMatcher extends SerialMatcher { - private $return_part_index; - - public function __construct($return_part_index = 0) { - $this->return_part_index = $return_part_index; - } - - public function process($parts) { - return $parts[$this->return_part_index]; - } - } - - class RegexMatcher { - private $regex; - - public function __construct($regex) { - $this->regex = $regex; - } - - public function matches($string, &$value) { - if(preg_match("/^{$this->regex}/", $string, $matches)) { - $value = $this->process($matches); - return strlen($matches[0]); - } - $value = false; - return false; - } - - protected function process($matches) { - return $matches[0]; - } - } - - class AnnotationsMatcher { - public function matches($string, &$annotations) { - $annotations = array(); - $annotation_matcher = new AnnotationMatcher; - while(true) { - if(preg_match('/\s(?=@)/', $string, $matches, PREG_OFFSET_CAPTURE)) { - $offset = $matches[0][1] + 1; - $string = substr($string, $offset); - } else { - return; // no more annotations - } - if(($length = $annotation_matcher->matches($string, $data)) !== false) { - $string = substr($string, $length); - list($name, $params) = $data; - $annotations[$name][] = $params; - } - } - } - } - - class AnnotationMatcher extends SerialMatcher { - protected function build() { - $this->add(new RegexMatcher('@')); - $this->add(new RegexMatcher('[A-Z][a-zA-Z0-9_]+')); - $this->add(new AnnotationParametersMatcher); - } - - protected function process($results) { - return array($results[1], $results[2]); - } - } - - class ConstantMatcher extends RegexMatcher { - private $constant; - - public function __construct($regex, $constant) { - parent::__construct($regex); - $this->constant = $constant; - } - - protected function process($matches) { - return $this->constant; - } - } - - class AnnotationParametersMatcher extends ParallelMatcher { - protected function build() { - $this->add(new ConstantMatcher('', array())); - $this->add(new ConstantMatcher('\(\)', array())); - $params_matcher = new SimpleSerialMatcher(1); - $params_matcher->add(new RegexMatcher('\(\s*')); - $params_matcher->add(new AnnotationValuesMatcher); - $params_matcher->add(new RegexMatcher('\s*\)')); - $this->add($params_matcher); - } - } - - class AnnotationValuesMatcher extends ParallelMatcher { - protected function build() { - $this->add(new AnnotationTopValueMatcher); - $this->add(new AnnotationHashMatcher); - } - } - - class AnnotationTopValueMatcher extends AnnotationValueMatcher { - protected function process($value) { - return array('value' => $value); - } - } - - class AnnotationValueMatcher extends ParallelMatcher { - protected function build() { - $this->add(new ConstantMatcher('true', true)); - $this->add(new ConstantMatcher('false', false)); - $this->add(new ConstantMatcher('TRUE', true)); - $this->add(new ConstantMatcher('FALSE', false)); - $this->add(new AnnotationStringMatcher); - $this->add(new AnnotationNumberMatcher); - $this->add(new AnnotationArrayMatcher); - } - } - - class AnnotationKeyMatcher extends ParallelMatcher { - protected function build() { - $this->add(new RegexMatcher('[a-zA-Z][a-zA-Z0-9_]*')); - $this->add(new AnnotationStringMatcher); - $this->add(new AnnotationIntegerMatcher); - } - } - - class AnnotationPairMatcher extends SerialMatcher { - protected function build() { - $this->add(new AnnotationKeyMatcher); - $this->add(new RegexMatcher('\s*=\s*')); - $this->add(new AnnotationValueMatcher); - } - - protected function process($parts) { - return array($parts[0] => $parts[2]); - } - } - - class AnnotationHashMatcher extends ParallelMatcher { - protected function build() { - $this->add(new AnnotationPairMatcher); - $this->add(new AnnotationMorePairsMatcher); - } - } - - class AnnotationMorePairsMatcher extends SerialMatcher { - protected function build() { - $this->add(new AnnotationPairMatcher); - $this->add(new RegexMatcher('\s*,\s*')); - $this->add(new AnnotationHashMatcher); - } - - protected function match($string, &$value) { - $result = parent::match($string, $value); - return $result; - } - - public function process($parts) { - return array_merge($parts[0], $parts[2]); - } - } - - class AnnotationArrayMatcher extends ParallelMatcher { - protected function build() { - $this->add(new ConstantMatcher('{}', array())); - $values_matcher = new SimpleSerialMatcher(1); - $values_matcher->add(new RegexMatcher('\s*{\s*')); - $values_matcher->add(new AnnotationArrayValuesMatcher); - $values_matcher->add(new RegexMatcher('\s*}\s*')); - $this->add($values_matcher); - } - } - - class AnnotationArrayValuesMatcher extends ParallelMatcher { - protected function build() { - $this->add(new AnnotationArrayValueMatcher); - $this->add(new AnnotationMoreValuesMatcher); - } - } - - class AnnotationMoreValuesMatcher extends SimpleSerialMatcher { - protected function build() { - $this->add(new AnnotationArrayValueMatcher); - $this->add(new RegexMatcher('\s*,\s*')); - $this->add(new AnnotationArrayValuesMatcher); - } - - protected function match($string, &$value) { - $result = parent::match($string, $value); - return $result; - } - - public function process($parts) { - return array_merge($parts[0], $parts[2]); - } - } - - class AnnotationArrayValueMatcher extends ParallelMatcher { - protected function build() { - $this->add(new AnnotationValueInArrayMatcher); - $this->add(new AnnotationPairMatcher); - } - } - - class AnnotationValueInArrayMatcher extends AnnotationValueMatcher { - public function process($value) { - return array($value); - } - } - - class AnnotationStringMatcher extends ParallelMatcher { - protected function build() { - $this->add(new AnnotationSingleQuotedStringMatcher); - $this->add(new AnnotationDoubleQuotedStringMatcher); - } - } - - class AnnotationNumberMatcher extends RegexMatcher { - public function __construct() { - parent::__construct("-?[0-9]*\.?[0-9]*"); - } - - protected function process($matches) { - $isFloat = strpos($matches[0], '.') !== false; - return $isFloat ? (float) $matches[0] : (int) $matches[0]; - } - } - - class AnnotationIntegerMatcher extends RegexMatcher { - public function __construct() { - parent::__construct("-?[0-9]*"); - } - - protected function process($matches) { - return (int) $matches[0]; - } - } - - class AnnotationSingleQuotedStringMatcher extends RegexMatcher { - public function __construct() { - parent::__construct("'([^']*)'"); - } - - protected function process($matches) { - return $matches[1]; - } - } - - class AnnotationDoubleQuotedStringMatcher extends RegexMatcher { - public function __construct() { - parent::__construct('"([^"]*)"'); - } - - protected function process($matches) { - return $matches[1]; - } - } -?> + + + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + **/ + + class CompositeMatcher { + protected $matchers = array(); + private $wasConstructed = false; + + public function add($matcher) { + $this->matchers[] = $matcher; + } + + public function matches($string, &$value) { + if(!$this->wasConstructed) { + $this->build(); + $this->wasConstructed = true; + } + return $this->match($string, $value); + } + + protected function build() {} + } + + class ParallelMatcher extends CompositeMatcher { + protected function match($string, &$value) { + $maxLength = false; + $result = null; + foreach($this->matchers as $matcher) { + $length = $matcher->matches($string, $subvalue); + if($maxLength === false || $length > $maxLength) { + $maxLength = $length; + $result = $subvalue; + } + } + $value = $this->process($result); + return $maxLength; + } + + protected function process($value) { + return $value; + } + } + + class SerialMatcher extends CompositeMatcher { + protected function match($string, &$value) { + $results = array(); + $total_length = 0; + foreach($this->matchers as $matcher) { + if(($length = $matcher->matches($string, $result)) === false) return false; + $total_length += $length; + $results[] = $result; + $string = substr($string, $length); + } + $value = $this->process($results); + return $total_length; + } + + protected function process($results) { + return implode('', $results); + } + } + + class SimpleSerialMatcher extends SerialMatcher { + private $return_part_index; + + public function __construct($return_part_index = 0) { + $this->return_part_index = $return_part_index; + } + + public function process($parts) { + return $parts[$this->return_part_index]; + } + } + + class RegexMatcher { + private $regex; + + public function __construct($regex) { + $this->regex = $regex; + } + + public function matches($string, &$value) { + if(preg_match("/^{$this->regex}/", $string, $matches)) { + $value = $this->process($matches); + return strlen($matches[0]); + } + $value = false; + return false; + } + + protected function process($matches) { + return $matches[0]; + } + } + + class AnnotationsMatcher { + public function matches($string, &$annotations) { + $annotations = array(); + $annotation_matcher = new AnnotationMatcher; + while(true) { + if(preg_match('/\s(?=@)/', $string, $matches, PREG_OFFSET_CAPTURE)) { + $offset = $matches[0][1] + 1; + $string = substr($string, $offset); + } else { + return; // no more annotations + } + if(($length = $annotation_matcher->matches($string, $data)) !== false) { + $string = substr($string, $length); + list($name, $params) = $data; + $annotations[$name][] = $params; + } + } + } + } + + class AnnotationMatcher extends SerialMatcher { + protected function build() { + $this->add(new RegexMatcher('@')); + $this->add(new RegexMatcher('[A-Z][a-zA-Z0-9_]+')); + $this->add(new AnnotationParametersMatcher); + } + + protected function process($results) { + return array($results[1], $results[2]); + } + } + + class ConstantMatcher extends RegexMatcher { + private $constant; + + public function __construct($regex, $constant) { + parent::__construct($regex); + $this->constant = $constant; + } + + protected function process($matches) { + return $this->constant; + } + } + + class AnnotationParametersMatcher extends ParallelMatcher { + protected function build() { + $this->add(new ConstantMatcher('', array())); + $this->add(new ConstantMatcher('\(\)', array())); + $params_matcher = new SimpleSerialMatcher(1); + $params_matcher->add(new RegexMatcher('\(\s*')); + $params_matcher->add(new AnnotationValuesMatcher); + $params_matcher->add(new RegexMatcher('\s*\)')); + $this->add($params_matcher); + } + } + + class AnnotationValuesMatcher extends ParallelMatcher { + protected function build() { + $this->add(new AnnotationTopValueMatcher); + $this->add(new AnnotationHashMatcher); + } + } + + class AnnotationTopValueMatcher extends AnnotationValueMatcher { + protected function process($value) { + return array('value' => $value); + } + } + + class AnnotationValueMatcher extends ParallelMatcher { + protected function build() { + $this->add(new ConstantMatcher('true', true)); + $this->add(new ConstantMatcher('false', false)); + $this->add(new ConstantMatcher('TRUE', true)); + $this->add(new ConstantMatcher('FALSE', false)); + $this->add(new AnnotationStringMatcher); + $this->add(new AnnotationNumberMatcher); + $this->add(new AnnotationArrayMatcher); + } + } + + class AnnotationKeyMatcher extends ParallelMatcher { + protected function build() { + $this->add(new RegexMatcher('[a-zA-Z][a-zA-Z0-9_]*')); + $this->add(new AnnotationStringMatcher); + $this->add(new AnnotationIntegerMatcher); + } + } + + class AnnotationPairMatcher extends SerialMatcher { + protected function build() { + $this->add(new AnnotationKeyMatcher); + $this->add(new RegexMatcher('\s*=\s*')); + $this->add(new AnnotationValueMatcher); + } + + protected function process($parts) { + return array($parts[0] => $parts[2]); + } + } + + class AnnotationHashMatcher extends ParallelMatcher { + protected function build() { + $this->add(new AnnotationPairMatcher); + $this->add(new AnnotationMorePairsMatcher); + } + } + + class AnnotationMorePairsMatcher extends SerialMatcher { + protected function build() { + $this->add(new AnnotationPairMatcher); + $this->add(new RegexMatcher('\s*,\s*')); + $this->add(new AnnotationHashMatcher); + } + + protected function match($string, &$value) { + $result = parent::match($string, $value); + return $result; + } + + public function process($parts) { + return array_merge($parts[0], $parts[2]); + } + } + + class AnnotationArrayMatcher extends ParallelMatcher { + protected function build() { + $this->add(new ConstantMatcher('{}', array())); + $values_matcher = new SimpleSerialMatcher(1); + $values_matcher->add(new RegexMatcher('\s*{\s*')); + $values_matcher->add(new AnnotationArrayValuesMatcher); + $values_matcher->add(new RegexMatcher('\s*}\s*')); + $this->add($values_matcher); + } + } + + class AnnotationArrayValuesMatcher extends ParallelMatcher { + protected function build() { + $this->add(new AnnotationArrayValueMatcher); + $this->add(new AnnotationMoreValuesMatcher); + } + } + + class AnnotationMoreValuesMatcher extends SimpleSerialMatcher { + protected function build() { + $this->add(new AnnotationArrayValueMatcher); + $this->add(new RegexMatcher('\s*,\s*')); + $this->add(new AnnotationArrayValuesMatcher); + } + + protected function match($string, &$value) { + $result = parent::match($string, $value); + return $result; + } + + public function process($parts) { + return array_merge($parts[0], $parts[2]); + } + } + + class AnnotationArrayValueMatcher extends ParallelMatcher { + protected function build() { + $this->add(new AnnotationValueInArrayMatcher); + $this->add(new AnnotationPairMatcher); + } + } + + class AnnotationValueInArrayMatcher extends AnnotationValueMatcher { + public function process($value) { + return array($value); + } + } + + class AnnotationStringMatcher extends ParallelMatcher { + protected function build() { + $this->add(new AnnotationSingleQuotedStringMatcher); + $this->add(new AnnotationDoubleQuotedStringMatcher); + } + } + + class AnnotationNumberMatcher extends RegexMatcher { + public function __construct() { + parent::__construct("-?[0-9]*\.?[0-9]*"); + } + + protected function process($matches) { + $isFloat = strpos($matches[0], '.') !== false; + return $isFloat ? (float) $matches[0] : (int) $matches[0]; + } + } + + class AnnotationIntegerMatcher extends RegexMatcher { + public function __construct() { + parent::__construct("-?[0-9]*"); + } + + protected function process($matches) { + return (int) $matches[0]; + } + } + + class AnnotationSingleQuotedStringMatcher extends RegexMatcher { + public function __construct() { + parent::__construct("'([^']*)'"); + } + + protected function process($matches) { + return $matches[1]; + } + } + + class AnnotationDoubleQuotedStringMatcher extends RegexMatcher { + public function __construct() { + parent::__construct('"([^"]*)"'); + } + + protected function process($matches) { + return $matches[1]; + } + } +?> diff --git a/lib/vendor/addendum/annotations/doc_comment.php b/lib/vendor/addendum/annotations/doc_comment.php index 169c9b038..1dcd24e20 100755 --- a/lib/vendor/addendum/annotations/doc_comment.php +++ b/lib/vendor/addendum/annotations/doc_comment.php @@ -1,130 +1,130 @@ -forClass($reflection); - } elseif($reflection instanceof ReflectionMethod) { - return $this->forMethod($reflection); - } elseif($reflection instanceof ReflectionProperty) { - return $this->forProperty($reflection); - } - } - - public function forClass($reflection) { - $this->process($reflection->getFileName()); - $name = $reflection->getName(); - return isset(self::$classes[$name]) ? self::$classes[$name] : false; - } - - public function forMethod($reflection) { - $this->process($reflection->getDeclaringClass()->getFileName()); - $class = $reflection->getDeclaringClass()->getName(); - $method = $reflection->getName(); - return isset(self::$methods[$class][$method]) ? self::$methods[$class][$method] : false; - } - - public function forProperty($reflection) { - $this->process($reflection->getDeclaringClass()->getFileName()); - $class = $reflection->getDeclaringClass()->getName(); - $field = $reflection->getName(); - return isset(self::$fields[$class][$field]) ? self::$fields[$class][$field] : false; - } - - private function process($file) { - if(!isset(self::$parsedFiles[$file])) { - $this->parse($file); - self::$parsedFiles[$file] = true; - } - } - - protected function parse($file) { - $tokens = $this->getTokens($file); - $currentClass = false; - $currentBlock = false; - $max = count($tokens); - $i = 0; - while($i < $max) { - $token = $tokens[$i]; - if(is_array($token)) { - list($code, $value) = $token; - switch($code) { - case T_DOC_COMMENT: - $comment = $value; - break; - - case T_CLASS: - $class = $this->getString($tokens, $i, $max); - if($comment !== false) { - self::$classes[$class] = $comment; - $comment = false; - } - break; - - case T_VARIABLE: - if($comment !== false) { - $field = substr($token[1], 1); - self::$fields[$class][$field] = $comment; - $comment = false; - } - break; - - case T_FUNCTION: - if($comment !== false) { - $function = $this->getString($tokens, $i, $max); - self::$methods[$class][$function] = $comment; - $comment = false; - } - - break; - - // ignore - case T_WHITESPACE: - case T_PUBLIC: - case T_PROTECTED: - case T_PRIVATE: - case T_ABSTRACT: - case T_FINAL: - case T_VAR: - break; - - default: - $comment = false; - break; - } - } else { - $comment = false; - } - $i++; - } - } - - private function getString($tokens, &$i, $max) { - do { - $token = $tokens[$i]; - $i++; - if(is_array($token)) { - if($token[0] == T_STRING) { - return $token[1]; - } - } - } while($i <= $max); - return false; - } - - private function getTokens($file) { - return token_get_all(file_get_contents($file)); - } - } +forClass($reflection); + } elseif($reflection instanceof ReflectionMethod) { + return $this->forMethod($reflection); + } elseif($reflection instanceof ReflectionProperty) { + return $this->forProperty($reflection); + } + } + + public function forClass($reflection) { + $this->process($reflection->getFileName()); + $name = $reflection->getName(); + return isset(self::$classes[$name]) ? self::$classes[$name] : false; + } + + public function forMethod($reflection) { + $this->process($reflection->getDeclaringClass()->getFileName()); + $class = $reflection->getDeclaringClass()->getName(); + $method = $reflection->getName(); + return isset(self::$methods[$class][$method]) ? self::$methods[$class][$method] : false; + } + + public function forProperty($reflection) { + $this->process($reflection->getDeclaringClass()->getFileName()); + $class = $reflection->getDeclaringClass()->getName(); + $field = $reflection->getName(); + return isset(self::$fields[$class][$field]) ? self::$fields[$class][$field] : false; + } + + private function process($file) { + if(!isset(self::$parsedFiles[$file])) { + $this->parse($file); + self::$parsedFiles[$file] = true; + } + } + + protected function parse($file) { + $tokens = $this->getTokens($file); + $currentClass = false; + $currentBlock = false; + $max = count($tokens); + $i = 0; + while($i < $max) { + $token = $tokens[$i]; + if(is_array($token)) { + list($code, $value) = $token; + switch($code) { + case T_DOC_COMMENT: + $comment = $value; + break; + + case T_CLASS: + $class = $this->getString($tokens, $i, $max); + if($comment !== false) { + self::$classes[$class] = $comment; + $comment = false; + } + break; + + case T_VARIABLE: + if($comment !== false) { + $field = substr($token[1], 1); + self::$fields[$class][$field] = $comment; + $comment = false; + } + break; + + case T_FUNCTION: + if($comment !== false) { + $function = $this->getString($tokens, $i, $max); + self::$methods[$class][$function] = $comment; + $comment = false; + } + + break; + + // ignore + case T_WHITESPACE: + case T_PUBLIC: + case T_PROTECTED: + case T_PRIVATE: + case T_ABSTRACT: + case T_FINAL: + case T_VAR: + break; + + default: + $comment = false; + break; + } + } else { + $comment = false; + } + $i++; + } + } + + private function getString($tokens, &$i, $max) { + do { + $token = $tokens[$i]; + $i++; + if(is_array($token)) { + if($token[0] == T_STRING) { + return $token[1]; + } + } + } while($i <= $max); + return false; + } + + private function getTokens($file) { + return token_get_all(file_get_contents($file)); + } + } ?> \ No newline at end of file diff --git a/lib/vendor/addendum/annotations/tests/acceptance_test.php b/lib/vendor/addendum/annotations/tests/acceptance_test.php index fd58cfd30..e5597a86e 100755 --- a/lib/vendor/addendum/annotations/tests/acceptance_test.php +++ b/lib/vendor/addendum/annotations/tests/acceptance_test.php @@ -1,233 +1,233 @@ -assertTrue($reflection->hasAnnotation('FirstAnnotation')); - $this->assertTrue($reflection->hasAnnotation('SecondAnnotation')); - $this->assertFalse($reflection->hasAnnotation('NonExistentAnnotation')); - $this->assertIsA($reflection->getAnnotation('FirstAnnotation'), 'FirstAnnotation'); - $this->assertIsA($reflection->getAnnotation('SecondAnnotation'), 'SecondAnnotation'); - - $annotations = $reflection->getAnnotations(); - $this->assertEqual(count($annotations), 2); - $this->assertIsA($annotations[0], 'FirstAnnotation'); - $this->assertIsA($annotations[1], 'SecondAnnotation'); - $this->assertFalse($reflection->getAnnotation('NonExistentAnnotation')); - - $this->assertIsA($reflection->getConstructor(), 'ReflectionAnnotatedMethod'); - $this->assertIsA($reflection->getMethod('exampleMethod'), 'ReflectionAnnotatedMethod'); - foreach($reflection->getMethods() as $method) { - $this->assertIsA($method, 'ReflectionAnnotatedMethod'); - } - - $this->assertIsA($reflection->getProperty('exampleProperty'), 'ReflectionAnnotatedProperty'); - foreach($reflection->getProperties() as $property) { - $this->assertIsA($property, 'ReflectionAnnotatedProperty'); - } - - foreach($reflection->getInterfaces() as $interface) { - $this->assertIsA($interface, 'ReflectionAnnotatedClass'); - } - - $this->assertIsA($reflection->getParentClass(), 'ReflectionAnnotatedClass'); - } - - public function testReflectionAnnotatedMethod() { - $reflection = new ReflectionAnnotatedMethod('Example', 'exampleMethod'); - $this->assertTrue($reflection->hasAnnotation('FirstAnnotation')); - $this->assertFalse($reflection->hasAnnotation('NonExistentAnnotation')); - $this->assertIsA($reflection->getAnnotation('FirstAnnotation'), 'FirstAnnotation'); - $this->assertFalse($reflection->getAnnotation('NonExistentAnnotation')); - - $annotations = $reflection->getAnnotations(); - $this->assertEqual(count($annotations), 1); - $this->assertIsA($annotations[0], 'FirstAnnotation'); - - $this->assertIsA($reflection->getDeclaringClass(), 'ReflectionAnnotatedClass'); - } - - public function testReflectionAnnotatedProperty() { - $reflection = new ReflectionAnnotatedProperty('Example', 'exampleProperty'); - $this->assertTrue($reflection->hasAnnotation('SecondAnnotation')); - $this->assertFalse($reflection->hasAnnotation('FirstAnnotation')); - $this->assertIsA($reflection->getAnnotation('SecondAnnotation'), 'SecondAnnotation'); - $this->assertFalse($reflection->getAnnotation('NonExistentAnnotation')); - - $annotations = $reflection->getAnnotations(); - $this->assertEqual(count($annotations), 1); - $this->assertIsA($annotations[0], 'SecondAnnotation'); - - $this->assertIsA($reflection->getDeclaringClass(), 'ReflectionAnnotatedClass'); - } - - public function testReflectionClassCanFilterMethodsByAccess() { - $reflection = new ReflectionAnnotatedClass('Example'); - $privateMethods = $reflection->getMethods(ReflectionMethod::IS_PRIVATE); - $this->assertEqual(count($privateMethods), 1); - $this->assertEqual($privateMethods[0]->getName(), 'justPrivate'); - } - - public function testReflectionClassCanFilterPropertiesByAccess() { - $reflection = new ReflectionAnnotatedClass('Example'); - $privateProperties = $reflection->getProperties(ReflectionProperty::IS_PUBLIC); - $this->assertEqual(count($privateProperties), 1); - $this->assertEqual($privateProperties[0]->getName(), 'publicOne'); - } - - public function testReflectionClassShouldReturnAllMethodsWithNoFilter() { - $reflection = new ReflectionAnnotatedClass('Example'); - $methods = $reflection->getMethods(); - $this->assertEqual(count($methods), 3); - } - - public function testReflectionClassShouldReturnAllPropertiesWithNoFilter() { - $reflection = new ReflectionAnnotatedClass('Example'); - $properties = $reflection->getProperties(); - $this->assertEqual(count($properties), 2); - } - - public function testMultipleAnnotationsOnClass() { - $reflection = new ReflectionAnnotatedClass('MultiExample'); - $annotations = $reflection->getAllAnnotations(); - $this->assertEqual(count($annotations), 3); - $this->assertEqual($annotations[0]->value, 1); - $this->assertEqual($annotations[1]->value, 2); - $this->assertEqual($annotations[2]->value, 3); - $this->assertIsA($annotations[0], 'FirstAnnotation'); - $this->assertIsA($annotations[1], 'FirstAnnotation'); - $this->assertIsA($annotations[2], 'SecondAnnotation'); - } - - public function testMultipleAnnotationsOnClassWithRestriction() { - $reflection = new ReflectionAnnotatedClass('MultiExample'); - $annotations = $reflection->getAllAnnotations('FirstAnnotation'); - $this->assertEqual(count($annotations), 2); - $this->assertEqual($annotations[0]->value, 1); - $this->assertEqual($annotations[1]->value, 2); - $this->assertIsA($annotations[0], 'FirstAnnotation'); - $this->assertIsA($annotations[1], 'FirstAnnotation'); - } - - public function testMultipleAnnotationsOnProperty() { - $reflection = new ReflectionAnnotatedClass('MultiExample'); - $reflection = $reflection->getProperty('property'); - $annotations = $reflection->getAllAnnotations(); - $this->assertEqual(count($annotations), 3); - $this->assertEqual($annotations[0]->value, 1); - $this->assertEqual($annotations[1]->value, 2); - $this->assertEqual($annotations[2]->value, 3); - $this->assertIsA($annotations[0], 'FirstAnnotation'); - $this->assertIsA($annotations[1], 'FirstAnnotation'); - $this->assertIsA($annotations[2], 'SecondAnnotation'); - } - - public function testMultipleAnnotationsOnPropertyWithRestriction() { - $reflection = new ReflectionAnnotatedClass('MultiExample'); - $reflection = $reflection->getProperty('property'); - $annotations = $reflection->getAllAnnotations('FirstAnnotation'); - $this->assertEqual(count($annotations), 2); - $this->assertEqual($annotations[0]->value, 1); - $this->assertEqual($annotations[1]->value, 2); - $this->assertIsA($annotations[0], 'FirstAnnotation'); - $this->assertIsA($annotations[1], 'FirstAnnotation'); - } - - public function testMultipleAnnotationsOnMethod() { - $reflection = new ReflectionAnnotatedClass('MultiExample'); - $reflection = $reflection->getMethod('aMethod'); - $annotations = $reflection->getAllAnnotations(); - $this->assertEqual(count($annotations), 3); - $this->assertEqual($annotations[0]->value, 1); - $this->assertEqual($annotations[1]->value, 2); - $this->assertEqual($annotations[2]->value, 3); - $this->assertIsA($annotations[0], 'FirstAnnotation'); - $this->assertIsA($annotations[1], 'FirstAnnotation'); - $this->assertIsA($annotations[2], 'SecondAnnotation'); - } - - public function testMultipleAnnotationsOnMethodWithRestriction() { - $reflection = new ReflectionAnnotatedClass('MultiExample'); - $reflection = $reflection->getMethod('aMethod'); - $annotations = $reflection->getAllAnnotations('FirstAnnotation'); - $this->assertEqual(count($annotations), 2); - $this->assertEqual($annotations[0]->value, 1); - $this->assertEqual($annotations[1]->value, 2); - $this->assertIsA($annotations[0], 'FirstAnnotation'); - $this->assertIsA($annotations[1], 'FirstAnnotation'); - } - } - - Mock::generatePartial('AnnotationsBuilder', 'MockedAnnotationsBuilder', array('getDocComment')); - - class TestOfPerformanceFeatures extends UnitTestCase { - public function setUp() { - AnnotationsBuilder::clearCache(); - } - - public function tearDown() { - AnnotationsBuilder::clearCache(); - } - - public function testBuilderShouldCacheResults() { - $builder = new MockedAnnotationsBuilder; - $reflection = new ReflectionClass('Example'); - $builder->build($reflection); - $builder->build($reflection); - $builder->expectOnce('getDocComment'); - } - } - - class TestOfSupportingFeatures extends UnitTestCase { - public function setUp() { - Addendum::resetIgnoredAnnotations(); - } - - public function tearDown() { - Addendum::resetIgnoredAnnotations(); - } - - public function testIgnoredAnnotationsAreNotUsed() { - Addendum::ignore('FirstAnnotation', 'SecondAnnotation'); - $reflection = new ReflectionAnnotatedClass('Example'); - $this->assertFalse($reflection->hasAnnotation('FirstAnnotation')); - $this->assertFalse($reflection->hasAnnotation('SecondAnnotation')); - } - } -?> +assertTrue($reflection->hasAnnotation('FirstAnnotation')); + $this->assertTrue($reflection->hasAnnotation('SecondAnnotation')); + $this->assertFalse($reflection->hasAnnotation('NonExistentAnnotation')); + $this->assertIsA($reflection->getAnnotation('FirstAnnotation'), 'FirstAnnotation'); + $this->assertIsA($reflection->getAnnotation('SecondAnnotation'), 'SecondAnnotation'); + + $annotations = $reflection->getAnnotations(); + $this->assertEqual(count($annotations), 2); + $this->assertIsA($annotations[0], 'FirstAnnotation'); + $this->assertIsA($annotations[1], 'SecondAnnotation'); + $this->assertFalse($reflection->getAnnotation('NonExistentAnnotation')); + + $this->assertIsA($reflection->getConstructor(), 'ReflectionAnnotatedMethod'); + $this->assertIsA($reflection->getMethod('exampleMethod'), 'ReflectionAnnotatedMethod'); + foreach($reflection->getMethods() as $method) { + $this->assertIsA($method, 'ReflectionAnnotatedMethod'); + } + + $this->assertIsA($reflection->getProperty('exampleProperty'), 'ReflectionAnnotatedProperty'); + foreach($reflection->getProperties() as $property) { + $this->assertIsA($property, 'ReflectionAnnotatedProperty'); + } + + foreach($reflection->getInterfaces() as $interface) { + $this->assertIsA($interface, 'ReflectionAnnotatedClass'); + } + + $this->assertIsA($reflection->getParentClass(), 'ReflectionAnnotatedClass'); + } + + public function testReflectionAnnotatedMethod() { + $reflection = new ReflectionAnnotatedMethod('Example', 'exampleMethod'); + $this->assertTrue($reflection->hasAnnotation('FirstAnnotation')); + $this->assertFalse($reflection->hasAnnotation('NonExistentAnnotation')); + $this->assertIsA($reflection->getAnnotation('FirstAnnotation'), 'FirstAnnotation'); + $this->assertFalse($reflection->getAnnotation('NonExistentAnnotation')); + + $annotations = $reflection->getAnnotations(); + $this->assertEqual(count($annotations), 1); + $this->assertIsA($annotations[0], 'FirstAnnotation'); + + $this->assertIsA($reflection->getDeclaringClass(), 'ReflectionAnnotatedClass'); + } + + public function testReflectionAnnotatedProperty() { + $reflection = new ReflectionAnnotatedProperty('Example', 'exampleProperty'); + $this->assertTrue($reflection->hasAnnotation('SecondAnnotation')); + $this->assertFalse($reflection->hasAnnotation('FirstAnnotation')); + $this->assertIsA($reflection->getAnnotation('SecondAnnotation'), 'SecondAnnotation'); + $this->assertFalse($reflection->getAnnotation('NonExistentAnnotation')); + + $annotations = $reflection->getAnnotations(); + $this->assertEqual(count($annotations), 1); + $this->assertIsA($annotations[0], 'SecondAnnotation'); + + $this->assertIsA($reflection->getDeclaringClass(), 'ReflectionAnnotatedClass'); + } + + public function testReflectionClassCanFilterMethodsByAccess() { + $reflection = new ReflectionAnnotatedClass('Example'); + $privateMethods = $reflection->getMethods(ReflectionMethod::IS_PRIVATE); + $this->assertEqual(count($privateMethods), 1); + $this->assertEqual($privateMethods[0]->getName(), 'justPrivate'); + } + + public function testReflectionClassCanFilterPropertiesByAccess() { + $reflection = new ReflectionAnnotatedClass('Example'); + $privateProperties = $reflection->getProperties(ReflectionProperty::IS_PUBLIC); + $this->assertEqual(count($privateProperties), 1); + $this->assertEqual($privateProperties[0]->getName(), 'publicOne'); + } + + public function testReflectionClassShouldReturnAllMethodsWithNoFilter() { + $reflection = new ReflectionAnnotatedClass('Example'); + $methods = $reflection->getMethods(); + $this->assertEqual(count($methods), 3); + } + + public function testReflectionClassShouldReturnAllPropertiesWithNoFilter() { + $reflection = new ReflectionAnnotatedClass('Example'); + $properties = $reflection->getProperties(); + $this->assertEqual(count($properties), 2); + } + + public function testMultipleAnnotationsOnClass() { + $reflection = new ReflectionAnnotatedClass('MultiExample'); + $annotations = $reflection->getAllAnnotations(); + $this->assertEqual(count($annotations), 3); + $this->assertEqual($annotations[0]->value, 1); + $this->assertEqual($annotations[1]->value, 2); + $this->assertEqual($annotations[2]->value, 3); + $this->assertIsA($annotations[0], 'FirstAnnotation'); + $this->assertIsA($annotations[1], 'FirstAnnotation'); + $this->assertIsA($annotations[2], 'SecondAnnotation'); + } + + public function testMultipleAnnotationsOnClassWithRestriction() { + $reflection = new ReflectionAnnotatedClass('MultiExample'); + $annotations = $reflection->getAllAnnotations('FirstAnnotation'); + $this->assertEqual(count($annotations), 2); + $this->assertEqual($annotations[0]->value, 1); + $this->assertEqual($annotations[1]->value, 2); + $this->assertIsA($annotations[0], 'FirstAnnotation'); + $this->assertIsA($annotations[1], 'FirstAnnotation'); + } + + public function testMultipleAnnotationsOnProperty() { + $reflection = new ReflectionAnnotatedClass('MultiExample'); + $reflection = $reflection->getProperty('property'); + $annotations = $reflection->getAllAnnotations(); + $this->assertEqual(count($annotations), 3); + $this->assertEqual($annotations[0]->value, 1); + $this->assertEqual($annotations[1]->value, 2); + $this->assertEqual($annotations[2]->value, 3); + $this->assertIsA($annotations[0], 'FirstAnnotation'); + $this->assertIsA($annotations[1], 'FirstAnnotation'); + $this->assertIsA($annotations[2], 'SecondAnnotation'); + } + + public function testMultipleAnnotationsOnPropertyWithRestriction() { + $reflection = new ReflectionAnnotatedClass('MultiExample'); + $reflection = $reflection->getProperty('property'); + $annotations = $reflection->getAllAnnotations('FirstAnnotation'); + $this->assertEqual(count($annotations), 2); + $this->assertEqual($annotations[0]->value, 1); + $this->assertEqual($annotations[1]->value, 2); + $this->assertIsA($annotations[0], 'FirstAnnotation'); + $this->assertIsA($annotations[1], 'FirstAnnotation'); + } + + public function testMultipleAnnotationsOnMethod() { + $reflection = new ReflectionAnnotatedClass('MultiExample'); + $reflection = $reflection->getMethod('aMethod'); + $annotations = $reflection->getAllAnnotations(); + $this->assertEqual(count($annotations), 3); + $this->assertEqual($annotations[0]->value, 1); + $this->assertEqual($annotations[1]->value, 2); + $this->assertEqual($annotations[2]->value, 3); + $this->assertIsA($annotations[0], 'FirstAnnotation'); + $this->assertIsA($annotations[1], 'FirstAnnotation'); + $this->assertIsA($annotations[2], 'SecondAnnotation'); + } + + public function testMultipleAnnotationsOnMethodWithRestriction() { + $reflection = new ReflectionAnnotatedClass('MultiExample'); + $reflection = $reflection->getMethod('aMethod'); + $annotations = $reflection->getAllAnnotations('FirstAnnotation'); + $this->assertEqual(count($annotations), 2); + $this->assertEqual($annotations[0]->value, 1); + $this->assertEqual($annotations[1]->value, 2); + $this->assertIsA($annotations[0], 'FirstAnnotation'); + $this->assertIsA($annotations[1], 'FirstAnnotation'); + } + } + + Mock::generatePartial('AnnotationsBuilder', 'MockedAnnotationsBuilder', array('getDocComment')); + + class TestOfPerformanceFeatures extends UnitTestCase { + public function setUp() { + AnnotationsBuilder::clearCache(); + } + + public function tearDown() { + AnnotationsBuilder::clearCache(); + } + + public function testBuilderShouldCacheResults() { + $builder = new MockedAnnotationsBuilder; + $reflection = new ReflectionClass('Example'); + $builder->build($reflection); + $builder->build($reflection); + $builder->expectOnce('getDocComment'); + } + } + + class TestOfSupportingFeatures extends UnitTestCase { + public function setUp() { + Addendum::resetIgnoredAnnotations(); + } + + public function tearDown() { + Addendum::resetIgnoredAnnotations(); + } + + public function testIgnoredAnnotationsAreNotUsed() { + Addendum::ignore('FirstAnnotation', 'SecondAnnotation'); + $reflection = new ReflectionAnnotatedClass('Example'); + $this->assertFalse($reflection->hasAnnotation('FirstAnnotation')); + $this->assertFalse($reflection->hasAnnotation('SecondAnnotation')); + } + } +?> diff --git a/lib/vendor/addendum/annotations/tests/all_tests.php b/lib/vendor/addendum/annotations/tests/all_tests.php index 203f720ee..f64dc0772 100755 --- a/lib/vendor/addendum/annotations/tests/all_tests.php +++ b/lib/vendor/addendum/annotations/tests/all_tests.php @@ -1,33 +1,33 @@ -addTestClass('TestOfAnnotations'); - $this->addTestClass('TestOfPerformanceFeatures'); - $this->addTestClass('TestOfSupportingFeatures'); - $this->addTestClass('TestOfAnnotation'); - $this->addTestClass('TestOfConstrainedAnnotation'); - $this->addTestClass('TestOfMatchers'); - $this->addTestClass('TestOfAnnotationMatchers'); - $this->addTestClass('TestOfDocComment'); - - } - } - - Addendum::setRawMode(false); - $test = new AllTests('All tests in reflection mode'); - $test->run(new HtmlReporter()); - - Addendum::setRawMode(true); - $test = new AllTests('All tests in raw mode'); - $test->run(new HtmlReporter()); -?> +addTestClass('TestOfAnnotations'); + $this->addTestClass('TestOfPerformanceFeatures'); + $this->addTestClass('TestOfSupportingFeatures'); + $this->addTestClass('TestOfAnnotation'); + $this->addTestClass('TestOfConstrainedAnnotation'); + $this->addTestClass('TestOfMatchers'); + $this->addTestClass('TestOfAnnotationMatchers'); + $this->addTestClass('TestOfDocComment'); + + } + } + + Addendum::setRawMode(false); + $test = new AllTests('All tests in reflection mode'); + $test->run(new HtmlReporter()); + + Addendum::setRawMode(true); + $test = new AllTests('All tests in raw mode'); + $test->run(new HtmlReporter()); +?> diff --git a/lib/vendor/addendum/annotations/tests/annotation_parser_test.php b/lib/vendor/addendum/annotations/tests/annotation_parser_test.php index 9cc1eba68..cb9563733 100755 --- a/lib/vendor/addendum/annotations/tests/annotation_parser_test.php +++ b/lib/vendor/addendum/annotations/tests/annotation_parser_test.php @@ -1,312 +1,312 @@ -assertIdentical($matcher->matches('1234a', $value), 4); - $this->assertIdentical($value, '1234'); - } - - public function testRegexMatcherShouldReturnFalseOnNoMatch() { - $matcher = new RegexMatcher('[0-9]+'); - $this->assertFalse($matcher->matches('abc123', $value)); - } - - public function testParallelMatcherShouldMatchLongerStringOnColision() { - $matcher = new ParallelMatcher; - $matcher->add(new RegexMatcher('true')); - $matcher->add(new RegexMatcher('.+')); - $this->assertEqual($matcher->matches('truestring', $value), 10); - $this->assertEqual($value, 'truestring'); - } - - public function testSerialMatcherShouldMatchAllParts() { - $matcher = new SerialMatcher; - $matcher->add(new RegexMatcher('[a-zA-Z0-9_]+')); - $matcher->add(new RegexMatcher('=')); - $matcher->add(new RegexMatcher('[0-9]+')); - $this->assertEqual($matcher->matches('key=20', $value), 6); - $this->assertEqual($value, 'key=20'); - } - - public function testSerialMatcherShouldFailIfAnyPartDoesNotMatch() { - $matcher = new SerialMatcher; - $matcher->add(new RegexMatcher('[a-zA-Z0-9_]+')); - $matcher->add(new RegexMatcher('=')); - $matcher->add(new RegexMatcher('[0-9]+')); - $this->assertFalse($matcher->matches('key=a20', $value)); - } - - public function testSimpleSerialMatcherShouldReturnRequestedPartOnMatch() { - $matcher = new SimpleSerialMatcher(1); - $matcher->add(new RegexMatcher('\(')); - $matcher->add(new RegexMatcher('[0-9]+')); - $matcher->add(new RegexMatcher('\)')); - $this->assertEqual($matcher->matches('(1234)', $value), 6); - $this->assertEqual($value, '1234'); - } - } - - class TestOfAnnotationMatchers extends UnitTestCase { - public function testAnnotationsMatcherShouldMatchAnnotationWithGarbage() { - $expected = array('Annotation' => array( - array('value' => true), - )); - $matcher = new AnnotationsMatcher; - $this->assertMatcherResult($matcher, '/** asd bla bla @Annotation(true) */@', $expected); - } - - public function testAnnotationsMatcherShouldNotMatchEmail() { - $matcher = new AnnotationsMatcher; - $this->assertMatcherResult($matcher, 'johno@example.com', array()); - } - - public function testAnnotationsMatcherShouldMatchMultipleAnnotations() { - $expected = array('Annotation' => array( - array('value' => true), - array('value' => false) - )); - $matcher = new AnnotationsMatcher; - $this->assertMatcherResult($matcher, ' ss @Annotation(true) @Annotation(false)', $expected); - } - - public function testAnnotationsMatcherShouldMatchMultipleAnnotationsOnManyLines() { - $expected = array('Annotation' => array( - array('value' => true), - array('value' => false) - )); - $block = "/** - @Annotation(true) - @Annotation(false) - **/"; - $matcher = new AnnotationsMatcher; - $this->assertMatcherResult($matcher, $block, $expected); - } - - public function testAnnotationMatcherShouldMatchMultilineAnnotations() { - $block= '/** - * @Annotation( - paramOne="value1", - paramTwo={ - "value2" , - {"one", "two"} - }, - paramThree="three" - ) - */'; - $expected = array('Annotation' => array( - array( - 'paramOne' => 'value1', - 'paramTwo' => array('value2', array('one', 'two')), - 'paramThree' => 'three', - ) - )); - $matcher = new AnnotationsMatcher; - $this->assertMatcherResult($matcher, $block, $expected); - } - - public function testAnnotationMatcherShouldMatchSimpleAnnotation() { - $matcher = new AnnotationMatcher; - $this->assertNotFalse($matcher->matches('@Namespace_Annotation', $value)); - $this->assertEqual($value, array('Namespace_Annotation', array())); - } - - public function testAnnotationMatcherShouldNotMatchAnnotationWithSmallStartingLetter() { - $matcher = new AnnotationMatcher; - $this->assertFalse($matcher->matches('@annotation', $value)); - } - - public function testAnnotationMatcherShouldMatchAlsoBrackets() { - $matcher = new AnnotationMatcher; - $this->assertEqual($matcher->matches('@Annotation()', $value), 13); - $this->assertEqual($value, array('Annotation', array())); - } - - public function testAnnotationMatcherShouldMatchValuedAnnotation() { - $matcher = new AnnotationMatcher; - $this->assertMatcherResult($matcher, '@Annotation(true)', array('Annotation', array('value' => true))); - } - - public function testAnnotationMatcherShouldMatchMultiValuedAnnotation() { - $matcher = new AnnotationMatcher; - $this->assertMatcherResult($matcher, '@Annotation(key=true, key2=3.14)', array('Annotation', array('key' => true, 'key2' => 3.14))); - } - - public function testParametersMatcherShouldMatchEmptyStringAndReturnEmptyArray() { - $matcher = new AnnotationParametersMatcher; - $this->assertIdentical($matcher->matches('', $value), 0); - $this->assertEqual($value, array()); - } - - public function testParametersMatcherShouldMatchEmptyBracketsAndReturnEmptyArray() { - $matcher = new AnnotationParametersMatcher; - $this->assertIdentical($matcher->matches('()', $value), 2); - $this->assertEqual($value, array()); - } - - public function testParametersMatcherShouldMatchMultilinedParameters() { - $matcher = new AnnotationParametersMatcher; - $block = "( - key = true, - key2 = false - )"; - $this->assertMatcherResult($matcher, $block, array('key' => true, 'key2' => false)); - } - - public function testValuesMatcherShouldMatchSimpleValueOrHash() { - $matcher = new AnnotationValuesMatcher; - $this->assertNotFalse($matcher->matches('true', $value)); - $this->assertNotFalse($matcher->matches('key=true', $value)); - } - - public function testValueMatcherShouldMatchConstants() { - $matcher = new AnnotationValueMatcher; - $this->assertMatcherResult($matcher, 'true', true); - $this->assertMatcherResult($matcher, 'false', false); - $this->assertMatcherResult($matcher, 'TRUE', true); - $this->assertMatcherResult($matcher, 'FALSE', false); - } - - public function testValueMatcherShouldMatchStrings() { - $matcher = new AnnotationValueMatcher; - $this->assertMatcherResult($matcher, '"string"', 'string'); - $this->assertMatcherResult($matcher, "'string'", 'string'); - } - - public function testValueMatcherShouldMatchNumbers() { - $matcher = new AnnotationValueMatcher; - $this->assertMatcherResult($matcher, '-3.14', -3.14); - $this->assertMatcherResult($matcher, '100', 100); - } - - public function testValueMatcherShouldMatchArray() { - $matcher = new AnnotationValueMatcher; - $this->assertMatcherResult($matcher, '{1}', array(1)); - } - - public function testArrayMatcherShouldMatchEmptyArray() { - $matcher = new AnnotationArrayMatcher; - $this->assertMatcherResult($matcher, '{}', array()); - } - - public function testValueInArrayMatcherReturnsAValueInArray() { - $matcher = new AnnotationValueInArrayMatcher; - $this->assertMatcherResult($matcher, '1', array(1)); - } - - public function testArrayMatcherShouldMatchSimpleValueInArray() { - $matcher = new AnnotationArrayMatcher; - $this->assertMatcherResult($matcher, '{1}', array(1)); - } - - public function testArrayMatcherShouldMatchSimplePair() { - $matcher = new AnnotationArrayMatcher; - $this->assertMatcherResult($matcher, '{key=5}', array('key' => 5)); - } - - public function TODO_testArrayMatcherShouldMatchPairWithNumericKeys() { - $matcher = new AnnotationArrayMatcher; - $this->assertMatcherResult($matcher, '{1="one", 2="two"}', array(1 => 'one', 2 => 'two')); - } - - public function testArrayMatcherShouldMatchMultiplePairs() { - $matcher = new AnnotationArrayMatcher; - $this->assertMatcherResult($matcher, '{key=5, "bla"=false}', array('key' => 5, 'bla' => false)); - } - - public function testArrayMatcherShouldMatchValuesMixedWithPairs() { - $matcher = new AnnotationArrayMatcher; - $this->assertMatcherResult($matcher, '{key=5, 1, 2, key2="ff"}', array('key' => 5, 1, 2, 'key2' => "ff")); - } - - public function testArrayMatcherShouldMatchMoreValuesInArrayWithWhiteSpace() { - $matcher = new AnnotationArrayMatcher; - $this->assertMatcherResult($matcher, "{1 , 2}", array(1, 2)); - } - - public function testArrayMatcherShouldMatchNestedArray() { - $matcher = new AnnotationArrayMatcher; - $this->assertMatcherResult($matcher, "{1 , {2, 3}, 4}", array(1, array(2, 3), 4)); - } - - public function testArrayMatcherShouldMatchWithMoreWhiteSpace() { - $matcher = new AnnotationArrayMatcher; - $this->assertMatcherResult($matcher, "{ 1 , 2 , 3 }", array(1, 2, 3)); - } - - public function testArrayMatcherShouldMatchWithMultilineWhiteSpace() { - $matcher = new AnnotationArrayMatcher; - $this->assertMatcherResult($matcher, "\n{1, 2, 3\n}", array(1, 2, 3)); - } - - public function testNumberMatcherShouldMatchInteger() { - $matcher = new AnnotationNumberMatcher; - $this->assertMatcherResult($matcher, '-314', -314); - } - - public function testNumberMatcherShouldMatchFloat() { - $matcher = new AnnotationNumberMatcher; - $this->assertMatcherResult($matcher, '-3.14', -3.14); - } - - public function testHashMatcherShouldMatchSimpleHash() { - $matcher = new AnnotationHashMatcher; - $this->assertMatcherResult($matcher, 'key=true', array('key' => true)); - } - - public function testHashMatcherShouldMatchAlsoMultipleKeys() { - $matcher = new AnnotationHashMatcher; - $this->assertMatcherResult($matcher, 'key=true,key2=false', array('key' => true, 'key2' => false)); - } - - public function testHashMatcherShouldMatchAlsoMultipleKeysWithWhiteSpace() { - $matcher = new AnnotationHashMatcher; - $this->assertMatcherResult($matcher, "key=true\n\t\r ,\n\t\r key2=false", array('key' => true, 'key2' => false)); - } - - public function testPairMatcherShouldMatchNumericKey() { - $matcher = new AnnotationPairMatcher; - $this->assertMatcherResult($matcher, '2 = true', array(2 => true)); - } - - public function testPairMatcherShouldMatchAlsoWhitespace() { - $matcher = new AnnotationPairMatcher; - $this->assertMatcherResult($matcher, 'key = true', array('key' => true)); - } - - public function testKeyMatcherShouldMatchSimpleKeysOrStrings() { - $matcher = new AnnotationKeyMatcher; - $this->assertNotFalse($matcher->matches('key', $value)); - $this->assertNotFalse($matcher->matches('"key"', $value)); - $this->assertNotFalse($matcher->matches("'key'", $value)); - } - - public function testKeyMatcherShouldMatchIntegerKeys() { - $matcher = new AnnotationKeyMatcher; - $this->assertMatcherResult($matcher, '123', 123); - } - - public function testStringMatcherShouldMatchDoubleAndSingleQuotedStringsAndHandleEscapes() { - $matcher = new AnnotationStringMatcher; - $this->assertMatcherResult($matcher, '"string string"', 'string string'); - $this->assertMatcherResult($matcher, "'string string'", "string string"); - } - - public function TODO_testStringMatcherShouldMatchEscapedStringsCorrectly() { - $matcher = new AnnotationStringMatcher; - $this->assertMatcherResult($matcher, '"string\"string"', 'string"string'); - $this->assertMatcherResult($matcher, "'string\'string'", "string'string"); - } - - private function assertNotFalse($value) { - $this->assertNotIdentical($value, false); - } - - private function assertMatcherResult($matcher, $string, $expected) { - $this->assertNotIdentical($matcher->matches($string, $value), false); - $this->assertIdentical($value, $expected); - } - } +assertIdentical($matcher->matches('1234a', $value), 4); + $this->assertIdentical($value, '1234'); + } + + public function testRegexMatcherShouldReturnFalseOnNoMatch() { + $matcher = new RegexMatcher('[0-9]+'); + $this->assertFalse($matcher->matches('abc123', $value)); + } + + public function testParallelMatcherShouldMatchLongerStringOnColision() { + $matcher = new ParallelMatcher; + $matcher->add(new RegexMatcher('true')); + $matcher->add(new RegexMatcher('.+')); + $this->assertEqual($matcher->matches('truestring', $value), 10); + $this->assertEqual($value, 'truestring'); + } + + public function testSerialMatcherShouldMatchAllParts() { + $matcher = new SerialMatcher; + $matcher->add(new RegexMatcher('[a-zA-Z0-9_]+')); + $matcher->add(new RegexMatcher('=')); + $matcher->add(new RegexMatcher('[0-9]+')); + $this->assertEqual($matcher->matches('key=20', $value), 6); + $this->assertEqual($value, 'key=20'); + } + + public function testSerialMatcherShouldFailIfAnyPartDoesNotMatch() { + $matcher = new SerialMatcher; + $matcher->add(new RegexMatcher('[a-zA-Z0-9_]+')); + $matcher->add(new RegexMatcher('=')); + $matcher->add(new RegexMatcher('[0-9]+')); + $this->assertFalse($matcher->matches('key=a20', $value)); + } + + public function testSimpleSerialMatcherShouldReturnRequestedPartOnMatch() { + $matcher = new SimpleSerialMatcher(1); + $matcher->add(new RegexMatcher('\(')); + $matcher->add(new RegexMatcher('[0-9]+')); + $matcher->add(new RegexMatcher('\)')); + $this->assertEqual($matcher->matches('(1234)', $value), 6); + $this->assertEqual($value, '1234'); + } + } + + class TestOfAnnotationMatchers extends UnitTestCase { + public function testAnnotationsMatcherShouldMatchAnnotationWithGarbage() { + $expected = array('Annotation' => array( + array('value' => true), + )); + $matcher = new AnnotationsMatcher; + $this->assertMatcherResult($matcher, '/** asd bla bla @Annotation(true) */@', $expected); + } + + public function testAnnotationsMatcherShouldNotMatchEmail() { + $matcher = new AnnotationsMatcher; + $this->assertMatcherResult($matcher, 'johno@example.com', array()); + } + + public function testAnnotationsMatcherShouldMatchMultipleAnnotations() { + $expected = array('Annotation' => array( + array('value' => true), + array('value' => false) + )); + $matcher = new AnnotationsMatcher; + $this->assertMatcherResult($matcher, ' ss @Annotation(true) @Annotation(false)', $expected); + } + + public function testAnnotationsMatcherShouldMatchMultipleAnnotationsOnManyLines() { + $expected = array('Annotation' => array( + array('value' => true), + array('value' => false) + )); + $block = "/** + @Annotation(true) + @Annotation(false) + **/"; + $matcher = new AnnotationsMatcher; + $this->assertMatcherResult($matcher, $block, $expected); + } + + public function testAnnotationMatcherShouldMatchMultilineAnnotations() { + $block= '/** + * @Annotation( + paramOne="value1", + paramTwo={ + "value2" , + {"one", "two"} + }, + paramThree="three" + ) + */'; + $expected = array('Annotation' => array( + array( + 'paramOne' => 'value1', + 'paramTwo' => array('value2', array('one', 'two')), + 'paramThree' => 'three', + ) + )); + $matcher = new AnnotationsMatcher; + $this->assertMatcherResult($matcher, $block, $expected); + } + + public function testAnnotationMatcherShouldMatchSimpleAnnotation() { + $matcher = new AnnotationMatcher; + $this->assertNotFalse($matcher->matches('@Namespace_Annotation', $value)); + $this->assertEqual($value, array('Namespace_Annotation', array())); + } + + public function testAnnotationMatcherShouldNotMatchAnnotationWithSmallStartingLetter() { + $matcher = new AnnotationMatcher; + $this->assertFalse($matcher->matches('@annotation', $value)); + } + + public function testAnnotationMatcherShouldMatchAlsoBrackets() { + $matcher = new AnnotationMatcher; + $this->assertEqual($matcher->matches('@Annotation()', $value), 13); + $this->assertEqual($value, array('Annotation', array())); + } + + public function testAnnotationMatcherShouldMatchValuedAnnotation() { + $matcher = new AnnotationMatcher; + $this->assertMatcherResult($matcher, '@Annotation(true)', array('Annotation', array('value' => true))); + } + + public function testAnnotationMatcherShouldMatchMultiValuedAnnotation() { + $matcher = new AnnotationMatcher; + $this->assertMatcherResult($matcher, '@Annotation(key=true, key2=3.14)', array('Annotation', array('key' => true, 'key2' => 3.14))); + } + + public function testParametersMatcherShouldMatchEmptyStringAndReturnEmptyArray() { + $matcher = new AnnotationParametersMatcher; + $this->assertIdentical($matcher->matches('', $value), 0); + $this->assertEqual($value, array()); + } + + public function testParametersMatcherShouldMatchEmptyBracketsAndReturnEmptyArray() { + $matcher = new AnnotationParametersMatcher; + $this->assertIdentical($matcher->matches('()', $value), 2); + $this->assertEqual($value, array()); + } + + public function testParametersMatcherShouldMatchMultilinedParameters() { + $matcher = new AnnotationParametersMatcher; + $block = "( + key = true, + key2 = false + )"; + $this->assertMatcherResult($matcher, $block, array('key' => true, 'key2' => false)); + } + + public function testValuesMatcherShouldMatchSimpleValueOrHash() { + $matcher = new AnnotationValuesMatcher; + $this->assertNotFalse($matcher->matches('true', $value)); + $this->assertNotFalse($matcher->matches('key=true', $value)); + } + + public function testValueMatcherShouldMatchConstants() { + $matcher = new AnnotationValueMatcher; + $this->assertMatcherResult($matcher, 'true', true); + $this->assertMatcherResult($matcher, 'false', false); + $this->assertMatcherResult($matcher, 'TRUE', true); + $this->assertMatcherResult($matcher, 'FALSE', false); + } + + public function testValueMatcherShouldMatchStrings() { + $matcher = new AnnotationValueMatcher; + $this->assertMatcherResult($matcher, '"string"', 'string'); + $this->assertMatcherResult($matcher, "'string'", 'string'); + } + + public function testValueMatcherShouldMatchNumbers() { + $matcher = new AnnotationValueMatcher; + $this->assertMatcherResult($matcher, '-3.14', -3.14); + $this->assertMatcherResult($matcher, '100', 100); + } + + public function testValueMatcherShouldMatchArray() { + $matcher = new AnnotationValueMatcher; + $this->assertMatcherResult($matcher, '{1}', array(1)); + } + + public function testArrayMatcherShouldMatchEmptyArray() { + $matcher = new AnnotationArrayMatcher; + $this->assertMatcherResult($matcher, '{}', array()); + } + + public function testValueInArrayMatcherReturnsAValueInArray() { + $matcher = new AnnotationValueInArrayMatcher; + $this->assertMatcherResult($matcher, '1', array(1)); + } + + public function testArrayMatcherShouldMatchSimpleValueInArray() { + $matcher = new AnnotationArrayMatcher; + $this->assertMatcherResult($matcher, '{1}', array(1)); + } + + public function testArrayMatcherShouldMatchSimplePair() { + $matcher = new AnnotationArrayMatcher; + $this->assertMatcherResult($matcher, '{key=5}', array('key' => 5)); + } + + public function TODO_testArrayMatcherShouldMatchPairWithNumericKeys() { + $matcher = new AnnotationArrayMatcher; + $this->assertMatcherResult($matcher, '{1="one", 2="two"}', array(1 => 'one', 2 => 'two')); + } + + public function testArrayMatcherShouldMatchMultiplePairs() { + $matcher = new AnnotationArrayMatcher; + $this->assertMatcherResult($matcher, '{key=5, "bla"=false}', array('key' => 5, 'bla' => false)); + } + + public function testArrayMatcherShouldMatchValuesMixedWithPairs() { + $matcher = new AnnotationArrayMatcher; + $this->assertMatcherResult($matcher, '{key=5, 1, 2, key2="ff"}', array('key' => 5, 1, 2, 'key2' => "ff")); + } + + public function testArrayMatcherShouldMatchMoreValuesInArrayWithWhiteSpace() { + $matcher = new AnnotationArrayMatcher; + $this->assertMatcherResult($matcher, "{1 , 2}", array(1, 2)); + } + + public function testArrayMatcherShouldMatchNestedArray() { + $matcher = new AnnotationArrayMatcher; + $this->assertMatcherResult($matcher, "{1 , {2, 3}, 4}", array(1, array(2, 3), 4)); + } + + public function testArrayMatcherShouldMatchWithMoreWhiteSpace() { + $matcher = new AnnotationArrayMatcher; + $this->assertMatcherResult($matcher, "{ 1 , 2 , 3 }", array(1, 2, 3)); + } + + public function testArrayMatcherShouldMatchWithMultilineWhiteSpace() { + $matcher = new AnnotationArrayMatcher; + $this->assertMatcherResult($matcher, "\n{1, 2, 3\n}", array(1, 2, 3)); + } + + public function testNumberMatcherShouldMatchInteger() { + $matcher = new AnnotationNumberMatcher; + $this->assertMatcherResult($matcher, '-314', -314); + } + + public function testNumberMatcherShouldMatchFloat() { + $matcher = new AnnotationNumberMatcher; + $this->assertMatcherResult($matcher, '-3.14', -3.14); + } + + public function testHashMatcherShouldMatchSimpleHash() { + $matcher = new AnnotationHashMatcher; + $this->assertMatcherResult($matcher, 'key=true', array('key' => true)); + } + + public function testHashMatcherShouldMatchAlsoMultipleKeys() { + $matcher = new AnnotationHashMatcher; + $this->assertMatcherResult($matcher, 'key=true,key2=false', array('key' => true, 'key2' => false)); + } + + public function testHashMatcherShouldMatchAlsoMultipleKeysWithWhiteSpace() { + $matcher = new AnnotationHashMatcher; + $this->assertMatcherResult($matcher, "key=true\n\t\r ,\n\t\r key2=false", array('key' => true, 'key2' => false)); + } + + public function testPairMatcherShouldMatchNumericKey() { + $matcher = new AnnotationPairMatcher; + $this->assertMatcherResult($matcher, '2 = true', array(2 => true)); + } + + public function testPairMatcherShouldMatchAlsoWhitespace() { + $matcher = new AnnotationPairMatcher; + $this->assertMatcherResult($matcher, 'key = true', array('key' => true)); + } + + public function testKeyMatcherShouldMatchSimpleKeysOrStrings() { + $matcher = new AnnotationKeyMatcher; + $this->assertNotFalse($matcher->matches('key', $value)); + $this->assertNotFalse($matcher->matches('"key"', $value)); + $this->assertNotFalse($matcher->matches("'key'", $value)); + } + + public function testKeyMatcherShouldMatchIntegerKeys() { + $matcher = new AnnotationKeyMatcher; + $this->assertMatcherResult($matcher, '123', 123); + } + + public function testStringMatcherShouldMatchDoubleAndSingleQuotedStringsAndHandleEscapes() { + $matcher = new AnnotationStringMatcher; + $this->assertMatcherResult($matcher, '"string string"', 'string string'); + $this->assertMatcherResult($matcher, "'string string'", "string string"); + } + + public function TODO_testStringMatcherShouldMatchEscapedStringsCorrectly() { + $matcher = new AnnotationStringMatcher; + $this->assertMatcherResult($matcher, '"string\"string"', 'string"string'); + $this->assertMatcherResult($matcher, "'string\'string'", "string'string"); + } + + private function assertNotFalse($value) { + $this->assertNotIdentical($value, false); + } + + private function assertMatcherResult($matcher, $string, $expected) { + $this->assertNotIdentical($matcher->matches($string, $value), false); + $this->assertIdentical($value, $expected); + } + } ?> \ No newline at end of file diff --git a/lib/vendor/addendum/annotations/tests/annotation_test.php b/lib/vendor/addendum/annotations/tests/annotation_test.php index d5865b13c..936e115ef 100755 --- a/lib/vendor/addendum/annotations/tests/annotation_test.php +++ b/lib/vendor/addendum/annotations/tests/annotation_test.php @@ -1,27 +1,27 @@ - 1, 'required' => 2), $this); - $this->assertEqual($annotation->optional, 1); - $this->assertEqual($annotation->required, 2); - } - - public function testConstructorThrowsErrorOnInvalidParameter() { - $annotation = new TestingAnnotation(array('unknown' => 1), $this); - $this->assertError("Property 'unknown' not defined for annotation 'TestingAnnotation'"); - } - - public function TODO_testConstructorThrowsErrorWithoutSpecifingRequiredParameters() { - $annotation = new TestingAnnotation(); - $this->assertError("Property 'required' in annotation 'TestingAnnotation' is required"); - } - } -?> + 1, 'required' => 2), $this); + $this->assertEqual($annotation->optional, 1); + $this->assertEqual($annotation->required, 2); + } + + public function testConstructorThrowsErrorOnInvalidParameter() { + $annotation = new TestingAnnotation(array('unknown' => 1), $this); + $this->assertError("Property 'unknown' not defined for annotation 'TestingAnnotation'"); + } + + public function TODO_testConstructorThrowsErrorWithoutSpecifingRequiredParameters() { + $annotation = new TestingAnnotation(); + $this->assertError("Property 'required' in annotation 'TestingAnnotation' is required"); + } + } +?> diff --git a/lib/vendor/addendum/annotations/tests/constrained_annotation_test.php b/lib/vendor/addendum/annotations/tests/constrained_annotation_test.php index 24f2144fb..a1cc765e1 100755 --- a/lib/vendor/addendum/annotations/tests/constrained_annotation_test.php +++ b/lib/vendor/addendum/annotations/tests/constrained_annotation_test.php @@ -1,73 +1,73 @@ -expectError("Annotation 'ClassRestrictedAnnotation' not allowed on BadlyAnnotatedClass::method"); - $reflection = new ReflectionAnnotatedClass('BadlyAnnotatedClass'); - $method = $reflection->getMethod('method'); - } - - public function testClassAnnotationThrowsErrorWhenOnProperty() { - $this->expectError("Annotation 'ClassRestrictedAnnotation' not allowed on BadlyAnnotatedClass::\$property"); - $reflection = new ReflectionAnnotatedClass('BadlyAnnotatedClass'); - $method = $reflection->getProperty('property'); - } - - public function testSingleTargetAnnotationThrowsNoErrorWhenOnRightPlace() { - $reflection = new ReflectionAnnotatedClass('SuccesfullyAnnotatedClass'); - $method = $reflection->getMethod('method'); - $property = $reflection->getProperty('property'); - $this->assertNoErrors(); - } - - public function testMultiTargetAnnotationThrowsErrorWhenOnWrongPlace() { - $this->expectError("Annotation 'ClassOrPropertyRestrictedAnnotation' not allowed on BadlyAnnotatedClass::method2"); - $reflection = new ReflectionAnnotatedClass('BadlyAnnotatedClass'); - $method = $reflection->getMethod('method2'); - } - - public function testMultiTargetAnnotationThrowsNoErrorWhenOnRightPlace() { - $reflection = new ReflectionAnnotatedClass('SuccesfullyAnnotatedClass'); - $method = $reflection->getProperty('property2'); - $this->assertNoErrors(); - } - } +expectError("Annotation 'ClassRestrictedAnnotation' not allowed on BadlyAnnotatedClass::method"); + $reflection = new ReflectionAnnotatedClass('BadlyAnnotatedClass'); + $method = $reflection->getMethod('method'); + } + + public function testClassAnnotationThrowsErrorWhenOnProperty() { + $this->expectError("Annotation 'ClassRestrictedAnnotation' not allowed on BadlyAnnotatedClass::\$property"); + $reflection = new ReflectionAnnotatedClass('BadlyAnnotatedClass'); + $method = $reflection->getProperty('property'); + } + + public function testSingleTargetAnnotationThrowsNoErrorWhenOnRightPlace() { + $reflection = new ReflectionAnnotatedClass('SuccesfullyAnnotatedClass'); + $method = $reflection->getMethod('method'); + $property = $reflection->getProperty('property'); + $this->assertNoErrors(); + } + + public function testMultiTargetAnnotationThrowsErrorWhenOnWrongPlace() { + $this->expectError("Annotation 'ClassOrPropertyRestrictedAnnotation' not allowed on BadlyAnnotatedClass::method2"); + $reflection = new ReflectionAnnotatedClass('BadlyAnnotatedClass'); + $method = $reflection->getMethod('method2'); + } + + public function testMultiTargetAnnotationThrowsNoErrorWhenOnRightPlace() { + $reflection = new ReflectionAnnotatedClass('SuccesfullyAnnotatedClass'); + $method = $reflection->getProperty('property2'); + $this->assertNoErrors(); + } + } ?> \ No newline at end of file diff --git a/lib/vendor/addendum/annotations/tests/doc_comment_test.php b/lib/vendor/addendum/annotations/tests/doc_comment_test.php index b57db8b27..3a7b3306c 100755 --- a/lib/vendor/addendum/annotations/tests/doc_comment_test.php +++ b/lib/vendor/addendum/annotations/tests/doc_comment_test.php @@ -1,87 +1,87 @@ -assertEqual($finder->get($reflection), '/** class doccomment */'); - } - - public function testFinderFindsFieldDocBlock() { - $reflection = new ReflectionClass('SomeClass'); - $property = $reflection->getProperty('field1'); - $finder = new DocComment(); - $this->assertEqual($finder->get($property), '/** field doccomment */'); - $property = $reflection->getProperty('field2'); - $finder = new DocComment(); - $this->assertFalse($finder->get($property)); - } - - public function testFinderFindsMethodDocBlock() { - $reflection = new ReflectionClass('SomeClass'); - $method = $reflection->getMethod('method1'); - $finder = new DocComment(); - $this->assertEqual($finder->get($method), '/** method1 doccomment */'); - $method = $reflection->getMethod('method2'); - $finder = new DocComment(); - $this->assertFalse($finder->get($method)); - } - - public function testMisplacedDocCommentDoesNotCausesDisaster() { - $reflection = new ReflectionClass('SomeOtherClass'); - $finder = new DocComment(); - $this->assertEqual($finder->get($reflection), false); - } - - public function testUnanotatedClassCanHaveAnotatedField() { - $reflection = new ReflectionClass('SomeOtherClass'); - $property = $reflection->getProperty('field1'); - $finder = new DocComment(); - $this->assertEqual($finder->get($property), '/** field doccomment */'); - } - - public function testParserIsOnlyCalledOncePerFile() { - $reflection = new ReflectionClass('SomeClass'); - $finder = new MockDocComment(); - $finder->expectOnce('parse'); - $this->assertEqual($finder->get($reflection), false); - $this->assertEqual($finder->get($reflection), false); - - $reflection = new ReflectionClass('SomeClass'); - $finder = new MockDocComment(); - $finder->expectNever('parse'); - $this->assertEqual($finder->get($reflection), false); - } - } -?> +assertEqual($finder->get($reflection), '/** class doccomment */'); + } + + public function testFinderFindsFieldDocBlock() { + $reflection = new ReflectionClass('SomeClass'); + $property = $reflection->getProperty('field1'); + $finder = new DocComment(); + $this->assertEqual($finder->get($property), '/** field doccomment */'); + $property = $reflection->getProperty('field2'); + $finder = new DocComment(); + $this->assertFalse($finder->get($property)); + } + + public function testFinderFindsMethodDocBlock() { + $reflection = new ReflectionClass('SomeClass'); + $method = $reflection->getMethod('method1'); + $finder = new DocComment(); + $this->assertEqual($finder->get($method), '/** method1 doccomment */'); + $method = $reflection->getMethod('method2'); + $finder = new DocComment(); + $this->assertFalse($finder->get($method)); + } + + public function testMisplacedDocCommentDoesNotCausesDisaster() { + $reflection = new ReflectionClass('SomeOtherClass'); + $finder = new DocComment(); + $this->assertEqual($finder->get($reflection), false); + } + + public function testUnanotatedClassCanHaveAnotatedField() { + $reflection = new ReflectionClass('SomeOtherClass'); + $property = $reflection->getProperty('field1'); + $finder = new DocComment(); + $this->assertEqual($finder->get($property), '/** field doccomment */'); + } + + public function testParserIsOnlyCalledOncePerFile() { + $reflection = new ReflectionClass('SomeClass'); + $finder = new MockDocComment(); + $finder->expectOnce('parse'); + $this->assertEqual($finder->get($reflection), false); + $this->assertEqual($finder->get($reflection), false); + + $reflection = new ReflectionClass('SomeClass'); + $finder = new MockDocComment(); + $finder->expectNever('parse'); + $this->assertEqual($finder->get($reflection), false); + } + } +?> diff --git a/tests/Doctrine/Tests/ORM/Query/IdentifierRecognitionTest.php b/tests/Doctrine/Tests/ORM/Query/IdentifierRecognitionTest.php index 5a54df142..0fc497c4d 100644 --- a/tests/Doctrine/Tests/ORM/Query/IdentifierRecognitionTest.php +++ b/tests/Doctrine/Tests/ORM/Query/IdentifierRecognitionTest.php @@ -1,130 +1,130 @@ -. - */ - -namespace Doctrine\Tests\ORM\Query; - -require_once __DIR__ . '/../../TestInit.php'; - -/** - * Test case for testing the saving and referencing of query identifiers. - * - * @author Guilherme Blanco - * @author Janne Vanhala - * @author Konsta Vesterinen - * @license http://www.opensource.org/licenses/lgpl-license.php LGPL - * @link http://www.phpdoctrine.org - * @since 2.0 - * @version $Revision$ - */ -class IdentifierRecognitionTest extends \Doctrine\Tests\OrmTestCase -{ - private $_em; - - protected function setUp() { - parent::setUp(); - $this->_em = $this->_getTestEntityManager(); - } - - public function testSingleAliasDeclarationIsSupported() - { - $entityManager = $this->_em; - $query = $entityManager->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u'); - $parserResult = $query->parse(); - - $decl = $parserResult->getQueryComponent('u'); - - $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); - $this->assertEquals(null, $decl['relation']); - $this->assertEquals(null, $decl['parent']); - $this->assertEquals(null, $decl['scalar']); - $this->assertEquals(null, $decl['map']); - } - - public function testSingleAliasDeclarationWithIndexByIsSupported() - { - $entityManager = $this->_em; - $query = $entityManager->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INDEX BY u.id'); - $parserResult = $query->parse(); - - $decl = $parserResult->getQueryComponent('u'); - - $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); - $this->assertEquals(null, $decl['relation']); - $this->assertEquals(null, $decl['parent']); - $this->assertEquals(null, $decl['scalar']); - $this->assertEquals('id', $decl['map']); - } - - public function testQueryParserSupportsMultipleAliasDeclarations() - { - $entityManager = $this->_em; - $query = $entityManager->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INDEX BY u.id LEFT JOIN u.phonenumbers p'); - $parserResult = $query->parse(); - - $decl = $parserResult->getQueryComponent('u'); - - $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); - $this->assertEquals(null, $decl['relation']); - $this->assertEquals(null, $decl['parent']); - $this->assertEquals(null, $decl['scalar']); - $this->assertEquals('id', $decl['map']); - - $decl = $parserResult->getQueryComponent('p'); - - $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); - $this->assertTrue($decl['relation'] instanceof \Doctrine\ORM\Mapping\AssociationMapping); - $this->assertEquals('u', $decl['parent']); - $this->assertEquals(null, $decl['scalar']); - $this->assertEquals(null, $decl['map']); - } - - - public function testQueryParserSupportsMultipleAliasDeclarationsWithIndexBy() - { - $entityManager = $this->_em; - $query = $entityManager->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INDEX BY u.id LEFT JOIN u.articles a INNER JOIN u.phonenumbers pn INDEX BY pn.phonenumber'); - $parserResult = $query->parse(); - - $decl = $parserResult->getQueryComponent('u'); - - $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); - $this->assertEquals(null, $decl['relation']); - $this->assertEquals(null, $decl['parent']); - $this->assertEquals(null, $decl['scalar']); - $this->assertEquals('id', $decl['map']); - - $decl = $parserResult->getQueryComponent('a'); - - $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); - $this->assertTrue($decl['relation'] instanceof \Doctrine\ORM\Mapping\AssociationMapping); - $this->assertEquals('u', $decl['parent']); - $this->assertEquals(null, $decl['scalar']); - $this->assertEquals(null, $decl['map']); - - $decl = $parserResult->getQueryComponent('pn'); - - $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); - $this->assertTrue($decl['relation'] instanceof \Doctrine\ORM\Mapping\AssociationMapping); - $this->assertEquals('u', $decl['parent']); - $this->assertEquals(null, $decl['scalar']); - $this->assertEquals('phonenumber', $decl['map']); - } -} +. + */ + +namespace Doctrine\Tests\ORM\Query; + +require_once __DIR__ . '/../../TestInit.php'; + +/** + * Test case for testing the saving and referencing of query identifiers. + * + * @author Guilherme Blanco + * @author Janne Vanhala + * @author Konsta Vesterinen + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link http://www.phpdoctrine.org + * @since 2.0 + * @version $Revision$ + */ +class IdentifierRecognitionTest extends \Doctrine\Tests\OrmTestCase +{ + private $_em; + + protected function setUp() { + parent::setUp(); + $this->_em = $this->_getTestEntityManager(); + } + + public function testSingleAliasDeclarationIsSupported() + { + $entityManager = $this->_em; + $query = $entityManager->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u'); + $parserResult = $query->parse(); + + $decl = $parserResult->getQueryComponent('u'); + + $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); + $this->assertEquals(null, $decl['relation']); + $this->assertEquals(null, $decl['parent']); + $this->assertEquals(null, $decl['scalar']); + $this->assertEquals(null, $decl['map']); + } + + public function testSingleAliasDeclarationWithIndexByIsSupported() + { + $entityManager = $this->_em; + $query = $entityManager->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INDEX BY u.id'); + $parserResult = $query->parse(); + + $decl = $parserResult->getQueryComponent('u'); + + $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); + $this->assertEquals(null, $decl['relation']); + $this->assertEquals(null, $decl['parent']); + $this->assertEquals(null, $decl['scalar']); + $this->assertEquals('id', $decl['map']); + } + + public function testQueryParserSupportsMultipleAliasDeclarations() + { + $entityManager = $this->_em; + $query = $entityManager->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INDEX BY u.id LEFT JOIN u.phonenumbers p'); + $parserResult = $query->parse(); + + $decl = $parserResult->getQueryComponent('u'); + + $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); + $this->assertEquals(null, $decl['relation']); + $this->assertEquals(null, $decl['parent']); + $this->assertEquals(null, $decl['scalar']); + $this->assertEquals('id', $decl['map']); + + $decl = $parserResult->getQueryComponent('p'); + + $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); + $this->assertTrue($decl['relation'] instanceof \Doctrine\ORM\Mapping\AssociationMapping); + $this->assertEquals('u', $decl['parent']); + $this->assertEquals(null, $decl['scalar']); + $this->assertEquals(null, $decl['map']); + } + + + public function testQueryParserSupportsMultipleAliasDeclarationsWithIndexBy() + { + $entityManager = $this->_em; + $query = $entityManager->createQuery('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INDEX BY u.id LEFT JOIN u.articles a INNER JOIN u.phonenumbers pn INDEX BY pn.phonenumber'); + $parserResult = $query->parse(); + + $decl = $parserResult->getQueryComponent('u'); + + $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); + $this->assertEquals(null, $decl['relation']); + $this->assertEquals(null, $decl['parent']); + $this->assertEquals(null, $decl['scalar']); + $this->assertEquals('id', $decl['map']); + + $decl = $parserResult->getQueryComponent('a'); + + $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); + $this->assertTrue($decl['relation'] instanceof \Doctrine\ORM\Mapping\AssociationMapping); + $this->assertEquals('u', $decl['parent']); + $this->assertEquals(null, $decl['scalar']); + $this->assertEquals(null, $decl['map']); + + $decl = $parserResult->getQueryComponent('pn'); + + $this->assertTrue($decl['metadata'] instanceof \Doctrine\ORM\Mapping\ClassMetadata); + $this->assertTrue($decl['relation'] instanceof \Doctrine\ORM\Mapping\AssociationMapping); + $this->assertEquals('u', $decl['parent']); + $this->assertEquals(null, $decl['scalar']); + $this->assertEquals('phonenumber', $decl['map']); + } +}