Upgrade to KH 3.1.3.1

This commit is contained in:
Deon George
2011-05-13 16:00:25 +10:00
parent 8013aadc4c
commit 6d256839fc
675 changed files with 22771 additions and 24111 deletions

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') or die('No direct script access.');
class Config_Database extends Kohana_Config_Database {}

View File

@@ -15,7 +15,7 @@
* @copyright (c) 2009 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Config_Database extends Kohana_Config_Reader {
class Kohana_Config_Database extends Config_Reader {
protected $_database_instance = 'default';

View File

@@ -1,8 +1,14 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Database connection wrapper. All database object instances are referenced
* by a name. Queries are typically handled by [Database_Query], rather than
* using the database object directly.
* Database connection wrapper/helper.
*
* You may get a database instance using `Database::instance('name')` where
* name is the [config](database/config) group.
*
* This class provides connection instance management via Database Drivers, as
* well as quoting, escaping and other related functions. Querys are done using
* [Database_Query] and [Database_Query_Builder] objects, which can be easily
* created using the [DB] helper class.
*
* @package Kohana/Database
* @category Base
@@ -152,12 +158,18 @@ abstract class Kohana_Database {
/**
* Disconnect from the database. This is called automatically by [Database::__destruct].
* Clears the database instance from [Database::$instances].
*
* $db->disconnect();
*
* @return boolean
*/
abstract public function disconnect();
public function disconnect()
{
unset(Database::$instances[$this->_instance]);
return TRUE;
}
/**
* Set the connection character set. This is called automatically by [Database::connect].
@@ -181,58 +193,56 @@ abstract class Kohana_Database {
*
* @param integer Database::SELECT, Database::INSERT, etc
* @param string SQL query
* @param mixed result object class, TRUE for stdClass, FALSE for assoc array
* @param mixed result object class string, TRUE for stdClass, FALSE for assoc array
* @param array object construct parameters for result class
* @return object Database_Result for SELECT queries
* @return array list (insert id, row count) for INSERT queries
* @return integer number of affected rows for all other queries
*/
abstract public function query($type, $sql, $as_object);
abstract public function query($type, $sql, $as_object = FALSE, array $params = NULL);
/**
* Count the number of records in the last query, without LIMIT or OFFSET applied.
* Start a SQL transaction
*
* // Get the total number of records that match the last query
* $count = $db->count_last_query();
* // Start the transactions
* $db->begin();
*
* @return integer
* try {
* DB::insert('users')->values($user1)...
* DB::insert('users')->values($user2)...
* // Insert successful commit the changes
* $db->commit();
* }
* catch (Database_Exception $e)
* {
* // Insert failed. Rolling back changes...
* $db->rollback();
* }
*
* @param string transaction mode
* @return boolean
*/
public function count_last_query()
{
if ($sql = $this->last_query)
{
$sql = trim($sql);
if (stripos($sql, 'SELECT') !== 0)
{
return FALSE;
}
abstract public function begin($mode = NULL);
if (stripos($sql, 'LIMIT') !== FALSE)
{
// Remove LIMIT from the SQL
$sql = preg_replace('/\sLIMIT\s+[^a-z]+/i', ' ', $sql);
}
/**
* Commit the current transaction
*
* // Commit the database changes
* $db->commit();
*
* @return boolean
*/
abstract public function commit();
if (stripos($sql, 'OFFSET') !== FALSE)
{
// Remove OFFSET from the SQL
$sql = preg_replace('/\sOFFSET\s+\d+/i', '', $sql);
}
// Get the total rows from the last query executed
$result = $this->query
(
Database::SELECT,
'SELECT COUNT(*) AS '.$this->quote_identifier('total_rows').' '.
'FROM ('.$sql.') AS '.$this->quote_table('counted_results'),
TRUE
);
// Return the total number of rows from the query
return (int) $result->current()->total_rows;
}
return FALSE;
}
/**
* Abort the current transaction
*
* // Undo the changes
* $db->rollback();
*
* @return boolean
*/
abstract public function rollback();
/**
* Count the number of records in a table.
@@ -246,7 +256,7 @@ abstract class Kohana_Database {
public function count_records($table)
{
// Quote the table name
$table = $this->quote_identifier($table);
$table = $this->quote_table($table);
return $this->query(Database::SELECT, 'SELECT COUNT(*) AS total_row_count FROM '.$table, FALSE)
->get('total_row_count');
@@ -347,11 +357,15 @@ abstract class Kohana_Database {
* // Get all name-related columns
* $columns = $db->list_columns('users', '%name%');
*
* // Get the columns from a table that doesn't use the table prefix
* $columns = $db->list_columns('users', NULL, FALSE);
*
* @param string table to get columns from
* @param string column to search for
* @param boolean whether to add the table prefix automatically or not
* @return array
*/
abstract public function list_columns($table, $like = NULL);
abstract public function list_columns($table, $like = NULL, $add_prefix = TRUE);
/**
* Extracts the text between parentheses, if any.
@@ -439,7 +453,7 @@ abstract class Kohana_Database {
else
{
// Convert the object to a string
return $this->quote((string) $value);
return $this->quote( (string) $value);
}
}
elseif (is_array($value))
@@ -459,6 +473,90 @@ abstract class Kohana_Database {
return $this->escape($value);
}
/**
* Quote a database column name and add the table prefix if needed.
*
* $column = $db->quote_column($column);
*
* You can also use SQL methods within identifiers.
*
* // The value of "column" will be quoted
* $column = $db->quote_column('COUNT("column")');
*
* @param mixed column name or array(column, alias)
* @return string
* @uses Database::quote_identifier
* @uses Database::table_prefix
*/
public function quote_column($column)
{
if (is_array($column))
{
list($column, $alias) = $column;
}
if ($column instanceof Database_Query)
{
// Create a sub-query
$column = '('.$column->compile($this).')';
}
elseif ($column instanceof Database_Expression)
{
// Use a raw expression
$column = $column->value();
}
else
{
// Convert to a string
$column = (string) $column;
if ($column === '*')
{
return $column;
}
elseif (strpos($column, '"') !== FALSE)
{
// Quote the column in FUNC("column") identifiers
$column = preg_replace('/"(.+?)"/e', '$this->quote_column("$1")', $column);
}
elseif (strpos($column, '.') !== FALSE)
{
$parts = explode('.', $column);
if ($prefix = $this->table_prefix())
{
// Get the offset of the table name, 2nd-to-last part
$offset = count($parts) - 2;
// Add the table prefix to the table name
$parts[$offset] = $prefix.$parts[$offset];
}
foreach ($parts as & $part)
{
if ($part !== '*')
{
// Quote each of the parts
$part = $this->_identifier.$part.$this->_identifier;
}
}
$column = implode('.', $parts);
}
else
{
$column = $this->_identifier.$column.$this->_identifier;
}
}
if (isset($alias))
{
$column .= ' AS '.$this->_identifier.$alias.$this->_identifier;
}
return $column;
}
/**
* Quote a database table name and adds the table prefix if needed.
*
@@ -469,40 +567,67 @@ abstract class Kohana_Database {
* @uses Database::quote_identifier
* @uses Database::table_prefix
*/
public function quote_table($value)
public function quote_table($table)
{
// Assign the table by reference from the value
if (is_array($value))
if (is_array($table))
{
$table =& $value[0];
list($table, $alias) = $table;
}
// Attach table prefix to alias
$value[1] = $this->table_prefix().$value[1];
if ($table instanceof Database_Query)
{
// Create a sub-query
$table = '('.$table->compile($this).')';
}
elseif ($table instanceof Database_Expression)
{
// Use a raw expression
$table = $table->value();
}
else
{
$table =& $value;
// Convert to a string
$table = (string) $table;
if (strpos($table, '.') !== FALSE)
{
$parts = explode('.', $table);
if ($prefix = $this->table_prefix())
{
// Get the offset of the table name, last part
$offset = count($parts) - 1;
// Add the table prefix to the table name
$parts[$offset] = $prefix.$parts[$offset];
}
foreach ($parts as & $part)
{
// Quote each of the parts
$part = $this->_identifier.$part.$this->_identifier;
}
$table = implode('.', $parts);
}
else
{
// Add the table prefix
$table = $this->_identifier.$this->table_prefix().$table.$this->_identifier;
}
}
if (is_string($table) AND strpos($table, '.') === FALSE)
if (isset($alias))
{
// Add the table prefix for tables
$table = $this->table_prefix().$table;
// Attach table prefix to alias
$table .= ' AS '.$this->_identifier.$this->table_prefix().$alias.$this->_identifier;
}
return $this->quote_identifier($value);
return $table;
}
/**
* Quote a database identifier, such as a column name. Adds the
* table prefix to the identifier if a table name is present.
*
* $column = $db->quote_identifier($column);
*
* You can also use SQL methods within identifiers.
*
* // The value of "column" will be quoted
* $column = $db->quote_identifier('COUNT("column")');
* Quote a database identifier
*
* Objects passed to this function will be converted to strings.
* [Database_Expression] objects will use the value of the expression.
@@ -511,67 +636,53 @@ abstract class Kohana_Database {
*
* @param mixed any identifier
* @return string
* @uses Database::table_prefix
*/
public function quote_identifier($value)
{
if ($value === '*')
if (is_array($value))
{
return $value;
}
elseif (is_object($value))
{
if ($value instanceof Database_Query)
{
// Create a sub-query
return '('.$value->compile($this).')';
}
elseif ($value instanceof Database_Expression)
{
// Use a raw expression
return $value->value();
}
else
{
// Convert the object to a string
return $this->quote_identifier((string) $value);
}
}
elseif (is_array($value))
{
// Separate the column and alias
list ($value, $alias) = $value;
return $this->quote_identifier($value).' AS '.$this->quote_identifier($alias);
list($value, $alias) = $value;
}
if (strpos($value, '"') !== FALSE)
if ($value instanceof Database_Query)
{
// Quote the column in FUNC("ident") identifiers
return preg_replace('/"(.+?)"/e', '$this->quote_identifier("$1")', $value);
// Create a sub-query
$value = '('.$value->compile($this).')';
}
elseif (strpos($value, '.') !== FALSE)
elseif ($value instanceof Database_Expression)
{
// Split the identifier into the individual parts
$parts = explode('.', $value);
if ($prefix = $this->table_prefix())
{
// Get the offset of the table name, 2nd-to-last part
// This works for databases that can have 3 identifiers (Postgre)
$offset = count($parts) - 2;
// Add the table prefix to the table name
$parts[$offset] = $prefix.$parts[$offset];
}
// Quote each of the parts
return implode('.', array_map(array($this, __FUNCTION__), $parts));
// Use a raw expression
$value = $value->value();
}
else
{
return $this->_identifier.$value.$this->_identifier;
// Convert to a string
$value = (string) $value;
if (strpos($value, '.') !== FALSE)
{
$parts = explode('.', $value);
foreach ($parts as & $part)
{
// Quote each of the parts
$part = $this->_identifier.$part.$this->_identifier;
}
$value = implode('.', $parts);
}
else
{
$value = $this->_identifier.$value.$this->_identifier;
}
}
if (isset($alias))
{
$value .= ' AS '.$this->_identifier.$alias.$this->_identifier;
}
return $value;
}
/**

View File

@@ -8,6 +8,8 @@
* // SELECT CONCAT(first_name, last_name) AS full_name
* $query = DB::select(array(DB::expr('CONCAT(first_name, last_name)'), 'full_name')));
*
* More examples are available on the [Query Builder](database/query/builder#database-expressions) page
*
* @package Kohana/Database
* @category Base
* @author Kohana Team

View File

@@ -64,9 +64,8 @@ class Kohana_Database_MySQL extends Database {
// No connection exists
$this->_connection = NULL;
throw new Database_Exception(':error', array(
':error' => mysql_error(),
),
throw new Database_Exception(':error',
array(':error' => mysql_error()),
mysql_errno());
}
@@ -114,6 +113,9 @@ class Kohana_Database_MySQL extends Database {
{
// Clear the connection
$this->_connection = NULL;
// Clear the instance
parent::disconnect();
}
}
}
@@ -150,7 +152,7 @@ class Kohana_Database_MySQL extends Database {
}
}
public function query($type, $sql, $as_object)
public function query($type, $sql, $as_object = FALSE, array $params = NULL)
{
// Make sure the database is connected
$this->_connection or $this->connect();
@@ -192,7 +194,7 @@ class Kohana_Database_MySQL extends Database {
if ($type === Database::SELECT)
{
// Return an iterator of results
return new Database_MySQL_Result($result, $sql, $as_object);
return new Database_MySQL_Result($result, $sql, $as_object, $params);
}
elseif ($type === Database::INSERT)
{
@@ -256,6 +258,57 @@ class Kohana_Database_MySQL extends Database {
return parent::datatype($type);
}
/**
* Start a SQL transaction
*
* @link http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html
*
* @param string Isolation level
* @return boolean
*/
public function begin($mode = NULL)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if ($mode AND ! mysql_query("SET TRANSACTION ISOLATION LEVEL $mode", $this->_connection))
{
throw new Database_Exception(':error',
array(':error' => mysql_error($this->_connection)),
mysql_errno($this->_connection));
}
return (bool) mysql_query('START TRANSACTION', $this->_connection);
}
/**
* Commit a SQL transaction
*
* @param string Isolation level
* @return boolean
*/
public function commit()
{
// Make sure the database is connected
$this->_connection or $this->connect();
return (bool) mysql_query('COMMIT', $this->_connection);
}
/**
* Rollback a SQL transaction
*
* @param string Isolation level
* @return boolean
*/
public function rollback()
{
// Make sure the database is connected
$this->_connection or $this->connect();
return (bool) mysql_query('ROLLBACK', $this->_connection);
}
public function list_tables($like = NULL)
{
if (is_string($like))
@@ -278,10 +331,10 @@ class Kohana_Database_MySQL extends Database {
return $tables;
}
public function list_columns($table, $like = NULL)
public function list_columns($table, $like = NULL, $add_prefix = TRUE)
{
// Quote the table name
$table = $this->quote_table($table);
$table = ($add_prefix === TRUE) ? $this->quote_table($table) : $table;
if (is_string($like))
{
@@ -330,7 +383,6 @@ class Kohana_Database_MySQL extends Database {
case 'varbinary':
$column['character_maximum_length'] = $length;
break;
case 'char':
case 'varchar':
$column['character_maximum_length'] = $length;
@@ -340,7 +392,6 @@ class Kohana_Database_MySQL extends Database {
case 'longtext':
$column['collation_name'] = $row['Collation'];
break;
case 'enum':
case 'set':
$column['collation_name'] = $row['Collation'];
@@ -367,11 +418,11 @@ class Kohana_Database_MySQL extends Database {
// Make sure the database is connected
$this->_connection or $this->connect();
if (($value = mysql_real_escape_string((string) $value, $this->_connection)) === FALSE)
if (($value = mysql_real_escape_string( (string) $value, $this->_connection)) === FALSE)
{
throw new Database_Exception(':error',
array(':error' => mysql_errno($this->_connection)),
mysql_error($this->_connection));
array(':error' => mysql_error($this->_connection)),
mysql_errno($this->_connection));
}
// SQL standard is to use single-quotes for all values

View File

@@ -1,6 +1,6 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* MySQL database result.
* MySQL database result. See [Results](/database/results) for usage and examples.
*
* @package Kohana/Database
* @category Query/Result
@@ -12,9 +12,9 @@ class Kohana_Database_MySQL_Result extends Database_Result {
protected $_internal_row = 0;
public function __construct($result, $sql, $as_object)
public function __construct($result, $sql, $as_object = FALSE, array $params = NULL)
{
parent::__construct($result, $sql, $as_object);
parent::__construct($result, $sql, $as_object, $params);
// Find the number of rows in the result
$this->_total_rows = mysql_num_rows($result);
@@ -46,7 +46,7 @@ class Kohana_Database_MySQL_Result extends Database_Result {
public function current()
{
if ($this->_current_row !== $this->_internal_row AND ! $this->seek($this->_current_row))
return FALSE;
return NULL;
// Increment internal row for optimization assuming rows are fetched in order
$this->_internal_row++;
@@ -59,7 +59,7 @@ class Kohana_Database_MySQL_Result extends Database_Result {
elseif (is_string($this->_as_object))
{
// Return an object of given class name
return mysql_fetch_object($this->_result, $this->_as_object);
return mysql_fetch_object($this->_result, $this->_as_object, $this->_object_params);
}
else
{

View File

@@ -56,11 +56,9 @@ class Kohana_Database_PDO extends Database {
}
catch (PDOException $e)
{
throw new Database_Exception(':error', array(
':error' => $e->getMessage(),
),
$e->getCode(),
$e);
throw new Database_Exception(':error',
array(':error' => $e->getMessage()),
$e->getCode());
}
if ( ! empty($this->_config['charset']))
@@ -75,7 +73,7 @@ class Kohana_Database_PDO extends Database {
// Destroy the PDO object
$this->_connection = NULL;
return TRUE;
return parent::disconnect();
}
public function set_charset($charset)
@@ -87,7 +85,7 @@ class Kohana_Database_PDO extends Database {
$this->_connection->exec('SET NAMES '.$this->quote($charset));
}
public function query($type, $sql, $as_object)
public function query($type, $sql, $as_object = FALSE, array $params = NULL)
{
// Make sure the database is connected
$this->_connection or $this->connect();
@@ -111,12 +109,12 @@ class Kohana_Database_PDO extends Database {
}
// Convert the exception in a database exception
throw new Database_Exception(':error [ :query ]', array(
throw new Database_Exception(':error [ :query ]',
array(
':error' => $e->getMessage(),
':query' => $sql
),
$e->getCode(),
$e);
$e->getCode());
}
if (isset($benchmark))
@@ -136,7 +134,7 @@ class Kohana_Database_PDO extends Database {
}
elseif (is_string($as_object))
{
$result->setFetchMode(PDO::FETCH_CLASS, $as_object);
$result->setFetchMode(PDO::FETCH_CLASS, $as_object, $params);
}
else
{
@@ -146,7 +144,7 @@ class Kohana_Database_PDO extends Database {
$result = $result->fetchAll();
// Return an iterator of results
return new Database_Result_Cached($result, $sql, $as_object);
return new Database_Result_Cached($result, $sql, $as_object, $params);
}
elseif ($type === Database::INSERT)
{
@@ -163,13 +161,37 @@ class Kohana_Database_PDO extends Database {
}
}
public function begin($mode = NULL)
{
// Make sure the database is connected
$this->_connection or $this->connect();
return $this->_connection->beginTransaction();
}
public function commit()
{
// Make sure the database is connected
$this->_connection or $this->connect();
return $this->_connection->commit();
}
public function rollback()
{
// Make sure the database is connected
$this->_connection or $this->connect();
return $this->_connection->rollBack();
}
public function list_tables($like = NULL)
{
throw new Kohana_Exception('Database method :method is not supported by :class',
array(':method' => __FUNCTION__, ':class' => __CLASS__));
}
public function list_columns($table, $like = NULL)
public function list_columns($table, $like = NULL, $add_prefix = TRUE)
{
throw new Kohana_Exception('Database method :method is not supported by :class',
array(':method' => __FUNCTION__, ':class' => __CLASS__));

View File

@@ -1,6 +1,6 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Database query wrapper.
* Database query wrapper. See [Prepared Statements](database/query/prepared) for usage and examples.
*
* @package Kohana/Database
* @category Query
@@ -14,7 +14,7 @@ class Kohana_Database_Query {
protected $_type;
// Cache lifetime
protected $_lifetime;
protected $_lifetime = NULL;
// SQL statement
protected $_sql;
@@ -25,6 +25,9 @@ class Kohana_Database_Query {
// Return results as associative arrays or objects
protected $_as_object = FALSE;
// Parameters for __construct when using object results
protected $_object_params = array();
/**
* Creates a new SQL query of the specified type.
*
@@ -52,7 +55,7 @@ class Kohana_Database_Query {
}
catch (Exception $e)
{
return Kohana::exception_text($e);
return Kohana_Exception::text($e);
}
}
@@ -69,11 +72,18 @@ class Kohana_Database_Query {
/**
* Enables the query to be cached for a specified amount of time.
*
* @param integer number of seconds to cache or null for default
* @param integer number of seconds to cache
* @return $this
* @uses Kohana::$cache_life
*/
public function cached($lifetime = NULL)
{
if ($lifetime === NULL)
{
// Use the global setting
$lifetime = Kohana::$cache_life;
}
$this->_lifetime = $lifetime;
return $this;
@@ -88,6 +98,8 @@ class Kohana_Database_Query {
{
$this->_as_object = FALSE;
$this->_object_params = array();
return $this;
}
@@ -97,10 +109,16 @@ class Kohana_Database_Query {
* @param string classname or TRUE for stdClass
* @return $this
*/
public function as_object($class = TRUE)
public function as_object($class = TRUE, array $params = NULL)
{
$this->_as_object = $class;
if ($params)
{
// Add object parameters
$this->_object_params = $params;
}
return $this;
}
@@ -191,7 +209,7 @@ class Kohana_Database_Query {
// Compile the SQL query
$sql = $this->compile($db);
if ( ! empty($this->_lifetime) AND $this->_type === Database::SELECT)
if ($this->_lifetime !== NULL AND $this->_type === Database::SELECT)
{
// Set the cache key based on the database instance name and SQL
$cache_key = 'Database::query("'.$db.'", "'.$sql.'")';
@@ -199,12 +217,12 @@ class Kohana_Database_Query {
if ($result = Kohana::cache($cache_key, NULL, $this->_lifetime))
{
// Return a cached result
return new Database_Result_Cached($result, $sql, $this->_as_object);
return new Database_Result_Cached($result, $sql, $this->_as_object, $this->_object_params);
}
}
// Execute the query
$result = $db->query($this->_type, $sql, $this->_as_object);
$result = $db->query($this->_type, $sql, $this->_as_object, $this->_object_params);
if (isset($cache_key))
{

View File

@@ -1,6 +1,6 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Database query builder.
* Database query builder. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query
@@ -95,35 +95,35 @@ abstract class Kohana_Database_Query_Builder extends Database_Query {
// BETWEEN always has exactly two arguments
list($min, $max) = $value;
if (is_string($min) AND array_key_exists($min, $this->_parameters))
if ((is_string($min) AND array_key_exists($min, $this->_parameters)) === FALSE)
{
// Set the parameter as the minimum
$min = $this->_parameters[$min];
// Quote the value, it is not a parameter
$min = $db->quote($min);
}
if (is_string($max) AND array_key_exists($max, $this->_parameters))
if ((is_string($max) AND array_key_exists($max, $this->_parameters)) === FALSE)
{
// Set the parameter as the maximum
$max = $this->_parameters[$max];
// Quote the value, it is not a parameter
$max = $db->quote($max);
}
// Quote the min and max value
$value = $db->quote($min).' AND '.$db->quote($max);
$value = $min.' AND '.$max;
}
else
elseif ((is_string($value) AND array_key_exists($value, $this->_parameters)) === FALSE)
{
if (is_string($value) AND array_key_exists($value, $this->_parameters))
{
// Set the parameter as the value
$value = $this->_parameters[$value];
}
// Quote the entire value normally
// Quote the value, it is not a parameter
$value = $db->quote($value);
}
if ($column)
{
// Apply proper quoting to the column
$column = $db->quote_column($column);
}
// Append the statement to the query
$sql .= $db->quote_identifier($column).' '.$op.' '.$value;
$sql .= trim($column.' '.$op.' '.$value);
}
$last_condition = $condition;
@@ -149,15 +149,15 @@ abstract class Kohana_Database_Query_Builder extends Database_Query {
list ($column, $value) = $group;
// Quote the column name
$column = $db->quote_identifier($column);
$column = $db->quote_column($column);
if (is_string($value) AND array_key_exists($value, $this->_parameters))
if ((is_string($value) AND array_key_exists($value, $this->_parameters)) === FALSE)
{
// Use the parameter value
$value = $this->_parameters[$value];
// Quote the value, it is not a parameter
$value = $db->quote($value);
}
$set[$column] = $column.' = '.$db->quote($value);
$set[$column] = $column.' = '.$value;
}
return implode(', ', $set);
@@ -177,13 +177,19 @@ abstract class Kohana_Database_Query_Builder extends Database_Query {
{
list ($column, $direction) = $group;
if ( ! empty($direction))
if ($direction)
{
// Make the direction uppercase
$direction = ' '.strtoupper($direction);
$direction = strtoupper($direction);
}
$sort[] = $db->quote_identifier($column).$direction;
if ($column)
{
// Quote the column, if it has a value
$column = $db->quote_column($column);
}
$sort[] = trim($column.' '.$direction);
}
return 'ORDER BY '.implode(', ', $sort);

View File

@@ -1,6 +1,6 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Database query builder for DELETE statements.
* Database query builder for DELETE statements. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query
@@ -73,7 +73,9 @@ class Kohana_Database_Query_Builder_Delete extends Database_Query_Builder_Where
$query .= ' LIMIT '.$this->_limit;
}
return $query;
$this->_sql = $query;
return parent::compile($db);
}
public function reset()
@@ -83,6 +85,8 @@ class Kohana_Database_Query_Builder_Delete extends Database_Query_Builder_Where
$this->_parameters = array();
$this->_sql = NULL;
return $this;
}

View File

@@ -1,6 +1,6 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Database query builder for INSERT statements.
* Database query builder for INSERT statements. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query
@@ -122,7 +122,7 @@ class Kohana_Database_Query_Builder_Insert extends Database_Query_Builder {
$query = 'INSERT INTO '.$db->quote_table($this->_table);
// Add the column names
$query .= ' ('.implode(', ', array_map(array($db, 'quote_identifier'), $this->_columns)).') ';
$query .= ' ('.implode(', ', array_map(array($db, 'quote_column'), $this->_columns)).') ';
if (is_array($this->_values))
{
@@ -132,16 +132,16 @@ class Kohana_Database_Query_Builder_Insert extends Database_Query_Builder {
$groups = array();
foreach ($this->_values as $group)
{
foreach ($group as $i => $value)
foreach ($group as $offset => $value)
{
if (is_string($value) AND isset($this->_parameters[$value]))
if ((is_string($value) AND array_key_exists($value, $this->_parameters)) === FALSE)
{
// Use the parameter value
$group[$i] = $this->_parameters[$value];
// Quote the value, it is not a parameter
$group[$offset] = $db->quote($value);
}
}
$groups[] = '('.implode(', ', array_map($quote, $group)).')';
$groups[] = '('.implode(', ', $group).')';
}
// Add the values
@@ -153,7 +153,9 @@ class Kohana_Database_Query_Builder_Insert extends Database_Query_Builder {
$query .= (string) $this->_values;
}
return $query;
$this->_sql = $query;
return parent::compile($db);;
}
public function reset()
@@ -165,6 +167,8 @@ class Kohana_Database_Query_Builder_Insert extends Database_Query_Builder {
$this->_parameters = array();
$this->_sql = NULL;
return $this;
}

View File

@@ -1,6 +1,6 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Database query builder for JOIN statements.
* Database query builder for JOIN statements. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query
@@ -19,6 +19,9 @@ class Kohana_Database_Query_Builder_Join extends Database_Query_Builder {
// ON ...
protected $_on = array();
// USING ...
protected $_using = array();
/**
* Creates a new JOIN statement for a table. Optionally, the type of JOIN
* can be specified as the second parameter.
@@ -49,11 +52,37 @@ class Kohana_Database_Query_Builder_Join extends Database_Query_Builder {
*/
public function on($c1, $op, $c2)
{
if ( ! empty($this->_using))
{
throw new Kohana_Exception('JOIN ... ON ... cannot be combined with JOIN ... USING ...');
}
$this->_on[] = array($c1, $op, $c2);
return $this;
}
/**
* Adds a new condition for joining.
*
* @param string column name
* @param ...
* @return $this
*/
public function using($columns)
{
if ( ! empty($this->_on))
{
throw new Kohana_Exception('JOIN ... ON ... cannot be combined with JOIN ... USING ...');
}
$columns = func_get_args();
$this->_using = array_merge($this->_using, $columns);
return $this;
}
/**
* Compile the SQL partial for a JOIN statement and return it.
*
@@ -72,27 +101,35 @@ class Kohana_Database_Query_Builder_Join extends Database_Query_Builder {
}
// Quote the table name that is being joined
$sql .= ' '.$db->quote_table($this->_table).' ON ';
$sql .= ' '.$db->quote_table($this->_table);
$conditions = array();
foreach ($this->_on as $condition)
if ( ! empty($this->_using))
{
// Split the condition
list($c1, $op, $c2) = $condition;
if ($op)
// Quote and concat the columns
$sql .= ' USING ('.implode(', ', array_map(array($db, 'quote_column'), $this->_using)).')';
}
else
{
$conditions = array();
foreach ($this->_on as $condition)
{
// Make the operator uppercase and spaced
$op = ' '.strtoupper($op);
// Split the condition
list($c1, $op, $c2) = $condition;
if ($op)
{
// Make the operator uppercase and spaced
$op = ' '.strtoupper($op);
}
// Quote each of the columns used for the condition
$conditions[] = $db->quote_column($c1).$op.' '.$db->quote_column($c2);
}
// Quote each of the identifiers used for the condition
$conditions[] = $db->quote_identifier($c1).$op.' '.$db->quote_identifier($c2);
// Concat the conditions "... AND ..."
$sql .= ' ON ('.implode(' AND ', $conditions).')';
}
// Concat the conditions "... AND ..."
$sql .= '('.implode(' AND ', $conditions).')';
return $sql;
}

View File

@@ -1,6 +1,6 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Database query builder for SELECT statements.
* Database query builder for SELECT statements. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query
@@ -31,6 +31,9 @@ class Kohana_Database_Query_Builder_Select extends Database_Query_Builder_Where
// OFFSET ...
protected $_offset = NULL;
// UNION ...
protected $_union = array();
// The last JOIN statement created
protected $_last_join;
@@ -76,10 +79,6 @@ class Kohana_Database_Query_Builder_Select extends Database_Query_Builder_Where
{
$columns = func_get_args();
// Ignore our default select of .* if we already have some selected columns.
if (count($columns) == 1 AND is_string($columns[0]) AND preg_match('/\.\*$/',$columns[0]) AND $this->_select)
return $this;
$this->_select = array_merge($this->_select, $columns);
return $this;
@@ -143,6 +142,22 @@ class Kohana_Database_Query_Builder_Select extends Database_Query_Builder_Where
return $this;
}
/**
* Adds "USING ..." conditions for the last created JOIN statement.
*
* @param string column name
* @param ...
* @return $this
*/
public function using($columns)
{
$columns = func_get_args();
call_user_func_array(array($this->_last_join, 'using'), $columns);
return $this;
}
/**
* Creates a "GROUP BY ..." filter.
*
@@ -270,6 +285,26 @@ class Kohana_Database_Query_Builder_Select extends Database_Query_Builder_Where
return $this;
}
/**
* Adds an other UNION clause.
*
* @param mixed $select if string, it must be the name of a table. Else
* must be an instance of Database_Query_Builder_Select
* @param boolean $all decides if it's an UNION or UNION ALL clause
* @return $this
*/
public function union($select, $all = TRUE)
{
if (is_string($select))
{
$select = DB::select()->from($select);
}
if ( ! $select instanceof Database_Query_Builder_Select)
throw new Kohana_Exception('first parameter must be a string or an instance of Database_Query_Builder_Select');
$this->_union []= array('select' => $select, 'all' => $all);
return $this;
}
/**
* Start returning results after "OFFSET ..."
*
@@ -291,8 +326,8 @@ class Kohana_Database_Query_Builder_Select extends Database_Query_Builder_Where
*/
public function compile(Database $db)
{
// Callback to quote identifiers
$quote_ident = array($db, 'quote_identifier');
// Callback to quote columns
$quote_column = array($db, 'quote_column');
// Callback to quote tables
$quote_table = array($db, 'quote_table');
@@ -314,7 +349,7 @@ class Kohana_Database_Query_Builder_Select extends Database_Query_Builder_Where
else
{
// Select all columns
$query .= implode(', ', array_unique(array_map($quote_ident, $this->_select)));
$query .= implode(', ', array_unique(array_map($quote_column, $this->_select)));
}
if ( ! empty($this->_from))
@@ -338,7 +373,7 @@ class Kohana_Database_Query_Builder_Select extends Database_Query_Builder_Where
if ( ! empty($this->_group_by))
{
// Add sorting
$query .= ' GROUP BY '.implode(', ', array_map($quote_ident, $this->_group_by));
$query .= ' GROUP BY '.implode(', ', array_map($quote_column, $this->_group_by));
}
if ( ! empty($this->_having))
@@ -364,8 +399,22 @@ class Kohana_Database_Query_Builder_Select extends Database_Query_Builder_Where
// Add offsets
$query .= ' OFFSET '.$this->_offset;
}
if ( ! empty($this->_union))
{
foreach ($this->_union as $u) {
$query .= ' UNION ';
if ($u['all'] === TRUE)
{
$query .= 'ALL ';
}
$query .= $u['select']->compile($db);
}
}
return $query;
$this->_sql = $query;
return parent::compile($db);
}
public function reset()
@@ -376,7 +425,8 @@ class Kohana_Database_Query_Builder_Select extends Database_Query_Builder_Where
$this->_where =
$this->_group_by =
$this->_having =
$this->_order_by = array();
$this->_order_by =
$this->_union = array();
$this->_distinct = FALSE;
@@ -386,7 +436,10 @@ class Kohana_Database_Query_Builder_Select extends Database_Query_Builder_Where
$this->_parameters = array();
$this->_sql = NULL;
return $this;
}
} // End Database_Query_Select

View File

@@ -1,6 +1,6 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Database query builder for UPDATE statements.
* Database query builder for UPDATE statements. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query
@@ -97,13 +97,21 @@ class Kohana_Database_Query_Builder_Update extends Database_Query_Builder_Where
$query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
}
if ( ! empty($this->_order_by))
{
// Add sorting
$query .= ' '.$this->_compile_order_by($db, $this->_order_by);
}
if ($this->_limit !== NULL)
{
// Add limiting
$query .= ' LIMIT '.$this->_limit;
}
return $query;
$this->_sql = $query;
return parent::compile($db);
}
public function reset()
@@ -117,6 +125,8 @@ class Kohana_Database_Query_Builder_Update extends Database_Query_Builder_Where
$this->_parameters = array();
$this->_sql = NULL;
return $this;
}

View File

@@ -1,6 +1,6 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Database query builder for WHERE statements.
* Database query builder for WHERE statements. See [Query Builder](/database/query/builder) for usage and examples.
*
* @package Kohana/Database
* @category Query

View File

@@ -1,6 +1,6 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Database result wrapper.
* Database result wrapper. See [Results](/database/results) for usage and examples.
*
* @package Kohana/Database
* @category Query/Result
@@ -23,6 +23,9 @@ abstract class Kohana_Database_Result implements Countable, Iterator, SeekableIt
// Return rows as an object or associative array
protected $_as_object;
// Parameters for __construct when using object results
protected $_object_params = NULL;
/**
* Sets the total number of rows and stores the result locally.
*
@@ -30,7 +33,7 @@ abstract class Kohana_Database_Result implements Countable, Iterator, SeekableIt
* @param string SQL query
* @return void
*/
public function __construct($result, $sql, $as_object)
public function __construct($result, $sql, $as_object = FALSE, array $params = NULL)
{
// Store the result locally
$this->_result = $result;
@@ -46,6 +49,12 @@ abstract class Kohana_Database_Result implements Countable, Iterator, SeekableIt
// Results as objects or associative arrays
$this->_as_object = $as_object;
if ($params)
{
// Object constructor params
$this->_object_params = $params;
}
}
/**

View File

@@ -1,6 +1,6 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Cached database result.
* Object used for caching the results of select queries. See [Results](/database/results#select-cached) for usage and examples.
*
* @package Kohana/Database
* @category Query/Result
@@ -45,7 +45,7 @@ class Kohana_Database_Result_Cached extends Database_Result {
public function current()
{
// Return an array of the row
return $this->_result[$this->_current_row];
return $this->valid() ? $this->_result[$this->_current_row] : NULL;
}
} // End Database_Result_Cached

View File

@@ -1,6 +1,17 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Database object creation helper methods.
* Provides a shortcut to get Database related objects for [making queries](../database/query).
*
* Shortcut | Returned Object
* -------------|---------------
* [`DB::query()`](#query) | [Database_Query]
* [`DB::insert()`](#insert) | [Database_Query_Builder_Insert]
* [`DB::select()`](#select),<br />[`DB::select_array()`](#select_array) | [Database_Query_Builder_Select]
* [`DB::update()`](#update) | [Database_Query_Builder_Update]
* [`DB::delete()`](#delete) | [Database_Query_Builder_Delete]
* [`DB::expr()`](#expr) | [Database_Expression]
*
* You pass the same parameters to these functions as you pass to the objects they return.
*
* @package Kohana/Database
* @category Base
@@ -114,6 +125,8 @@ class Kohana_DB {
* is the only way to use SQL functions within query builders.
*
* $expression = DB::expr('COUNT(users.id)');
* $query = DB::update('users')->set(array('login_count' => DB::expr('login_count + 1')))->where('id', '=', $id);
* $users = ORM::factory('user')->where(DB::expr("BINARY `hash`"), '=', $hash)->find();
*
* @param string expression
* @return Database_Expression

View File

@@ -0,0 +1,58 @@
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Database Model base class.
*
* @package Kohana/Database
* @category Models
* @author Kohana Team
* @copyright (c) 2008-2010 Kohana Team
* @license http://kohanaframework.org/license
*/
abstract class Kohana_Model_Database extends Model {
/**
* Create a new model instance. A [Database] instance or configuration
* group name can be passed to the model. If no database is defined, the
* "default" database group will be used.
*
* $model = Model::factory($name);
*
* @param string model name
* @param mixed Database instance object or string
* @return Model
*/
public static function factory($name, $db = NULL)
{
// Add the model prefix
$class = 'Model_'.$name;
return new $class($db);
}
// Database instance
protected $_db = 'default';
/**
* Loads the database.
*
* $model = new Foo_Model($db);
*
* @param mixed Database instance object or string
* @return void
*/
public function __construct($db = NULL)
{
if ($db !== NULL)
{
// Set the database instance name
$this->_db = $db;
}
if (is_string($this->_db))
{
// Load the database
$this->_db = Database::instance($this->_db);
}
}
} // End Model

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') or die('No direct script access.');
abstract class Model_Database extends Kohana_Model_Database {}