From cc7b1367fa4252aff8f261e34e7a11b99c9b9185 Mon Sep 17 00:00:00 2001 From: zYne Date: Sun, 1 Jul 2007 11:27:45 +0000 Subject: [PATCH] support for expressional column values --- lib/Doctrine/Adapter/Statement.php | 30 +- lib/Doctrine/Adapter/Statement/Mock.php | 281 +++++++++- lib/Doctrine/Connection.php | 17 +- lib/Doctrine/Connection/UnitOfWork.php | 22 +- lib/Doctrine/Expression.php | 654 +--------------------- lib/Doctrine/Expression/Driver.php | 686 ++++++++++++++++++++++++ lib/Doctrine/Expression/Firebird.php | 4 +- lib/Doctrine/Expression/Mock.php | 35 ++ lib/Doctrine/Expression/Mssql.php | 10 +- lib/Doctrine/Expression/Mysql.php | 4 +- lib/Doctrine/Expression/Oracle.php | 4 +- lib/Doctrine/Expression/Pgsql.php | 4 +- lib/Doctrine/Expression/Sqlite.php | 4 +- lib/Doctrine/Record.php | 4 +- tests/Expression/DriverTestCase.php | 171 ++++++ tests/ExpressionTestCase.php | 160 +----- tests/UnitTestCase.php | 1 - tests/run.php | 1 + 18 files changed, 1276 insertions(+), 816 deletions(-) create mode 100644 lib/Doctrine/Expression/Driver.php create mode 100644 lib/Doctrine/Expression/Mock.php create mode 100644 tests/Expression/DriverTestCase.php diff --git a/lib/Doctrine/Adapter/Statement.php b/lib/Doctrine/Adapter/Statement.php index cbd039b56..ffa59820c 100644 --- a/lib/Doctrine/Adapter/Statement.php +++ b/lib/Doctrine/Adapter/Statement.php @@ -34,6 +34,33 @@ abstract class Doctrine_Adapter_Statement public function bindValue($no, $value) { } + /** + * fetch + * + * @see Doctrine::FETCH_* constants + * @param integer $fetchStyle Controls how the next row will be returned to the caller. + * This value must be one of the Doctrine::FETCH_* constants, + * defaulting to Doctrine::FETCH_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 Doctrine::FETCH_ORI_* constants, defaulting to + * Doctrine::FETCH_ORI_NEXT. To request a scrollable cursor for your + * Doctrine_Adapter_Statement_Interface object, + * you must set the Doctrine::ATTR_CURSOR attribute to Doctrine::CURSOR_SCROLL when you + * prepare the SQL statement with Doctrine_Adapter_Interface->prepare(). + * + * @param integer $cursorOffset For a Doctrine_Adapter_Statement_Interface object representing a scrollable cursor for which the + * $cursorOrientation parameter is set to Doctrine::FETCH_ORI_ABS, this value specifies + * the absolute number of the row in the result set that shall be fetched. + * + * For a Doctrine_Adapter_Statement_Interface object representing a scrollable cursor for + * which the $cursorOrientation parameter is set to Doctrine::FETCH_ORI_REL, this value + * specifies the row to fetch relative to the cursor position before + * Doctrine_Adapter_Statement_Interface->fetch() was called. + * + * @return mixed + */ public function fetch() { } @@ -55,6 +82,7 @@ abstract class Doctrine_Adapter_Statement public function setFetchMode($mode) { } - public function columnCount(){ + public function columnCount() + { } } diff --git a/lib/Doctrine/Adapter/Statement/Mock.php b/lib/Doctrine/Adapter/Statement/Mock.php index dc7cc2863..449d1b513 100644 --- a/lib/Doctrine/Adapter/Statement/Mock.php +++ b/lib/Doctrine/Adapter/Statement/Mock.php @@ -31,7 +31,7 @@ * @since 1.0 * @version $Revision$ */ -class Doctrine_Adapter_Statement_Mock +class Doctrine_Adapter_Statement_Mock implements Doctrine_Adapter_Statement_Interface { private $mock; @@ -41,27 +41,294 @@ class Doctrine_Adapter_Statement_Mock { $this->mock = $mock; } - public function fetch($fetchMode) + /** + * bindColumn + * 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 Doctrine::PARAM_* constants. + * @return boolean Returns TRUE on success or FALSE on failure + */ + public function bindColumn($column, $param, $type = null) + { + + } + /** + * 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 Doctrine::PARAM_* constants. + * + * @return boolean Returns TRUE on success or FALSE on failure. + */ + public function bindValue($param, $value, $type = null) + { + + } + /** + * bindParam + * Binds a PHP variable to a corresponding named or question mark placeholder in the + * SQL statement that was use to prepare the statement. Unlike Doctrine_Adapter_Statement_Interface->bindValue(), + * the variable is bound as a reference and will only be evaluated at the time + * that Doctrine_Adapter_Statement_Interface->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 Doctrine::PARAM_* constants. To return + * an INOUT parameter from a stored procedure, use the bitwise OR operator to set the + * Doctrine::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() + { + return true; + } + /** + * columnCount + * Returns the number of columns in the result set + * + * @return integer Returns the number of columns in the result set represented + * by the Doctrine_Adapter_Statement_Interface object. If there is no result set, + * this method should return 0. + */ + public function columnCount() + { + return 0; + } + /** + * 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() { return array(); } - public function fetchAll($fetchMode) + /** + * 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() + { + return array(); + } + /** + * fetch + * + * @see Doctrine::FETCH_* constants + * @param integer $fetchStyle Controls how the next row will be returned to the caller. + * This value must be one of the Doctrine::FETCH_* constants, + * defaulting to Doctrine::FETCH_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 Doctrine::FETCH_ORI_* constants, defaulting to + * Doctrine::FETCH_ORI_NEXT. To request a scrollable cursor for your + * Doctrine_Adapter_Statement_Interface object, + * you must set the Doctrine::ATTR_CURSOR attribute to Doctrine::CURSOR_SCROLL when you + * prepare the SQL statement with Doctrine_Adapter_Interface->prepare(). + * + * @param integer $cursorOffset For a Doctrine_Adapter_Statement_Interface object representing a scrollable cursor for which the + * $cursorOrientation parameter is set to Doctrine::FETCH_ORI_ABS, this value specifies + * the absolute number of the row in the result set that shall be fetched. + * + * For a Doctrine_Adapter_Statement_Interface object representing a scrollable cursor for + * which the $cursorOrientation parameter is set to Doctrine::FETCH_ORI_REL, this value + * specifies the row to fetch relative to the cursor position before + * Doctrine_Adapter_Statement_Interface->fetch() was called. + * + * @return mixed + */ + public function fetch($fetchStyle = Doctrine::FETCH_BOTH, + $cursorOrientation = Doctrine::FETCH_ORI_NEXT, + $cursorOffset = null) { return array(); } - public function execute() + /** + * 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 Doctrine::FETCH_* constants, + * defaulting to Doctrine::FETCH_BOTH + * + * @param integer $columnIndex Returns the indicated 0-indexed column when the value of $fetchStyle is + * Doctrine::FETCH_COLUMN. Defaults to 0. + * + * @return array + */ + public function fetchAll($fetchMode = Doctrine::FETCH_BOTH) + { + return array(); + } + /** + * execute + * 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) { if(is_object($this->mock)) { $this->mock->addQuery($this->queryString); } return true; } - public function fetchColumn($colnum = 0) + /** + * 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, Doctrine_Adapter_Statement_Interface->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 0; } - public function closeCursor() + /** + * 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 + * Doctrine_Adapter_Statement_Interface->fetch() with Doctrine::FETCH_CLASS or Doctrine::FETCH_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 true; + return new $className(); } + /** + * 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() + { + return true; + } + /** + * 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() + { + return 0; + } + /** + * 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) + { } + /** + * getAttribute + * Retrieve a statement attribute + * + * @param integer $attribute + * @see Doctrine::ATTR_* constants + * @return mixed the attribute value + */ + public function getAttribute($attribute) + { } + /** + * 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 Doctrine::FETCH_* constants. + * @return boolean Returns 1 on success or FALSE on failure. + */ + public function setFetchMode($mode, $arg1 = null, $arg2 = null) + { } } diff --git a/lib/Doctrine/Connection.php b/lib/Doctrine/Connection.php index 1f122c643..ebdb8c27e 100644 --- a/lib/Doctrine/Connection.php +++ b/lib/Doctrine/Connection.php @@ -474,10 +474,23 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun // build the statement $query = 'INSERT INTO ' . $this->quoteIdentifier($table) . '(' . implode(', ', $cols) . ') ' - . 'VALUES (' . substr(str_repeat('?, ', count($values)), 0, -2) . ')'; + . 'VALUES ('; + + $a = array(); + foreach ($values as $k => $value) { + if ($value instanceof Doctrine_Expression) { + $value = $value->getSql(); + unset($values[$k]); + } else { + $value = '?'; + } + $a[] = $value; + } + $query .= implode(', ', $a) . ')'; // prepare and execute the statement - $this->execute($query, array_values($values)); + + $this->exec($query, array_values($values)); return true; } diff --git a/lib/Doctrine/Connection/UnitOfWork.php b/lib/Doctrine/Connection/UnitOfWork.php index a1542afae..ba63aed94 100644 --- a/lib/Doctrine/Connection/UnitOfWork.php +++ b/lib/Doctrine/Connection/UnitOfWork.php @@ -139,7 +139,7 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module */ public function saveGraph(Doctrine_Record $record) { - $conn = $this->getConnection(); + $conn = $this->getConnection(); if ($conn->transaction->isSaved($record)) { return false; @@ -383,16 +383,22 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module if (empty($array)) { return false; } - $set = array(); + $set = array(); foreach ($array as $name => $value) { - $set[] = $name . ' = ?'; + if ($value instanceof Doctrine_Expression) { + $set[] = $value->getSql(); + unset($array[$name]); + } else { + + $set[] = $name . ' = ?'; - if ($value instanceof Doctrine_Record) { - if ( ! $value->exists()) { - $record->save($this->conn); + if ($value instanceof Doctrine_Record) { + if ( ! $value->exists()) { + $record->save($this->conn); + } + $array[$name] = $value->getIncremented(); + $record->set($name, $value->getIncremented()); } - $array[$name] = $value->getIncremented(); - $record->set($name, $value->getIncremented()); } } diff --git a/lib/Doctrine/Expression.php b/lib/Doctrine/Expression.php index 647f1420e..13a828796 100644 --- a/lib/Doctrine/Expression.php +++ b/lib/Doctrine/Expression.php @@ -30,657 +30,17 @@ Doctrine::autoload('Doctrine_Connection_Module'); * @version $Revision$ * @author Konsta Vesterinen */ -class Doctrine_Expression extends Doctrine_Connection_Module +class Doctrine_Expression { - public function getIdentifier($column) - { - return $column; - } - public function getIdentifiers($columns) - { - return $columns; - } - /** - * regexp - * returns the regular expression operator - * - * @return string - */ - public function regexp() - { - throw new Doctrine_Expression_Exception('Regular expression operator is not supported by this database driver.'); - } - /** - * Returns the average value of a column - * - * @param string $column the column to use - * @return string generated sql including an AVG aggregate function - */ - public function avg($column) - { - $column = $this->getIdentifier($column); - return 'AVG(' . $column . ')'; - } + protected $_expression; - /** - * Returns the number of rows (without a NULL value) of a column - * - * If a '*' is used instead of a column the number of selected rows - * is returned. - * - * @param string|integer $column the column to use - * @return string generated sql including a COUNT aggregate function - */ - public function count($column) + public function __construct($expression) { - $column = $this->getIdentifier($column); - return 'COUNT(' . $column . ')'; + $this->_expression = $expression; } - - /** - * Returns the highest value of a column - * - * @param string $column the column to use - * @return string generated sql including a MAX aggregate function - */ - public function max($column) + + public function getSql() { - $column = $this->getIdentifier($column); - return 'MAX(' . $column . ')'; - } - - /** - * Returns the lowest value of a column - * - * @param string $column the column to use - * @return string - */ - public function min($column) - { - $column = $this->getIdentifier($column); - return 'MIN(' . $column . ')'; - } - - /** - * Returns the total sum of a column - * - * @param string $column the column to use - * @return string - */ - public function sum($column) - { - $column = $this->getIdentifier($column); - return 'SUM(' . $column . ')'; - } - - // scalar functions - - /** - * Returns the md5 sum of a field. - * - * Note: Not SQL92, but common functionality - * - * @return string - */ - public function md5($column) - { - $column = $this->getIdentifier($column); - return 'MD5(' . $column . ')'; - } - - /** - * Returns the length of a text field. - * - * @param string $expression1 - * @param string $expression2 - * @return string - */ - public function length($column) - { - $column = $this->getIdentifier($column); - return 'LENGTH(' . $column . ')'; - } - - /** - * Rounds a numeric field to the number of decimals specified. - * - * @param string $expression1 - * @param string $expression2 - * @return string - */ - public function round($column, $decimals = 0) - { - $column = $this->getIdentifier($column); - - return 'ROUND(' . $column . ', ' . $decimals . ')'; - } - - /** - * Returns the remainder of the division operation - * $expression1 / $expression2. - * - * @param string $expression1 - * @param string $expression2 - * @return string - */ - public function mod($expression1, $expression2) - { - $expression1 = $this->getIdentifier($expression1); - $expression2 = $this->getIdentifier($expression2); - return 'MOD(' . $expression1 . ', ' . $expression2 . ')'; - } - /** - * ltrim - * returns the string $str with leading space characters removed - * - * @param string $str literal string or column name - * @return string - */ - public function ltrim($str) - { - return 'LTRIM(' . $str . ')'; - } - /** - * upper - * Returns the string $str with all characters changed to - * uppercase according to the current character set mapping. - * - * @param string $str literal string or column name - * @return string - */ - public function upper($str) - { - return 'UPPER(' . $str . ')'; - } - /** - * lower - * Returns the string $str with all characters changed to - * lowercase according to the current character set mapping. - * - * @param string $str literal string or column name - * @return string - */ - public function lower($str) - { - return 'LOWER(' . $str . ')'; - } - /** - * locate - * returns the position of the first occurrence of substring $substr in string $str - * - * @param string $substr literal string to find - * @param string $str literal string - * @return integer - */ - public function locate($str, $substr) - { - return 'LOCATE(' . $str . ', ' . $substr . ')'; - } - /** - * Returns the current system date. - * - * @return string - */ - public function now() - { - return 'NOW()'; - } - /** - * soundex - * Returns a string to call a function to compute the - * soundex encoding of a string - * - * The string "?000" is returned if the argument is NULL. - * - * @param string $value - * @return string SQL soundex function with given parameter - */ - public function soundex($value) - { - throw new Doctrine_Expression_Exception('SQL soundex function not supported by this driver.'); - } - /** - * return string to call a function to get a substring inside an SQL statement - * - * Note: Not SQL92, but common functionality. - * - * SQLite only supports the 2 parameter variant of this function - * - * @param string $value an sql string literal or column name/alias - * @param integer $position where to start the substring portion - * @param integer $length the substring portion length - * @return string SQL substring function with given parameters - */ - public function substring($value, $from, $len = null) - { - $value = $this->getIdentifier($value); - if ($len === null) - return 'SUBSTRING(' . $value . ' FROM ' . $from . ')'; - else { - $len = $this->getIdentifier($len); - return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $len . ')'; - } - } - /** - * Returns a series of strings concatinated - * - * concat() accepts an arbitrary number of parameters. Each parameter - * must contain an expression or an array with expressions. - * - * @param string|array(string) strings that will be concatinated. - */ - public function concat() - { - $args = func_get_args(); - - return 'CONCAT(' . join(', ', (array) $args) . ')'; - } - /** - * Returns the SQL for a logical not. - * - * Example: - * - * $q = new Doctrine_Query(); - * $e = $q->expr; - * $q->select('*')->from('table') - * ->where($e->eq('id', $e->not('null')); - * - * - * @return string a logical expression - */ - public function not($expression) - { - $expression = $this->getIdentifier($expression); - return 'NOT(' . $expression . ')'; - } - /** - * Returns the SQL to perform the same mathematical operation over an array - * of values or expressions. - * - * basicMath() accepts an arbitrary number of parameters. Each parameter - * must contain a value or an expression or an array with values or - * expressions. - * - * @param string $type the type of operation, can be '+', '-', '*' or '/'. - * @param string|array(string) - * @return string an expression - */ - private function basicMath($type, array $args) - { - $elements = $this->getIdentifiers($args); - if (count($elements) < 1) { - return ''; - } - if (count($elements) == 1) { - return $elements[0]; - } else { - return '(' . implode(' ' . $type . ' ', $elements) . ')'; - } - } - /** - * Returns the SQL to add values or expressions together. - * - * add() accepts an arbitrary number of parameters. Each parameter - * must contain a value or an expression or an array with values or - * expressions. - * - * Example: - * - * $q = new Doctrine_Query(); - * $e = $q->expr; - * - * $q->select('u.*') - * ->from('User u') - * ->where($e->eq($e->add('id', 2), 12)); - * - * - * @param string|array(string) - * @return string an expression - */ - public function add(array $args) - { - return $this->basicMath('+', $args); - } - - /** - * Returns the SQL to subtract values or expressions from eachother. - * - * subtract() accepts an arbitrary number of parameters. Each parameter - * must contain a value or an expression or an array with values or - * expressions. - * - * Example: - * - * $q = new Doctrine_Query(); - * $e = $q->expr; - * - * $q->select('u.*') - * ->from('User u') - * ->where($e->eq($e->sub('id', 2), 12)); - * - * - * @param string|array(string) - * @return string an expression - */ - public function sub(array $args) - { - return $this->basicMath('-', $args ); - } - - /** - * Returns the SQL to multiply values or expressions by eachother. - * - * multiply() accepts an arbitrary number of parameters. Each parameter - * must contain a value or an expression or an array with values or - * expressions. - * - * Example: - * - * $q = new Doctrine_Query(); - * $e = $q->expr; - * - * $q->select('u.*') - * ->from('User u') - * ->where($e->eq($e->mul('id', 2), 12)); - * - * - * @param string|array(string) - * @return string an expression - */ - public function mul(array $args) - { - return $this->basicMath('*', $args); - } - - /** - * Returns the SQL to divide values or expressions by eachother. - * - * divide() accepts an arbitrary number of parameters. Each parameter - * must contain a value or an expression or an array with values or - * expressions. - * - * Example: - * - * $q = new Doctrine_Query(); - * $e = $q->expr; - * - * $q->select('u.*') - * ->from('User u') - * ->where($e->eq($e->div('id', 2), 12)); - * - * - * @param string|array(string) - * @return string an expression - */ - public function div(array $args) - { - return $this->basicMath('/', $args); - } - - /** - * Returns the SQL to check if two values are equal. - * - * Example: - * - * $q = new Doctrine_Query(); - * $q->select('u.*') - * ->from('User u') - * ->where($q->expr->eq('id', 1)); - * - * - * @param string $value1 logical expression to compare - * @param string $value2 logical expression to compare with - * @return string logical expression - */ - public function eq($value1, $value2) - { - $value1 = $this->getIdentifier($value1); - $value2 = $this->getIdentifier($value2); - return $value1 . ' = ' . $value2; - } - - /** - * Returns the SQL to check if two values are unequal. - * - * Example: - * - * $q = new Doctrine_Query(); - * $q->select('u.*') - * ->from('User u') - * ->where($q->expr->neq('id', 1)); - * - * - * @param string $value1 logical expression to compare - * @param string $value2 logical expression to compare with - * @return string logical expression - */ - public function neq($value1, $value2) - { - $value1 = $this->getIdentifier($value1); - $value2 = $this->getIdentifier($value2); - return $value1 . ' <> ' . $value2; - } - - /** - * Returns the SQL to check if one value is greater than another value. - * - * Example: - * - * $q = new Doctrine_Query(); - * $q->select('u.*') - * ->from('User u') - * ->where($q->expr->gt('id', 1)); - * - * - * @param string $value1 logical expression to compare - * @param string $value2 logical expression to compare with - * @return string logical expression - */ - public function gt($value1, $value2) - { - $value1 = $this->getIdentifier($value1); - $value2 = $this->getIdentifier($value2); - return $value1 . ' > ' . $value2; - } - - /** - * Returns the SQL to check if one value is greater than or equal to - * another value. - * - * Example: - * - * $q = new Doctrine_Query(); - * $q->select('u.*') - * ->from('User u') - * ->where($q->expr->gte('id', 1)); - * - * - * @param string $value1 logical expression to compare - * @param string $value2 logical expression to compare with - * @return string logical expression - */ - public function gte($value1, $value2) - { - $value1 = $this->getIdentifier($value1); - $value2 = $this->getIdentifier($value2); - return $value1 . ' >= ' . $value2; - } - - /** - * Returns the SQL to check if one value is less than another value. - * - * Example: - * - * $q = new Doctrine_Query(); - * $q->select('u.*') - * ->from('User u') - * ->where($q->expr->lt('id', 1)); - * - * - * @param string $value1 logical expression to compare - * @param string $value2 logical expression to compare with - * @return string logical expression - */ - public function lt($value1, $value2) - { - $value1 = $this->getIdentifier($value1); - $value2 = $this->getIdentifier($value2); - return $value1 . ' < ' . $value2; - } - - /** - * Returns the SQL to check if one value is less than or equal to - * another value. - * - * Example: - * - * $q = new Doctrine_Query(); - * $q->select('u.*') - * ->from('User u') - * ->where($q->expr->lte('id', 1)); - * - * - * @param string $value1 logical expression to compare - * @param string $value2 logical expression to compare with - * @return string logical expression - */ - public function lte($value1, $value2) - { - $value1 = $this->getIdentifier($value1); - $value2 = $this->getIdentifier($value2); - return $value1 . ' <= ' . $value2; - } - - /** - * Returns the SQL to check if a value is one in a set of - * given values.. - * - * in() accepts an arbitrary number of parameters. The first parameter - * must always specify the value that should be matched against. Successive - * must contain a logical expression or an array with logical expressions. - * These expressions will be matched against the first parameter. - * - * Example: - * - * $q = new Doctrine_Query(); - * $q->select('u.*') - * ->from('User u') - * ->where($q->expr->in( 'id', array(1,2,3))); - * - * - * @param string $column the value that should be matched against - * @param string|array(string) values that will be matched against $column - * @return string logical expression - */ - public function in($column, $values) - { - if ( ! is_array($values)) { - $values = array($values); - } - $values = $this->getIdentifiers($values); - $column = $this->getIdentifier($column); - - if (count($values) == 0) { - throw new Doctrine_Expression_Exception('Values array for IN operator should not be empty.'); - } - return $column . ' IN (' . implode(', ', $values) . ')'; - } - /** - * Returns SQL that checks if a expression is null. - * - * Example: - * - * $q = new Doctrine_Query(); - * $q->select('u.*') - * ->from('User u') - * ->where($q->expr->isNull('id')); - * - * - * @param string $expression the expression that should be compared to null - * @return string logical expression - */ - public function isNull($expression) - { - $expression = $this->getIdentifier($expression); - return $expression . ' IS NULL'; - } - /** - * Returns SQL that checks if a expression is not null. - * - * Example: - * - * $q = new Doctrine_Query(); - * $q->select('u.*') - * ->from('User u') - * ->where($q->expr->isNotNull('id')); - * - * - * @param string $expression the expression that should be compared to null - * @return string logical expression - */ - public function isNotNull($expression) - { - $expression = $this->getIdentifier($expression); - return $expression . ' IS NOT NULL'; - } - /** - * Returns SQL that checks if an expression evaluates to a value between - * two values. - * - * The parameter $expression is checked if it is between $value1 and $value2. - * - * Note: There is a slight difference in the way BETWEEN works on some databases. - * http://www.w3schools.com/sql/sql_between.asp. If you want complete database - * independence you should avoid using between(). - * - * Example: - * - * $q = new Doctrine_Query(); - * $q->select('u.*') - * ->from('User u') - * ->where($q->expr->between('id', 1, 5)); - * - * - * @param string $expression the value to compare to - * @param string $value1 the lower value to compare with - * @param string $value2 the higher value to compare with - * @return string logical expression - */ - public function between($expression, $value1, $value2) - { - $expression = $this->getIdentifier($expression); - $value1 = $this->getIdentifier($value1); - $value2 = $this->getIdentifier($value2); - return $expression . ' BETWEEN ' .$value1 . ' AND ' . $value2; - } - /** - * Returns global unique identifier - * - * @return string to get global unique identifier - */ - public function guid() - { - throw new Doctrine_Expression_Exception('method not implemented'); - } - /** - * returns arcus cosine SQL string - * - * @return string - */ - public function acos($value) - { - return 'ACOS(' . $value . ')'; - } - /** - * __call - * - * for all native RDBMS functions the function name itself is returned - */ - public function __call($m, $a) - { - if ($this->conn->getAttribute(Doctrine::ATTR_PORTABILITY) & Doctrine::PORTABILITY_EXPR) { - throw new Doctrine_Expression_Exception('Unknown expression ' . $m); - } - return $m . '()'; + return $this->_expression; } } diff --git a/lib/Doctrine/Expression/Driver.php b/lib/Doctrine/Expression/Driver.php new file mode 100644 index 000000000..344e516fc --- /dev/null +++ b/lib/Doctrine/Expression/Driver.php @@ -0,0 +1,686 @@ +. + */ +Doctrine::autoload('Doctrine_Connection_Module'); +/** + * Doctrine_Expression_Driver + * + * @package Doctrine + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + * @author Konsta Vesterinen + */ +class Doctrine_Expression_Driver extends Doctrine_Connection_Module +{ + public function getIdentifier($column) + { + return $column; + } + public function getIdentifiers($columns) + { + return $columns; + } + /** + * regexp + * returns the regular expression operator + * + * @return string + */ + public function regexp() + { + throw new Doctrine_Expression_Exception('Regular expression operator is not supported by this database driver.'); + } + /** + * Returns the average value of a column + * + * @param string $column the column to use + * @return string generated sql including an AVG aggregate function + */ + public function avg($column) + { + $column = $this->getIdentifier($column); + return 'AVG(' . $column . ')'; + } + + /** + * Returns the number of rows (without a NULL value) of a column + * + * If a '*' is used instead of a column the number of selected rows + * is returned. + * + * @param string|integer $column the column to use + * @return string generated sql including a COUNT aggregate function + */ + public function count($column) + { + $column = $this->getIdentifier($column); + return 'COUNT(' . $column . ')'; + } + + /** + * Returns the highest value of a column + * + * @param string $column the column to use + * @return string generated sql including a MAX aggregate function + */ + public function max($column) + { + $column = $this->getIdentifier($column); + return 'MAX(' . $column . ')'; + } + + /** + * Returns the lowest value of a column + * + * @param string $column the column to use + * @return string + */ + public function min($column) + { + $column = $this->getIdentifier($column); + return 'MIN(' . $column . ')'; + } + + /** + * Returns the total sum of a column + * + * @param string $column the column to use + * @return string + */ + public function sum($column) + { + $column = $this->getIdentifier($column); + return 'SUM(' . $column . ')'; + } + + // scalar functions + + /** + * Returns the md5 sum of a field. + * + * Note: Not SQL92, but common functionality + * + * @return string + */ + public function md5($column) + { + $column = $this->getIdentifier($column); + return 'MD5(' . $column . ')'; + } + + /** + * Returns the length of a text field. + * + * @param string $expression1 + * @param string $expression2 + * @return string + */ + public function length($column) + { + $column = $this->getIdentifier($column); + return 'LENGTH(' . $column . ')'; + } + + /** + * Rounds a numeric field to the number of decimals specified. + * + * @param string $expression1 + * @param string $expression2 + * @return string + */ + public function round($column, $decimals = 0) + { + $column = $this->getIdentifier($column); + + return 'ROUND(' . $column . ', ' . $decimals . ')'; + } + + /** + * Returns the remainder of the division operation + * $expression1 / $expression2. + * + * @param string $expression1 + * @param string $expression2 + * @return string + */ + public function mod($expression1, $expression2) + { + $expression1 = $this->getIdentifier($expression1); + $expression2 = $this->getIdentifier($expression2); + return 'MOD(' . $expression1 . ', ' . $expression2 . ')'; + } + /** + * ltrim + * returns the string $str with leading space characters removed + * + * @param string $str literal string or column name + * @return string + */ + public function ltrim($str) + { + return 'LTRIM(' . $str . ')'; + } + /** + * upper + * Returns the string $str with all characters changed to + * uppercase according to the current character set mapping. + * + * @param string $str literal string or column name + * @return string + */ + public function upper($str) + { + return 'UPPER(' . $str . ')'; + } + /** + * lower + * Returns the string $str with all characters changed to + * lowercase according to the current character set mapping. + * + * @param string $str literal string or column name + * @return string + */ + public function lower($str) + { + return 'LOWER(' . $str . ')'; + } + /** + * locate + * returns the position of the first occurrence of substring $substr in string $str + * + * @param string $substr literal string to find + * @param string $str literal string + * @return integer + */ + public function locate($str, $substr) + { + return 'LOCATE(' . $str . ', ' . $substr . ')'; + } + /** + * Returns the current system date. + * + * @return string + */ + public function now() + { + return 'NOW()'; + } + /** + * soundex + * Returns a string to call a function to compute the + * soundex encoding of a string + * + * The string "?000" is returned if the argument is NULL. + * + * @param string $value + * @return string SQL soundex function with given parameter + */ + public function soundex($value) + { + throw new Doctrine_Expression_Exception('SQL soundex function not supported by this driver.'); + } + /** + * return string to call a function to get a substring inside an SQL statement + * + * Note: Not SQL92, but common functionality. + * + * SQLite only supports the 2 parameter variant of this function + * + * @param string $value an sql string literal or column name/alias + * @param integer $position where to start the substring portion + * @param integer $length the substring portion length + * @return string SQL substring function with given parameters + */ + public function substring($value, $from, $len = null) + { + $value = $this->getIdentifier($value); + if ($len === null) + return 'SUBSTRING(' . $value . ' FROM ' . $from . ')'; + else { + $len = $this->getIdentifier($len); + return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $len . ')'; + } + } + /** + * Returns a series of strings concatinated + * + * concat() accepts an arbitrary number of parameters. Each parameter + * must contain an expression or an array with expressions. + * + * @param string|array(string) strings that will be concatinated. + */ + public function concat() + { + $args = func_get_args(); + + return 'CONCAT(' . join(', ', (array) $args) . ')'; + } + /** + * Returns the SQL for a logical not. + * + * Example: + * + * $q = new Doctrine_Query(); + * $e = $q->expr; + * $q->select('*')->from('table') + * ->where($e->eq('id', $e->not('null')); + * + * + * @return string a logical expression + */ + public function not($expression) + { + $expression = $this->getIdentifier($expression); + return 'NOT(' . $expression . ')'; + } + /** + * Returns the SQL to perform the same mathematical operation over an array + * of values or expressions. + * + * basicMath() accepts an arbitrary number of parameters. Each parameter + * must contain a value or an expression or an array with values or + * expressions. + * + * @param string $type the type of operation, can be '+', '-', '*' or '/'. + * @param string|array(string) + * @return string an expression + */ + private function basicMath($type, array $args) + { + $elements = $this->getIdentifiers($args); + if (count($elements) < 1) { + return ''; + } + if (count($elements) == 1) { + return $elements[0]; + } else { + return '(' . implode(' ' . $type . ' ', $elements) . ')'; + } + } + /** + * Returns the SQL to add values or expressions together. + * + * add() accepts an arbitrary number of parameters. Each parameter + * must contain a value or an expression or an array with values or + * expressions. + * + * Example: + * + * $q = new Doctrine_Query(); + * $e = $q->expr; + * + * $q->select('u.*') + * ->from('User u') + * ->where($e->eq($e->add('id', 2), 12)); + * + * + * @param string|array(string) + * @return string an expression + */ + public function add(array $args) + { + return $this->basicMath('+', $args); + } + + /** + * Returns the SQL to subtract values or expressions from eachother. + * + * subtract() accepts an arbitrary number of parameters. Each parameter + * must contain a value or an expression or an array with values or + * expressions. + * + * Example: + * + * $q = new Doctrine_Query(); + * $e = $q->expr; + * + * $q->select('u.*') + * ->from('User u') + * ->where($e->eq($e->sub('id', 2), 12)); + * + * + * @param string|array(string) + * @return string an expression + */ + public function sub(array $args) + { + return $this->basicMath('-', $args ); + } + + /** + * Returns the SQL to multiply values or expressions by eachother. + * + * multiply() accepts an arbitrary number of parameters. Each parameter + * must contain a value or an expression or an array with values or + * expressions. + * + * Example: + * + * $q = new Doctrine_Query(); + * $e = $q->expr; + * + * $q->select('u.*') + * ->from('User u') + * ->where($e->eq($e->mul('id', 2), 12)); + * + * + * @param string|array(string) + * @return string an expression + */ + public function mul(array $args) + { + return $this->basicMath('*', $args); + } + + /** + * Returns the SQL to divide values or expressions by eachother. + * + * divide() accepts an arbitrary number of parameters. Each parameter + * must contain a value or an expression or an array with values or + * expressions. + * + * Example: + * + * $q = new Doctrine_Query(); + * $e = $q->expr; + * + * $q->select('u.*') + * ->from('User u') + * ->where($e->eq($e->div('id', 2), 12)); + * + * + * @param string|array(string) + * @return string an expression + */ + public function div(array $args) + { + return $this->basicMath('/', $args); + } + + /** + * Returns the SQL to check if two values are equal. + * + * Example: + * + * $q = new Doctrine_Query(); + * $q->select('u.*') + * ->from('User u') + * ->where($q->expr->eq('id', 1)); + * + * + * @param string $value1 logical expression to compare + * @param string $value2 logical expression to compare with + * @return string logical expression + */ + public function eq($value1, $value2) + { + $value1 = $this->getIdentifier($value1); + $value2 = $this->getIdentifier($value2); + return $value1 . ' = ' . $value2; + } + + /** + * Returns the SQL to check if two values are unequal. + * + * Example: + * + * $q = new Doctrine_Query(); + * $q->select('u.*') + * ->from('User u') + * ->where($q->expr->neq('id', 1)); + * + * + * @param string $value1 logical expression to compare + * @param string $value2 logical expression to compare with + * @return string logical expression + */ + public function neq($value1, $value2) + { + $value1 = $this->getIdentifier($value1); + $value2 = $this->getIdentifier($value2); + return $value1 . ' <> ' . $value2; + } + + /** + * Returns the SQL to check if one value is greater than another value. + * + * Example: + * + * $q = new Doctrine_Query(); + * $q->select('u.*') + * ->from('User u') + * ->where($q->expr->gt('id', 1)); + * + * + * @param string $value1 logical expression to compare + * @param string $value2 logical expression to compare with + * @return string logical expression + */ + public function gt($value1, $value2) + { + $value1 = $this->getIdentifier($value1); + $value2 = $this->getIdentifier($value2); + return $value1 . ' > ' . $value2; + } + + /** + * Returns the SQL to check if one value is greater than or equal to + * another value. + * + * Example: + * + * $q = new Doctrine_Query(); + * $q->select('u.*') + * ->from('User u') + * ->where($q->expr->gte('id', 1)); + * + * + * @param string $value1 logical expression to compare + * @param string $value2 logical expression to compare with + * @return string logical expression + */ + public function gte($value1, $value2) + { + $value1 = $this->getIdentifier($value1); + $value2 = $this->getIdentifier($value2); + return $value1 . ' >= ' . $value2; + } + + /** + * Returns the SQL to check if one value is less than another value. + * + * Example: + * + * $q = new Doctrine_Query(); + * $q->select('u.*') + * ->from('User u') + * ->where($q->expr->lt('id', 1)); + * + * + * @param string $value1 logical expression to compare + * @param string $value2 logical expression to compare with + * @return string logical expression + */ + public function lt($value1, $value2) + { + $value1 = $this->getIdentifier($value1); + $value2 = $this->getIdentifier($value2); + return $value1 . ' < ' . $value2; + } + + /** + * Returns the SQL to check if one value is less than or equal to + * another value. + * + * Example: + * + * $q = new Doctrine_Query(); + * $q->select('u.*') + * ->from('User u') + * ->where($q->expr->lte('id', 1)); + * + * + * @param string $value1 logical expression to compare + * @param string $value2 logical expression to compare with + * @return string logical expression + */ + public function lte($value1, $value2) + { + $value1 = $this->getIdentifier($value1); + $value2 = $this->getIdentifier($value2); + return $value1 . ' <= ' . $value2; + } + + /** + * Returns the SQL to check if a value is one in a set of + * given values.. + * + * in() accepts an arbitrary number of parameters. The first parameter + * must always specify the value that should be matched against. Successive + * must contain a logical expression or an array with logical expressions. + * These expressions will be matched against the first parameter. + * + * Example: + * + * $q = new Doctrine_Query(); + * $q->select('u.*') + * ->from('User u') + * ->where($q->expr->in( 'id', array(1,2,3))); + * + * + * @param string $column the value that should be matched against + * @param string|array(string) values that will be matched against $column + * @return string logical expression + */ + public function in($column, $values) + { + if ( ! is_array($values)) { + $values = array($values); + } + $values = $this->getIdentifiers($values); + $column = $this->getIdentifier($column); + + if (count($values) == 0) { + throw new Doctrine_Expression_Exception('Values array for IN operator should not be empty.'); + } + return $column . ' IN (' . implode(', ', $values) . ')'; + } + /** + * Returns SQL that checks if a expression is null. + * + * Example: + * + * $q = new Doctrine_Query(); + * $q->select('u.*') + * ->from('User u') + * ->where($q->expr->isNull('id')); + * + * + * @param string $expression the expression that should be compared to null + * @return string logical expression + */ + public function isNull($expression) + { + $expression = $this->getIdentifier($expression); + return $expression . ' IS NULL'; + } + /** + * Returns SQL that checks if a expression is not null. + * + * Example: + * + * $q = new Doctrine_Query(); + * $q->select('u.*') + * ->from('User u') + * ->where($q->expr->isNotNull('id')); + * + * + * @param string $expression the expression that should be compared to null + * @return string logical expression + */ + public function isNotNull($expression) + { + $expression = $this->getIdentifier($expression); + return $expression . ' IS NOT NULL'; + } + /** + * Returns SQL that checks if an expression evaluates to a value between + * two values. + * + * The parameter $expression is checked if it is between $value1 and $value2. + * + * Note: There is a slight difference in the way BETWEEN works on some databases. + * http://www.w3schools.com/sql/sql_between.asp. If you want complete database + * independence you should avoid using between(). + * + * Example: + * + * $q = new Doctrine_Query(); + * $q->select('u.*') + * ->from('User u') + * ->where($q->expr->between('id', 1, 5)); + * + * + * @param string $expression the value to compare to + * @param string $value1 the lower value to compare with + * @param string $value2 the higher value to compare with + * @return string logical expression + */ + public function between($expression, $value1, $value2) + { + $expression = $this->getIdentifier($expression); + $value1 = $this->getIdentifier($value1); + $value2 = $this->getIdentifier($value2); + return $expression . ' BETWEEN ' .$value1 . ' AND ' . $value2; + } + /** + * Returns global unique identifier + * + * @return string to get global unique identifier + */ + public function guid() + { + throw new Doctrine_Expression_Exception('method not implemented'); + } + /** + * returns arcus cosine SQL string + * + * @return string + */ + public function acos($value) + { + return 'ACOS(' . $value . ')'; + } + /** + * __call + * + * for all native RDBMS functions the function name itself is returned + */ + public function __call($m, $a) + { + if ($this->conn->getAttribute(Doctrine::ATTR_PORTABILITY) & Doctrine::PORTABILITY_EXPR) { + throw new Doctrine_Expression_Exception('Unknown expression ' . $m); + } + return $m . '()'; + } +} diff --git a/lib/Doctrine/Expression/Firebird.php b/lib/Doctrine/Expression/Firebird.php index 5404496e4..68ebfe8f3 100644 --- a/lib/Doctrine/Expression/Firebird.php +++ b/lib/Doctrine/Expression/Firebird.php @@ -18,7 +18,7 @@ * and is licensed under the LGPL. For more information, see * . */ -Doctrine::autoload('Doctrine_Expression'); +Doctrine::autoload('Doctrine_Expression_Driver'); /** * Doctrine_Expression_Firebird * @@ -32,7 +32,7 @@ Doctrine::autoload('Doctrine_Expression'); * @author Lorenzo Alberton (PEAR MDB2 Interbase driver) * @author Lukas Smith (PEAR MDB2 library) */ -class Doctrine_Expression_Firebird extends Doctrine_Expression +class Doctrine_Expression_Firebird extends Doctrine_Expression_Driver { /** * return string for internal table used when calling only a function diff --git a/lib/Doctrine/Expression/Mock.php b/lib/Doctrine/Expression/Mock.php new file mode 100644 index 000000000..4048ce131 --- /dev/null +++ b/lib/Doctrine/Expression/Mock.php @@ -0,0 +1,35 @@ +. + */ +Doctrine::autoload('Doctrine_Connection_Module'); +/** + * Doctrine_Expression_Mock + * Mock driver that is used for testing purposes + * + * @package Doctrine + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + * @author Konsta Vesterinen + */ +class Doctrine_Expression_Mock extends Doctrine_Expression_Driver +{ } diff --git a/lib/Doctrine/Expression/Mssql.php b/lib/Doctrine/Expression/Mssql.php index d0da43a43..88ef21c03 100644 --- a/lib/Doctrine/Expression/Mssql.php +++ b/lib/Doctrine/Expression/Mssql.php @@ -18,7 +18,7 @@ * and is licensed under the LGPL. For more information, see * . */ -Doctrine::autoload('Doctrine_Expression'); +Doctrine::autoload('Doctrine_Expression_Driver'); /** * Doctrine_Expression_Mssql * @@ -30,7 +30,7 @@ Doctrine::autoload('Doctrine_Expression'); * @version $Revision$ * @author Konsta Vesterinen */ -class Doctrine_Expression_Mssql extends Doctrine_Expression +class Doctrine_Expression_Mssql extends Doctrine_Expression_Driver { /** * Return string to call a variable with the current timestamp inside an SQL statement @@ -59,10 +59,10 @@ class Doctrine_Expression_Mssql extends Doctrine_Expression */ public function substring($value, $position, $length = null) { - if (!is_null($length)) { - return "SUBSTRING($value, $position, $length)"; + if ( ! is_null($length)) { + return 'SUBSTRING(' . $value . ', ' . $position . ', ' . $length . ')'; } - return "SUBSTRING($value, $position, LEN($value) - $position + 1)"; + return 'SUBSTRING(' . $value . ', ' . $position . ', LEN(' . $value . ') - ' . $position . ' + 1)'; } /** * Returns string to concatenate two or more string parameters diff --git a/lib/Doctrine/Expression/Mysql.php b/lib/Doctrine/Expression/Mysql.php index 6e9628033..136ac0986 100644 --- a/lib/Doctrine/Expression/Mysql.php +++ b/lib/Doctrine/Expression/Mysql.php @@ -18,7 +18,7 @@ * and is licensed under the LGPL. For more information, see * . */ -Doctrine::autoload('Doctrine_Expression'); +Doctrine::autoload('Doctrine_Expression_Driver'); /** * Doctrine_Expression_Mysql * @@ -30,7 +30,7 @@ Doctrine::autoload('Doctrine_Expression'); * @version $Revision$ * @author Konsta Vesterinen */ -class Doctrine_Expression_Mysql extends Doctrine_Expression +class Doctrine_Expression_Mysql extends Doctrine_Expression_Driver { /** * returns the regular expression operator diff --git a/lib/Doctrine/Expression/Oracle.php b/lib/Doctrine/Expression/Oracle.php index 081c1fb86..d70215484 100644 --- a/lib/Doctrine/Expression/Oracle.php +++ b/lib/Doctrine/Expression/Oracle.php @@ -18,7 +18,7 @@ * and is licensed under the LGPL. For more information, see * . */ -Doctrine::autoload('Doctrine_Expression'); +Doctrine::autoload('Doctrine_Expression_Driver'); /** * Doctrine_Expression_Sqlite * @@ -30,7 +30,7 @@ Doctrine::autoload('Doctrine_Expression'); * @version $Revision$ * @author Konsta Vesterinen */ -class Doctrine_Expression_Oracle extends Doctrine_Expression +class Doctrine_Expression_Oracle extends Doctrine_Expression_Driver { /** * Returns a series of strings concatinated diff --git a/lib/Doctrine/Expression/Pgsql.php b/lib/Doctrine/Expression/Pgsql.php index 5957f424a..b7eb58a13 100644 --- a/lib/Doctrine/Expression/Pgsql.php +++ b/lib/Doctrine/Expression/Pgsql.php @@ -18,7 +18,7 @@ * and is licensed under the LGPL. For more information, see * . */ -Doctrine::autoload('Doctrine_Expression'); +Doctrine::autoload('Doctrine_Expression_Driver'); /** * Doctrine_Expression_Pgsql * @@ -30,7 +30,7 @@ Doctrine::autoload('Doctrine_Expression'); * @version $Revision$ * @author Konsta Vesterinen */ -class Doctrine_Expression_Pgsql extends Doctrine_Expression +class Doctrine_Expression_Pgsql extends Doctrine_Expression_Driver { /** * Returns the md5 sum of a field. diff --git a/lib/Doctrine/Expression/Sqlite.php b/lib/Doctrine/Expression/Sqlite.php index 32de624c3..00913932b 100644 --- a/lib/Doctrine/Expression/Sqlite.php +++ b/lib/Doctrine/Expression/Sqlite.php @@ -18,7 +18,7 @@ * and is licensed under the LGPL. For more information, see * . */ -Doctrine::autoload('Doctrine_Expression'); +Doctrine::autoload('Doctrine_Expression_Driver'); /** * Doctrine_Expression_Sqlite * @@ -30,7 +30,7 @@ Doctrine::autoload('Doctrine_Expression'); * @version $Revision$ * @author Konsta Vesterinen */ -class Doctrine_Expression_Sqlite extends Doctrine_Expression +class Doctrine_Expression_Sqlite extends Doctrine_Expression_Driver { /** * Returns the md5 sum of the data that SQLite's md5() function receives. diff --git a/lib/Doctrine/Record.php b/lib/Doctrine/Record.php index 14f2c73bc..b8b4eb9aa 100644 --- a/lib/Doctrine/Record.php +++ b/lib/Doctrine/Record.php @@ -631,7 +631,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count $this->_data = $stmt->fetch(PDO::FETCH_ASSOC); if ( ! $this->_data) { - throw new Doctrine_Record_Exception('Failed to refresh. Record does not exist anymore'); + throw new Doctrine_Record_Exception('Failed to refresh. Record does not exist.'); } $this->_data = array_change_key_case($this->_data, CASE_LOWER); @@ -1049,7 +1049,7 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count default: if ($this->_data[$v] instanceof Doctrine_Record) { $this->_data[$v] = $this->_data[$v]->getIncremented(); - } + } $a[$v] = $this->_data[$v]; } diff --git a/tests/Expression/DriverTestCase.php b/tests/Expression/DriverTestCase.php new file mode 100644 index 000000000..da293cfd4 --- /dev/null +++ b/tests/Expression/DriverTestCase.php @@ -0,0 +1,171 @@ +. + */ + +/** + * Doctrine_Expression_Driver_TestCase + * + * @package Doctrine + * @author Konsta Vesterinen + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision$ + */ +class Doctrine_Expression_Driver_TestCase extends Doctrine_UnitTestCase { + + /** + * AGGREGATE FUNCTIONS + */ + public function testAvgReturnsValidSql() { + $this->expr = new Doctrine_Expression_Mock(); + + $this->assertEqual($this->expr->avg('id'), 'AVG(id)'); + } + public function testCountReturnsValidSql() { + $this->assertEqual($this->expr->count('id'), 'COUNT(id)'); + } + public function testMaxReturnsValidSql() { + $this->assertEqual($this->expr->max('id'), 'MAX(id)'); + } + public function testMinReturnsValidSql() { + $this->assertEqual($this->expr->min('id'), 'MIN(id)'); + } + public function testSumReturnsValidSql() { + $this->assertEqual($this->expr->sum('id'), 'SUM(id)'); + } + + public function testRegexpImplementedOnlyAtDriverLevel() { + try { + $this->expr->regexp('[abc]'); + $this->fail(); + } catch(Doctrine_Expression_Exception $e) { + $this->pass(); + } + } + public function testSoundexImplementedOnlyAtDriverLevel() { + try { + $this->expr->soundex('arnold'); + $this->fail(); + } catch(Doctrine_Expression_Exception $e) { + $this->pass(); + } + } + /** + * TIME FUNCTIONS + */ + public function testNowReturnsValidSql() { + $this->assertEqual($this->expr->now(), 'NOW()'); + } + + /** + * STRING FUNCTIONS + */ + public function testUpperReturnsValidSql() { + $this->assertEqual($this->expr->upper('id', 3), 'UPPER(id)'); + } + public function testLowerReturnsValidSql() { + $this->assertEqual($this->expr->lower('id'), 'LOWER(id)'); + } + public function testLengthReturnsValidSql() { + $this->assertEqual($this->expr->length('id'), 'LENGTH(id)'); + } + public function testLtrimReturnsValidSql() { + $this->assertEqual($this->expr->ltrim('id'), 'LTRIM(id)'); + } + public function testLocateReturnsValidSql() { + $this->assertEqual($this->expr->locate('id', 3), 'LOCATE(id, 3)'); + } + public function testConcatReturnsValidSql() { + $this->assertEqual($this->expr->concat('id', 'type'), 'CONCAT(id, type)'); + } + public function testSubstringReturnsValidSql() { + $this->assertEqual($this->expr->substring('id', 3), 'SUBSTRING(id FROM 3)'); + + $this->assertEqual($this->expr->substring('id', 3, 2), 'SUBSTRING(id FROM 3 FOR 2)'); + } + + /** + * MATH FUNCTIONS + */ + public function testRoundReturnsValidSql() { + $this->assertEqual($this->expr->round(2.3), 'ROUND(2.3, 0)'); + + $this->assertEqual($this->expr->round(2.3, 1), 'ROUND(2.3, 1)'); + } + public function testModReturnsValidSql() { + $this->assertEqual($this->expr->mod(2, 3), 'MOD(2, 3)'); + } + public function testSubReturnsValidSql() { + $this->assertEqual($this->expr->sub(array(2, 3)), '(2 - 3)'); + } + public function testMulReturnsValidSql() { + $this->assertEqual($this->expr->mul(array(2, 3)), '(2 * 3)'); + } + public function testAddReturnsValidSql() { + $this->assertEqual($this->expr->add(array(2, 3)), '(2 + 3)'); + } + public function testDivReturnsValidSql() { + $this->assertEqual($this->expr->div(array(2, 3)), '(2 / 3)'); + } + + /** + * ASSERT OPERATORS + */ + + public function testEqReturnsValidSql() { + $this->assertEqual($this->expr->eq(1, 1), '1 = 1'); + } + public function testNeqReturnsValidSql() { + $this->assertEqual($this->expr->neq(1, 2), '1 <> 2'); + } + public function testGtReturnsValidSql() { + $this->assertEqual($this->expr->gt(2, 1), '2 > 1'); + } + public function testGteReturnsValidSql() { + $this->assertEqual($this->expr->gte(1, 1), '1 >= 1'); + } + public function testLtReturnsValidSql() { + $this->assertEqual($this->expr->lt(1, 2), '1 < 2'); + } + public function testLteReturnsValidSql() { + $this->assertEqual($this->expr->lte(1, 1), '1 <= 1'); + } + + /** + * WHERE OPERATORS + */ + public function testNotReturnsValidSql() { + $this->assertEqual($this->expr->not('id'), 'NOT(id)'); + } + public function testInReturnsValidSql() { + $this->assertEqual($this->expr->in('id', array(1, 2)), 'id IN (1, 2)'); + } + public function testIsNullReturnsValidSql() { + $this->assertEqual($this->expr->isNull('type'), 'type IS NULL'); + } + public function testIsNotNullReturnsValidSql() { + $this->assertEqual($this->expr->isNotNull('type'), 'type IS NOT NULL'); + } + public function testBetweenReturnsValidSql() { + $this->assertEqual($this->expr->between('age', 12, 14), 'age BETWEEN 12 AND 14'); + } +} diff --git a/tests/ExpressionTestCase.php b/tests/ExpressionTestCase.php index d342f9594..40eefcc18 100644 --- a/tests/ExpressionTestCase.php +++ b/tests/ExpressionTestCase.php @@ -30,143 +30,37 @@ * @since 1.0 * @version $Revision$ */ -class Doctrine_Expression_TestCase extends Doctrine_UnitTestCase { +class Doctrine_Expression_TestCase extends Doctrine_UnitTestCase +{ + public function prepareTables() + { + $this->tables = array('ExpressionTest'); + + parent::prepareTables(); + } + public function prepareData() + { + + } + public function testSavingWithAnExpression() + { - /** - * AGGREGATE FUNCTIONS - */ - public function testAvgReturnsValidSql() { - $this->expr = new Doctrine_Expression_Mock(); + $e = new ExpressionTest(); - $this->assertEqual($this->expr->avg('id'), 'AVG(id)'); - } - public function testCountReturnsValidSql() { - $this->assertEqual($this->expr->count('id'), 'COUNT(id)'); - } - public function testMaxReturnsValidSql() { - $this->assertEqual($this->expr->max('id'), 'MAX(id)'); - } - public function testMinReturnsValidSql() { - $this->assertEqual($this->expr->min('id'), 'MIN(id)'); - } - public function testSumReturnsValidSql() { - $this->assertEqual($this->expr->sum('id'), 'SUM(id)'); - } + $e->name = new Doctrine_Expression("CONCAT('some', 'one')"); - public function testRegexpImplementedOnlyAtDriverLevel() { - try { - $this->expr->regexp('[abc]'); - $this->fail(); - } catch(Doctrine_Expression_Exception $e) { - $this->pass(); - } - } - public function testSoundexImplementedOnlyAtDriverLevel() { - try { - $this->expr->soundex('arnold'); - $this->fail(); - } catch(Doctrine_Expression_Exception $e) { - $this->pass(); - } - } - /** - * TIME FUNCTIONS - */ - public function testNowReturnsValidSql() { - $this->assertEqual($this->expr->now(), 'NOW()'); - } + $e->save(); - /** - * STRING FUNCTIONS - */ - public function testUpperReturnsValidSql() { - $this->assertEqual($this->expr->upper('id', 3), 'UPPER(id)'); - } - public function testLowerReturnsValidSql() { - $this->assertEqual($this->expr->lower('id'), 'LOWER(id)'); - } - public function testLengthReturnsValidSql() { - $this->assertEqual($this->expr->length('id'), 'LENGTH(id)'); - } - public function testLtrimReturnsValidSql() { - $this->assertEqual($this->expr->ltrim('id'), 'LTRIM(id)'); - } - public function testLocateReturnsValidSql() { - $this->assertEqual($this->expr->locate('id', 3), 'LOCATE(id, 3)'); - } - public function testConcatReturnsValidSql() { - $this->assertEqual($this->expr->concat('id', 'type'), 'CONCAT(id, type)'); - } - public function testSubstringReturnsValidSql() { - $this->assertEqual($this->expr->substring('id', 3), 'SUBSTRING(id FROM 3)'); + $e->refresh(); - $this->assertEqual($this->expr->substring('id', 3, 2), 'SUBSTRING(id FROM 3 FOR 2)'); - } - - /** - * MATH FUNCTIONS - */ - public function testRoundReturnsValidSql() { - $this->assertEqual($this->expr->round(2.3), 'ROUND(2.3, 0)'); - - $this->assertEqual($this->expr->round(2.3, 1), 'ROUND(2.3, 1)'); - } - public function testModReturnsValidSql() { - $this->assertEqual($this->expr->mod(2, 3), 'MOD(2, 3)'); - } - public function testSubReturnsValidSql() { - $this->assertEqual($this->expr->sub(array(2, 3)), '(2 - 3)'); - } - public function testMulReturnsValidSql() { - $this->assertEqual($this->expr->mul(array(2, 3)), '(2 * 3)'); - } - public function testAddReturnsValidSql() { - $this->assertEqual($this->expr->add(array(2, 3)), '(2 + 3)'); - } - public function testDivReturnsValidSql() { - $this->assertEqual($this->expr->div(array(2, 3)), '(2 / 3)'); - } - - /** - * ASSERT OPERATORS - */ - - public function testEqReturnsValidSql() { - $this->assertEqual($this->expr->eq(1, 1), '1 = 1'); - } - public function testNeqReturnsValidSql() { - $this->assertEqual($this->expr->neq(1, 2), '1 <> 2'); - } - public function testGtReturnsValidSql() { - $this->assertEqual($this->expr->gt(2, 1), '2 > 1'); - } - public function testGteReturnsValidSql() { - $this->assertEqual($this->expr->gte(1, 1), '1 >= 1'); - } - public function testLtReturnsValidSql() { - $this->assertEqual($this->expr->lt(1, 2), '1 < 2'); - } - public function testLteReturnsValidSql() { - $this->assertEqual($this->expr->lte(1, 1), '1 <= 1'); - } - - /** - * WHERE OPERATORS - */ - public function testNotReturnsValidSql() { - $this->assertEqual($this->expr->not('id'), 'NOT(id)'); - } - public function testInReturnsValidSql() { - $this->assertEqual($this->expr->in('id', array(1, 2)), 'id IN (1, 2)'); - } - public function testIsNullReturnsValidSql() { - $this->assertEqual($this->expr->isNull('type'), 'type IS NULL'); - } - public function testIsNotNullReturnsValidSql() { - $this->assertEqual($this->expr->isNotNull('type'), 'type IS NOT NULL'); - } - public function testBetweenReturnsValidSql() { - $this->assertEqual($this->expr->between('age', 12, 14), 'age BETWEEN 12 AND 14'); + $this->assertEqual($e->name, 'someone'); + } +} +class ExpressionTest extends Doctrine_Record +{ + public function setTableDefinition() + { + $this->hasColumn('name', 'string'); + $this->hasColumn('amount', 'integer'); } } -class Doctrine_Expression_Mock extends Doctrine_Expression { } diff --git a/tests/UnitTestCase.php b/tests/UnitTestCase.php index 537bb1031..2b698d3d4 100644 --- a/tests/UnitTestCase.php +++ b/tests/UnitTestCase.php @@ -94,7 +94,6 @@ class Doctrine_UnitTestCase extends UnitTestCase switch($e[1]) { case 'Export': case 'Import': - case 'Expression': case 'Transaction': case 'DataDict': case 'Sequence': diff --git a/tests/run.php b/tests/run.php index 7070340bd..92adf7e4c 100644 --- a/tests/run.php +++ b/tests/run.php @@ -140,6 +140,7 @@ $test->addTestCase(new Doctrine_Import_Sqlite_TestCase()); // Expression module (not yet fully tested) $test->addTestCase(new Doctrine_Expression_TestCase()); +$test->addTestCase(new Doctrine_Expression_Driver_TestCase()); $test->addTestCase(new Doctrine_Expression_Firebird_TestCase()); $test->addTestCase(new Doctrine_Expression_Informix_TestCase()); $test->addTestCase(new Doctrine_Expression_Mysql_TestCase());