summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/database/classes/database/expression.php46
-rw-r--r--modules/database/classes/database/query.php818
-rw-r--r--modules/database/classes/database/result.php200
-rw-r--r--modules/database/classes/db.php252
-rw-r--r--modules/database/classes/driver/mysql/db.php214
-rw-r--r--modules/database/classes/driver/mysql/query.php5
-rw-r--r--modules/database/classes/driver/mysql/result.php90
-rw-r--r--modules/database/classes/driver/pdo/db.php228
-rw-r--r--modules/database/classes/driver/pdo/query.php443
-rw-r--r--modules/database/classes/driver/pdo/result.php90
-rw-r--r--modules/orm/classes/orm.php1575
-rw-r--r--modules/orm/classes/orm/result.php412
12 files changed, 2192 insertions, 2181 deletions
diff --git a/modules/database/classes/database/expression.php b/modules/database/classes/database/expression.php
index a041967..1d4de19 100644
--- a/modules/database/classes/database/expression.php
+++ b/modules/database/classes/database/expression.php
@@ -7,27 +7,29 @@
*/
class Expression_Database
{
- /**
- * Part of query that should not be escaped
- * @var mixed
- * @access public
- */
- public $value;
- /**
- * Marks a part of query as a database specific expression,
- * e.g. calls to SQL functions like MAX(), SUBSTR() etc.
- * Example
- * <code>
- * $q->fields(DB::expr('COUNT(*)'));
- * </code>
- *
- * @param mixed $value Part of query that should not be escaped
- * @return Expression_Database
- * @access public
- */
- public function __construct($value)
- {
- $this->value = $value;
- }
+ /**
+ * Part of query that should not be escaped
+ * @var mixed
+ * @access public
+ */
+ public $value;
+
+ /**
+ * Marks a part of query as a database specific expression,
+ * e.g. calls to SQL functions like MAX(), SUBSTR() etc.
+ * Example
+ * <code>
+ * $q->fields(DB::expr('COUNT(*)'));
+ * </code>
+ *
+ * @param mixed $value Part of query that should not be escaped
+ * @return Expression_Database
+ * @access public
+ */
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+
}
diff --git a/modules/database/classes/database/query.php b/modules/database/classes/database/query.php
index 23b9876..e83a4bd 100644
--- a/modules/database/classes/database/query.php
+++ b/modules/database/classes/database/query.php
@@ -5,7 +5,7 @@
* Database drivers extend this class so that they can generate database specific queries.
* The idea is to provide a database agnostic interface to query writing.
*
- * @method mixed table(string $table = null) Set table to query.
+ * @method mixed table(string $table = null) Set table to query.
* Without arguments returns current table, returns self otherwise.
*
* @method mixed data(array $data = null) Set data for insert or update queries.
@@ -29,103 +29,104 @@
*/
abstract class Query_Database
{
- /**
- * Array of conditions that rows must meet
- * @var array
- * @access protected
- */
- protected $_conditions = array();
-
- /**
- * Table to query
- * @var unknown
- * @access protected
- */
- protected $_table;
-
- /**
- * Fields to return in the query
- * @var array
- * @access protected
- */
- protected $_fields;
-
- /**
- * Data for row insertion or update
- * @var unknown
- * @access protected
- */
- protected $_data;
-
- /**
- * Query type. Available types: select, update, insert, delete, count
- * @var string
- * @access protected
- */
- protected $_type;
-
- /**
- * Parameters for tables to join
- * @var array
- * @access protected
- */
- protected $_joins = array();
-
- /**
- * Number of rows to return
- * @var int
- * @access protected
- */
- protected $_limit;
-
- /**
- * Offset of the first row
- * @var int
- * @access protected
- */
- protected $_offset;
-
- /**
- * Columns and directions to order by
- * @var array
- * @access protected
- */
- protected $_orderby = array();
-
- /**
- * Database connection
- * @var DB
- * @access protected
- */
- protected $_db;
-
- /**
- * Conditions for aggregator functions
- * @var array
- * @access protected
- */
- protected $_having = array();
-
- /**
- * Column to group by for aggregator functions
- * @var string
- * @access protected
- */
- protected $_group_by;
-
- /**
- * Last alias used on the table
- * @var string
- * @access protected
- */
- protected $_alias = null;
-
- /**
- * Methods and type of value they allow that are available via __call
- * @var array
- * @access protected
- */
- protected $methods = array('data' => 'array','limit' => array('integer','NULL'),'offset' => array('integer','NULL'),'group_by' => array('string','NULL'),'type' => 'string');
+
+ /**
+ * Array of conditions that rows must meet
+ * @var array
+ * @access protected
+ */
+ protected $_conditions = array();
+
+ /**
+ * Table to query
+ * @var unknown
+ * @access protected
+ */
+ protected $_table;
+
+ /**
+ * Fields to return in the query
+ * @var array
+ * @access protected
+ */
+ protected $_fields;
+
+ /**
+ * Data for row insertion or update
+ * @var unknown
+ * @access protected
+ */
+ protected $_data;
+
+ /**
+ * Query type. Available types: select, update, insert, delete, count
+ * @var string
+ * @access protected
+ */
+ protected $_type;
+
+ /**
+ * Parameters for tables to join
+ * @var array
+ * @access protected
+ */
+ protected $_joins = array();
+
+ /**
+ * Number of rows to return
+ * @var int
+ * @access protected
+ */
+ protected $_limit;
+
+ /**
+ * Offset of the first row
+ * @var int
+ * @access protected
+ */
+ protected $_offset;
+
+ /**
+ * Columns and directions to order by
+ * @var array
+ * @access protected
+ */
+ protected $_orderby = array();
+
+ /**
+ * Database connection
+ * @var DB
+ * @access protected
+ */
+ protected $_db;
+
+ /**
+ * Conditions for aggregator functions
+ * @var array
+ * @access protected
+ */
+ protected $_having = array();
+
+ /**
+ * Column to group by for aggregator functions
+ * @var string
+ * @access protected
+ */
+ protected $_group_by;
+
+ /**
+ * Last alias used on the table
+ * @var string
+ * @access protected
+ */
+ protected $_alias = null;
+
+ /**
+ * Methods and type of value they allow that are available via __call
+ * @var array
+ * @access protected
+ */
+ protected $methods = array('data' => 'array', 'limit' => array('integer', 'NULL'), 'offset' => array('integer', 'NULL'), 'group_by' => array('string', 'NULL'), 'type' => 'string');
/**
* UNION queries
@@ -133,323 +134,326 @@ abstract class Query_Database
* @access protected
*/
protected $_union = array();
-
- /**
- * Generates a query in format that can be executed on current database implementation
- *
- * @access public
- */
- public abstract function query();
-
- /**
- * Creates a new query
- *
- * @param DB $db Database connection
- * @param string $type Query type. Available types: select, update, insert, delete, count
- * @return void
- * @access public
- */
- public function __construct($db, $type)
- {
- $this->_db = $db;
- $this->_type = $type;
- }
-
- /**
- * Sets fields to be queried from the database. You can add aliases to the fields
- * by passing them as:
- *
- * array('field_name','alias')
- *
- * Example: $query->fields('id', array('name', 'fairy_name'))
- *
- * @param mixed $field,... Fields to be selected from the table
- * @return mixed If no parameters are passed returns current array of fields,
- * otherwise returns self.
- * @access public
- */
- public function fields()
- {
- $p = func_get_args();
- if (empty($p))
- {
- return $this->_fields;
- }
- else
- {
- $this->_fields=$p;
- }
- return $this;
- }
/**
- * Sets the table to perform operations on, also supports subqueries
- *
+ * Generates a query in format that can be executed on current database implementation
+ *
+ * @access public
+ */
+ public abstract function query();
+
+ /**
+ * Creates a new query
+ *
+ * @param DB $db Database connection
+ * @param string $type Query type. Available types: select, update, insert, delete, count
+ * @return void
+ * @access public
+ */
+ public function __construct($db, $type)
+ {
+ $this->_db = $db;
+ $this->_type = $type;
+ }
+
+ /**
+ * Sets fields to be queried from the database. You can add aliases to the fields
+ * by passing them as:
+ *
+ * array('field_name','alias')
+ *
+ * Example: $query->fields('id', array('name', 'fairy_name'))
+ *
+ * @param mixed $field,... Fields to be selected from the table
+ * @return mixed If no parameters are passed returns current array of fields,
+ * otherwise returns self.
+ * @access public
+ */
+ public function fields()
+ {
+ $p = func_get_args();
+ if (empty($p))
+ {
+ return $this->_fields;
+ }
+ else
+ {
+ $this->_fields = $p;
+ }
+ return $this;
+ }
+
+ /**
+ * Sets the table to perform operations on, also supports subqueries
+ *
* @param string|Query_database|Expression_database $table table to select from
* @param string $alias Alias for this table
- * @return mixed Returns self if a table is passed, otherwise returns the table
- * @access public
- */
- public function table($table=null,$alias=null)
- {
+ * @return mixed Returns self if a table is passed, otherwise returns the table
+ * @access public
+ */
+ public function table($table = null, $alias = null)
+ {
if ($table == null)
- {
- return is_array($this->_table)?$this->_table[1]:$this->_table;
- }
-
- if (!is_string($table) && $alias==null)
- {
+ {
+ return is_array($this->_table) ? $this->_table[1] : $this->_table;
+ }
+
+ if (!is_string($table) && $alias == null)
+ {
$alias = $this->add_alias();
- }
- $this->_table = $alias == null?$table:array($table, $alias);
-
+ }
+ $this->_table = $alias == null ? $table : array($table, $alias);
+
return $this;
}
+
#
- /**
- * Magic methods to create methods for all generic query parts
- *
- * @param string $method Name of the method to call
- * @param array $args Array of parameters
- * @return mixed If no arguments are passed returns the current value of the property,
- * otherwise returns self.
- * @access public
- * @throws Exception If method doesn't exist
- * @throws Exception If value is of incorrect type
- * @see $methods
- */
- public function __call($method, $args)
- {
- if (isset($this->methods[$method]))
- {
- $property = '_'.$method;
-
- if (empty($args))
- {
- return $this->$property;
- }
- $val = $args[0];
- if (is_numeric($val))
- {
- $val = (int) $val;
- }
- $allowed_types = $this->methods[$method];
- if (!is_array($allowed_types))
- {
- $allowed_types=array($allowed_types);
- }
- if (!in_array(gettype($val), $allowed_types))
- {
- throw new Exception("Method '{$method}' only accepts values of type: ".implode(' or ',$allowed_types).", '{$val}' was passed");
- }
- $this->$property = $val;
- return $this;
- }
- throw new Exception("Method '{$method}' doesn't exist.");
- }
-
- /**
- * Executes the query
- *
- * @return object Executes current query on its database connection
- * @access public
- * @see DB
- */
- public function execute()
- {
- $query = $this->query();
- $result = $this->_db->execute($query[0], $query[1]);
- if ($this->_type == 'count')
- {
- return $result->get('count');
- }
- return $result;
- }
-
- /**
- * Adds a joined table to the query.
- *
- * @param string $table Table to join
- * @param array $conds Conditions to join tables on, same behavior as with where() method
- * @param string $type Type of join. Defaults to 'left'
- * @return Query_Database Returns self
- * @access public
- * @see where()
- */
- public function join($table,$conds,$type='left')
- {
- $this->_joins[] = array($table, $type, $this->get_condition_part($conds));
- return $this;
- }
-
- /**
- * Sets conditions for aggregate functions, same behavior as with where() method
- *
- * @return Query_Database Returns self
- * @access public
- * @see where()
- */
- public function having()
- {
- $p = func_get_args();
- $cond = $this->get_condition_part($p);
- $this->_having = array_merge($this->_having, array($cond));
- return $this;
- }
-
- /**
- * Adds a column to ordering parameters.
- *
- * @param string $column Column to order by
- * @param string $dir Ordering direction.
- * @return Query_Database Returns self
- * @throws Exception If ordering direction isn't DESC or ASC
- * @access public
- */
- public function order_by($column, $dir)
- {
- $dir = strtoupper($dir);
- if ($dir != 'DESC' && $dir != 'ASC')
- {
- throw new Exception("Invalid sorting direction {$dir} specified");
- }
- $this->_orderby[] = array($column,$dir);
- return $this;
- }
-
- /**
- * Sets conditions for the query.
- * Can be called in many ways, examples:
- * Shorthand equals condition:
- * <code>
- * $q->where('name', 'Tinkerbell')
- * </code>
- * Conditions with operator:
- * <code>
- * $q->where('id', '>', 3)
- * </code>
- * OR logic:
- * <code>
- * $q->where('or', array('name', 'Tinkerbell'))
- * </code>
- * OR logic with operator
- * <code>
- * ->where('or', array('id', '>', 3))
- * </code>
- * Arrays represent brackets. e.g
- * <code>
- * $q->where('name', 'Tinkerbell')
- * ->where('or', array(
- * array('id', '>', 7),
- * array('id', '<', 15)
- * );
- * //Will produce "WHERE `name`='Tinkerbell' OR (`id` > 7 AND `id` < 15)"
- * </code>
- * Multiple calls to where() append new conditions to previous ones
- *
- * @param mixed $column Column name, logic parameter 'OR' or 'AND' or an array of conditions
- * @param mixed $operator Condition value, operator or an array of parameters
- * @param mixed $val Condition value
- *
- * @return Query_Database Returns self
- * @access public
- */
- public function where()
- {
- $p = func_get_args();
- $cond = $this->get_condition_part($p);
- $this->_conditions = array_merge($this->_conditions, array($cond));
-
- return $this;
- }
-
- /**
- * Recursively builds condition arrays for methods like where(), having()
- *
- * @param array $p Parameters passed to the method
- * @return array Array in condition format
- * @access private
- * @throws Exception If condition format is incorrect
- */
- private function get_condition_part($p)
- {
- if (is_string($p[0]) && (strtolower($p[0]) == 'or' || strtolower($p[0]) == 'and') && isset($p[1]) && is_array($p[1]))
- {
- $cond = $this->get_condition_part($p[1]);
- $cond['logic'] = strtolower($p[0]);
- return $cond;
- }
-
- if (is_array($p[0]))
- {
- if (count($p) == 1)
- {
- return $this->get_condition_part($p[0]);
- }
- $conds = array();
- foreach($p as $q)
- {
- $conds[] = $this->get_condition_part($q);
- }
- if (count($conds) == 1)
- {
- return $conds;
- }
- return array('logic' => 'and', 'conditions' => $conds);
- }
-
- if ((is_string($p[0]) || get_class($p[0]) == 'Expression_Database') && isset($p[1]))
- {
- if (strpos($p[0], '.') === false)
- {
- $p[0]=$this->last_alias().'.'.$p[0];
- }
- return array(
- 'logic' => 'and',
- 'conditions' => array(
- 'field' => $p[0],
- 'operator' => isset($p[2]) ? $p[1] : '=',
- 'value' => isset($p[2]) ? $p[2] : $p[1]
- )
- );
- }
-
- throw new Exception('Incorrect conditional statement passed');
- }
-
- /**
- * Gets last generated alias
- *
- * @return string Last generated alias. If no alias were created returns table name.
- * @access public
- */
- public function last_alias()
- {
- if ($this->_alias === null)
- {
- return $this->_table;
- }
- return 'a'.$this->_alias;
- }
-
- /**
- * Generates new alias. Useful for dynamically adding aliases to joins.
- * Alias is just a letter 'a' with an incremented number.
- *
- * @return string New alias
- * @access public
- */
- public function add_alias()
- {
- if ($this->_alias === null)
- {
- $this->_alias = 0;
- }
- else
- {
- $this->_alias++;
- }
- return $this->last_alias();
- }
+ /**
+ * Magic methods to create methods for all generic query parts
+ *
+ * @param string $method Name of the method to call
+ * @param array $args Array of parameters
+ * @return mixed If no arguments are passed returns the current value of the property,
+ * otherwise returns self.
+ * @access public
+ * @throws Exception If method doesn't exist
+ * @throws Exception If value is of incorrect type
+ * @see $methods
+ */
+
+ public function __call($method, $args)
+ {
+ if (isset($this->methods[$method]))
+ {
+ $property = '_'.$method;
+
+ if (empty($args))
+ {
+ return $this->$property;
+ }
+ $val = $args[0];
+ if (is_numeric($val))
+ {
+ $val = (int) $val;
+ }
+ $allowed_types = $this->methods[$method];
+ if (!is_array($allowed_types))
+ {
+ $allowed_types = array($allowed_types);
+ }
+ if (!in_array(gettype($val), $allowed_types))
+ {
+ throw new Exception("Method '{$method}' only accepts values of type: ".implode(' or ', $allowed_types).", '{$val}' was passed");
+ }
+ $this->$property = $val;
+ return $this;
+ }
+ throw new Exception("Method '{$method}' doesn't exist.");
+ }
+
+ /**
+ * Executes the query
+ *
+ * @return object Executes current query on its database connection
+ * @access public
+ * @see DB
+ */
+ public function execute()
+ {
+ $query = $this->query();
+ $result = $this->_db->execute($query[0], $query[1]);
+ if ($this->_type == 'count')
+ {
+ return $result->get('count');
+ }
+ return $result;
+ }
+
+ /**
+ * Adds a joined table to the query.
+ *
+ * @param string $table Table to join
+ * @param array $conds Conditions to join tables on, same behavior as with where() method
+ * @param string $type Type of join. Defaults to 'left'
+ * @return Query_Database Returns self
+ * @access public
+ * @see where()
+ */
+ public function join($table, $conds, $type = 'left')
+ {
+ $this->_joins[] = array($table, $type, $this->get_condition_part($conds));
+ return $this;
+ }
+
+ /**
+ * Sets conditions for aggregate functions, same behavior as with where() method
+ *
+ * @return Query_Database Returns self
+ * @access public
+ * @see where()
+ */
+ public function having()
+ {
+ $p = func_get_args();
+ $cond = $this->get_condition_part($p);
+ $this->_having = array_merge($this->_having, array($cond));
+ return $this;
+ }
+
+ /**
+ * Adds a column to ordering parameters.
+ *
+ * @param string $column Column to order by
+ * @param string $dir Ordering direction.
+ * @return Query_Database Returns self
+ * @throws Exception If ordering direction isn't DESC or ASC
+ * @access public
+ */
+ public function order_by($column, $dir)
+ {
+ $dir = strtoupper($dir);
+ if ($dir != 'DESC' && $dir != 'ASC')
+ {
+ throw new Exception("Invalid sorting direction {$dir} specified");
+ }
+ $this->_orderby[] = array($column, $dir);
+ return $this;
+ }
+
+ /**
+ * Sets conditions for the query.
+ * Can be called in many ways, examples:
+ * Shorthand equals condition:
+ * <code>
+ * $q->where('name', 'Tinkerbell')
+ * </code>
+ * Conditions with operator:
+ * <code>
+ * $q->where('id', '>', 3)
+ * </code>
+ * OR logic:
+ * <code>
+ * $q->where('or', array('name', 'Tinkerbell'))
+ * </code>
+ * OR logic with operator
+ * <code>
+ * ->where('or', array('id', '>', 3))
+ * </code>
+ * Arrays represent brackets. e.g
+ * <code>
+ * $q->where('name', 'Tinkerbell')
+ * ->where('or', array(
+ * array('id', '>', 7),
+ * array('id', '<', 15)
+ * );
+ * //Will produce "WHERE `name`='Tinkerbell' OR (`id` > 7 AND `id` < 15)"
+ * </code>
+ * Multiple calls to where() append new conditions to previous ones
+ *
+ * @param mixed $column Column name, logic parameter 'OR' or 'AND' or an array of conditions
+ * @param mixed $operator Condition value, operator or an array of parameters
+ * @param mixed $val Condition value
+ *
+ * @return Query_Database Returns self
+ * @access public
+ */
+ public function where()
+ {
+ $p = func_get_args();
+ $cond = $this->get_condition_part($p);
+ $this->_conditions = array_merge($this->_conditions, array($cond));
+
+ return $this;
+ }
+
+ /**
+ * Recursively builds condition arrays for methods like where(), having()
+ *
+ * @param array $p Parameters passed to the method
+ * @return array Array in condition format
+ * @access private
+ * @throws Exception If condition format is incorrect
+ */
+ private function get_condition_part($p)
+ {
+ if (is_string($p[0]) && (strtolower($p[0]) == 'or' || strtolower($p[0]) == 'and') && isset($p[1]) && is_array($p[1]))
+ {
+ $cond = $this->get_condition_part($p[1]);
+ $cond['logic'] = strtolower($p[0]);
+ return $cond;
+ }
+
+ if (is_array($p[0]))
+ {
+ if (count($p) == 1)
+ {
+ return $this->get_condition_part($p[0]);
+ }
+ $conds = array();
+ foreach ($p as $q)
+ {
+ $conds[] = $this->get_condition_part($q);
+ }
+ if (count($conds) == 1)
+ {
+ return $conds;
+ }
+ return array('logic' => 'and', 'conditions' => $conds);
+ }
+
+ if ((is_string($p[0]) || get_class($p[0]) == 'Expression_Database') && isset($p[1]))
+ {
+ if (strpos($p[0], '.') === false)
+ {
+ $p[0] = $this->last_alias().'.'.$p[0];
+ }
+ return array(
+ 'logic' => 'and',
+ 'conditions' => array(
+ 'field' => $p[0],
+ 'operator' => isset($p[2]) ? $p[1] : '=',
+ 'value' => isset($p[2]) ? $p[2] : $p[1]
+ )
+ );
+ }
+
+ throw new Exception('Incorrect conditional statement passed');
+ }
+
+ /**
+ * Gets last generated alias
+ *
+ * @return string Last generated alias. If no alias were created returns table name.
+ * @access public
+ */
+ public function last_alias()
+ {
+ if ($this->_alias === null)
+ {
+ return $this->_table;
+ }
+ return 'a'.$this->_alias;
+ }
+
+ /**
+ * Generates new alias. Useful for dynamically adding aliases to joins.
+ * Alias is just a letter 'a' with an incremented number.
+ *
+ * @return string New alias
+ * @access public
+ */
+ public function add_alias()
+ {
+ if ($this->_alias === null)
+ {
+ $this->_alias = 0;
+ }
+ else
+ {
+ $this->_alias++;
+ }
+ return $this->last_alias();
+ }
+
}
diff --git a/modules/database/classes/database/result.php b/modules/database/classes/database/result.php
index 1c6b9fe..db58119 100644
--- a/modules/database/classes/database/result.php
+++ b/modules/database/classes/database/result.php
@@ -8,114 +8,114 @@
abstract class Result_Database implements Iterator
{
- /**
- * Current row number
- * @var integer
- * @access protected
- */
- protected $_position = -1;
+ /**
+ * Current row number
+ * @var integer
+ * @access protected
+ */
+ protected $_position = -1;
- /**
- * Database result object
- * @var mixed
- * @access protected
- */
- protected $_result;
+ /**
+ * Database result object
+ * @var mixed
+ * @access protected
+ */
+ protected $_result;
- /**
- * Current row
- * @var object
- * @access protected
- */
- protected $_row;
+ /**
+ * Current row
+ * @var object
+ * @access protected
+ */
+ protected $_row;
- /**
- * If at least one row has been fetched
- * @var object
- * @access protected
- */
- protected $_fetched = false;
+ /**
+ * If at least one row has been fetched
+ * @var object
+ * @access protected
+ */
+ protected $_fetched = false;
- /**
- * Returns current row
- *
- * @return object Current row in result set
- * @access public
- */
- public function current()
- {
- $this->check_fetched();
- return $this->_row;
- }
+ /**
+ * Returns current row
+ *
+ * @return object Current row in result set
+ * @access public
+ */
+ public function current()
+ {
+ $this->check_fetched();
+ return $this->_row;
+ }
- /**
- * Gets the number of the current row
- *
- * @return integer Row number
- * @access public
- */
- public function key()
- {
- $this->check_fetched();
- return $this->_position;
- }
+ /**
+ * Gets the number of the current row
+ *
+ * @return integer Row number
+ * @access public
+ */
+ public function key()
+ {
+ $this->check_fetched();
+ return $this->_position;
+ }
- /**
- * Check if current row exists.
- *
- * @return bool True if row exists
- * @access public
- */
- public function valid()
- {
- $this->check_fetched();
- return $this->_row != null;
- }
+ /**
+ * Check if current row exists.
+ *
+ * @return bool True if row exists
+ * @access public
+ */
+ public function valid()
+ {
+ $this->check_fetched();
+ return $this->_row != null;
+ }
- /**
- * Returns all rows as array
- *
- * @return array Array of rows
- * @access public
- */
- public function as_array()
- {
- $arr = array();
- foreach ($this as $row)
- {
- $arr[] = $row;
- }
- return $arr;
- }
+ /**
+ * Returns all rows as array
+ *
+ * @return array Array of rows
+ * @access public
+ */
+ public function as_array()
+ {
+ $arr = array();
+ foreach ($this as $row)
+ {
+ $arr[] = $row;
+ }
+ return $arr;
+ }
- /**
- * Checks if the rows from the result set have
- * been fetched at least once. If not fetches first row.
- *
- * @access public
- */
- protected function check_fetched()
- {
- if (!$this->_fetched)
- {
- $this->_fetched = true;
- $this->next();
- }
- }
+ /**
+ * Checks if the rows from the result set have
+ * been fetched at least once. If not fetches first row.
+ *
+ * @access public
+ */
+ protected function check_fetched()
+ {
+ if (!$this->_fetched)
+ {
+ $this->_fetched = true;
+ $this->next();
+ }
+ }
- /**
- * Gets a column from the current row in the set
- *
- * @param string $column Column name
- * @return mixed Column value
- * @access public
- */
- public function get($column)
- {
- if ($this->valid() && isset($this->_row->$column))
- {
- return $this->_row->$column;
- }
- }
+ /**
+ * Gets a column from the current row in the set
+ *
+ * @param string $column Column name
+ * @return mixed Column value
+ * @access public
+ */
+ public function get($column)
+ {
+ if ($this->valid() && isset($this->_row->$column))
+ {
+ return $this->_row->$column;
+ }
+ }
} \ No newline at end of file
diff --git a/modules/database/classes/db.php b/modules/database/classes/db.php
index 4979450..ee6d779 100644
--- a/modules/database/classes/db.php
+++ b/modules/database/classes/db.php
@@ -9,140 +9,140 @@
abstract class DB
{
- /**
- * An associative array of connections to databases
- * @var array
- * @access private
- * @static
- */
- private static $_instances = array();
+ /**
+ * An associative array of connections to databases
+ * @var array
+ * @access private
+ * @static
+ */
+ private static $_instances = array();
- /**
- * Executes a prepared statement query
- *
- * @param string $query A prepared statement query
- * @param array $params Parameters for the query
- * @return Result_Database
- * @access public
- * @see Result_Database
- */
- public abstract function execute($query, $params = array());
+ /**
+ * Executes a prepared statement query
+ *
+ * @param string $query A prepared statement query
+ * @param array $params Parameters for the query
+ * @return Result_Database
+ * @access public
+ * @see Result_Database
+ */
+ public abstract function execute($query, $params = array());
- /**
- * Builds a new Query to the database
- *
- * @param string $type Query type. Available types: select, update, insert, delete, count
- * @return Result_Database
- * @access public
- * @see Query_Database
- */
- public abstract function build_query($type);
+ /**
+ * Builds a new Query to the database
+ *
+ * @param string $type Query type. Available types: select, update, insert, delete, count
+ * @return Result_Database
+ * @access public
+ * @see Query_Database
+ */
+ public abstract function build_query($type);
- /**
- * Gets the id of the last inserted row.
- *
- * @return mixed The id of the last inserted row
- * @access public
- */
- public abstract function get_insert_id();
+ /**
+ * Gets the id of the last inserted row.
+ *
+ * @return mixed The id of the last inserted row
+ * @access public
+ */
+ public abstract function get_insert_id();
- /**
- * Gets column names for the specified table
- *
- * @param string $table Name of the table to get columns from
- * @return array Array of column names
- * @access public
- */
- public abstract function list_columns($table);
+ /**
+ * Gets column names for the specified table
+ *
+ * @param string $table Name of the table to get columns from
+ * @return array Array of column names
+ * @access public
+ */
+ public abstract function list_columns($table);
- /**
- * Executes a named query where parameters are passed as an associative array
- * Example:
- * <code>
- * $result=$db->namedQuery("SELECT * FROM fairies where name = :name",array('name'=>'Tinkerbell'));
- * </code>
- *
- * @param string $query A named query
- * @param array $params Associative array of parameters
- * @return Result_Database Current drivers implementation of Result_Database
- * @access public
- */
- public function named_query($query, $params = array())
- {
- $bind = array();
- preg_match_all('#:(\w+)#is', $query, $matches, PREG_SET_ORDER);
- foreach ($matches as $match)
- {
- if (isset($params[$match[1]]))
- {
- $query = preg_replace("#{$match[0]}#", '?', $query, 1);
- $bind[] = $params[$match[1]];
- }
- }
- return $this->execute($query, $bind);
- }
+ /**
+ * Executes a named query where parameters are passed as an associative array
+ * Example:
+ * <code>
+ * $result=$db->namedQuery("SELECT * FROM fairies where name = :name",array('name'=>'Tinkerbell'));
+ * </code>
+ *
+ * @param string $query A named query
+ * @param array $params Associative array of parameters
+ * @return Result_Database Current drivers implementation of Result_Database
+ * @access public
+ */
+ public function named_query($query, $params = array())
+ {
+ $bind = array();
+ preg_match_all('#:(\w+)#is', $query, $matches, PREG_SET_ORDER);
+ foreach ($matches as $match)
+ {
+ if (isset($params[$match[1]]))
+ {
+ $query = preg_replace("#{$match[0]}#", '?', $query, 1);
+ $bind[] = $params[$match[1]];
+ }
+ }
+ return $this->execute($query, $bind);
+ }
- /**
- * Returns an Expression_Database representation of the value.
- * Values wrapped inside Expression_Database are not escaped in queries
- *
- * @param mixed $value Value to be wrapped
- * @return Expression_Database Raw value that will not be escaped during query building
- * @access public
- * @static
- */
- public static function expr($value)
- {
- return new Expression_Database($value);
- }
+ /**
+ * Returns an Expression_Database representation of the value.
+ * Values wrapped inside Expression_Database are not escaped in queries
+ *
+ * @param mixed $value Value to be wrapped
+ * @return Expression_Database Raw value that will not be escaped during query building
+ * @access public
+ * @static
+ */
+ public static function expr($value)
+ {
+ return new Expression_Database($value);
+ }
- /**
- * Builds a query for specified connection.
- *
- * @param string $type Query type. Available types: select,update,insert,delete,count
- * @param string $config Configuration name of the connection.
- * Defaults to 'default'.
- * @return Query_Database Driver implementation of the Query_Database class.
- * @access public
- * @static
- */
- public static function query($type, $config = 'default')
- {
- return DB::instance($config)->build_query($type);
- }
+ /**
+ * Builds a query for specified connection.
+ *
+ * @param string $type Query type. Available types: select,update,insert,delete,count
+ * @param string $config Configuration name of the connection.
+ * Defaults to 'default'.
+ * @return Query_Database Driver implementation of the Query_Database class.
+ * @access public
+ * @static
+ */
+ public static function query($type, $config = 'default')
+ {
+ return DB::instance($config)->build_query($type);
+ }
- /**
- * Gets the id of the last inserted row
- *
- * @param string $config Configuration name of the connection.
- * Defaults to 'default'.
- * @return mixed Id of the last inserted row
- * @access public
- * @static
- */
- public static function insert_id($config = 'default')
- {
- return DB::instance($config)->get_insert_id();
- }
+ /**
+ * Gets the id of the last inserted row
+ *
+ * @param string $config Configuration name of the connection.
+ * Defaults to 'default'.
+ * @return mixed Id of the last inserted row
+ * @access public
+ * @static
+ */
+ public static function insert_id($config = 'default')
+ {
+ return DB::instance($config)->get_insert_id();
+ }
- /**
- * Gets an instance of a connection to the database
- *
- * @param string $config Configuration name of the connection.
- * Defaults to 'default'.
- * @return DB Driver implementation of the DB class.
- * @access public
- * @static
- */
- public static function instance($config = 'default')
- {
- if (!isset(DB::$_instances[$config]))
- {
- $driver = Config::get("database.{$config}.driver");
- $driver = "DB_{$driver}_Driver";
- DB::$_instances[$config] = new $driver($config);
- }
- return DB::$_instances[$config];
- }
+ /**
+ * Gets an instance of a connection to the database
+ *
+ * @param string $config Configuration name of the connection.
+ * Defaults to 'default'.
+ * @return DB Driver implementation of the DB class.
+ * @access public
+ * @static
+ */
+ public static function instance($config = 'default')
+ {
+ if (!isset(DB::$_instances[$config]))
+ {
+ $driver = Config::get("database.{$config}.driver");
+ $driver = "DB_{$driver}_Driver";
+ DB::$_instances[$config] = new $driver($config);
+ }
+ return DB::$_instances[$config];
+ }
}
diff --git a/modules/database/classes/driver/mysql/db.php b/modules/database/classes/driver/mysql/db.php
index 88df9b8..1d49acf 100644
--- a/modules/database/classes/driver/mysql/db.php
+++ b/modules/database/classes/driver/mysql/db.php
@@ -7,120 +7,120 @@
class DB_Mysql_Driver extends DB
{
- /**
- * Mysqli database connection object
- * @var mysqli
- * @access public
- * @link http://php.net/manual/en/class.mysqli.php
- */
- public $conn;
+ /**
+ * Mysqli database connection object
+ * @var mysqli
+ * @access public
+ * @link http://php.net/manual/en/class.mysqli.php
+ */
+ public $conn;
- /**
- * Type of the database, mysql.
- * @var string
- * @access public
- */
- public $db_type = 'mysql';
+ /**
+ * Type of the database, mysql.
+ * @var string
+ * @access public
+ */
+ public $db_type = 'mysql';
- /**
- * Initializes database connection
- *
- * @param string $config Name of the connection to initialize
- * @return void
- * @access public
- */
- public function __construct($config)
- {
- $this->conn = mysqli_connect(
- Config::get("database.{$config}.host", 'localhost'), Config::get("database.{$config}.user", ''), Config::get("database.{$config}.password", ''), Config::get("database.{$config}.db")
- );
- $this->conn->set_charset("utf8");
- }
+ /**
+ * Initializes database connection
+ *
+ * @param string $config Name of the connection to initialize
+ * @return void
+ * @access public
+ */
+ public function __construct($config)
+ {
+ $this->conn = mysqli_connect(
+ Config::get("database.{$config}.host", 'localhost'), Config::get("database.{$config}.user", ''), Config::get("database.{$config}.password", ''), Config::get("database.{$config}.db")
+ );
+ $this->conn->set_charset("utf8");
+ }
- /**
- * Gets column names for the specified table
- *
- * @param string $table Name of the table to get columns from
- * @return array Array of column names
- * @throw Exception if table doesn't exist
- * @access public
- */
- public function list_columns($table)
- {
- $columns = array();
- $table_desc = $this->execute("DESCRIBE `$table`");
- Debug::log($table_desc);
- if (!$table_desc->valid())
- {
- throw new Exception("Table '{$table}' doesn't exist");
- }
- foreach ($table_desc as $column)
- {
- $columns[] = $column->Field;
- }
+ /**
+ * Gets column names for the specified table
+ *
+ * @param string $table Name of the table to get columns from
+ * @return array Array of column names
+ * @throw Exception if table doesn't exist
+ * @access public
+ */
+ public function list_columns($table)
+ {
+ $columns = array();
+ $table_desc = $this->execute("DESCRIBE `$table`");
+ Debug::log($table_desc);
+ if (!$table_desc->valid())
+ {
+ throw new Exception("Table '{$table}' doesn't exist");
+ }
+ foreach ($table_desc as $column)
+ {
+ $columns[] = $column->Field;
+ }
- return $columns;
- }
+ return $columns;
+ }
- /**
- * Builds a new Query implementation
- *
- * @param string $type Query type. Available types: select,update,insert,delete,count
- * @return Query_Mysql_Driver Returns a Mysqli implementation of a Query.
- * @access public
- * @see Query_Database
- */
- public function build_query($type)
- {
- return new Query_Mysql_Driver($this, $type);
- }
+ /**
+ * Builds a new Query implementation
+ *
+ * @param string $type Query type. Available types: select,update,insert,delete,count
+ * @return Query_Mysql_Driver Returns a Mysqli implementation of a Query.
+ * @access public
+ * @see Query_Database
+ */
+ public function build_query($type)
+ {
+ return new Query_Mysql_Driver($this, $type);
+ }
- /**
- * Gets the id of the last inserted row.
- *
- * @return mixed Row id
- * @access public
- */
- public function get_insert_id()
- {
- return $this->conn->insert_id;
- }
+ /**
+ * Gets the id of the last inserted row.
+ *
+ * @return mixed Row id
+ * @access public
+ */
+ public function get_insert_id()
+ {
+ return $this->conn->insert_id;
+ }
- /**
- * Executes a prepared statement query
- *
- * @param string $query A prepared statement query
- * @param array $params Parameters for the query
- * @return Result_Mysql_Driver Mysqli implementation of a database result
- * @access public
- * @throws Exception If the query resulted in an error
- * @see Database_Result
- */
- public function execute($query, $params = array())
- {
- $cursor = $this->conn->prepare($query);
- if (!$cursor)
- {
- throw new Exception("Database error: {$this->conn->error} \n in query:\n{$query}");
- }
- $types = '';
- $bind = array();
- $refs = array();
- if (!empty($params))
- {
- foreach ($params as $key => $param)
- {
- $refs[$key] = is_array($param) ? $param[0] : $param;
- $bind[] = &$refs[$key];
- $types .= is_array($param) ? $param[1] : 's';
- }
- array_unshift($bind, $types);
+ /**
+ * Executes a prepared statement query
+ *
+ * @param string $query A prepared statement query
+ * @param array $params Parameters for the query
+ * @return Result_Mysql_Driver Mysqli implementation of a database result
+ * @access public
+ * @throws Exception If the query resulted in an error
+ * @see Database_Result
+ */
+ public function execute($query, $params = array())
+ {
+ $cursor = $this->conn->prepare($query);
+ if (!$cursor)
+ {
+ throw new Exception("Database error: {$this->conn->error} \n in query:\n{$query}");
+ }
+ $types = '';
+ $bind = array();
+ $refs = array();
+ if (!empty($params))
+ {
+ foreach ($params as $key => $param)
+ {
+ $refs[$key] = is_array($param) ? $param[0] : $param;
+ $bind[] = &$refs[$key];
+ $types .= is_array($param) ? $param[1] : 's';
+ }
+ array_unshift($bind, $types);
- call_user_func_array(array($cursor, 'bind_param'), $bind);
- }
- $cursor->execute();
- $res = $cursor->get_result();
- return new Result_Mysql_Driver($res);
- }
+ call_user_func_array(array($cursor, 'bind_param'), $bind);
+ }
+ $cursor->execute();
+ $res = $cursor->get_result();
+ return new Result_Mysql_Driver($res);
+ }
} \ No newline at end of file
diff --git a/modules/database/classes/driver/mysql/query.php b/modules/database/classes/driver/mysql/query.php
index 803f932..b880338 100644
--- a/modules/database/classes/driver/mysql/query.php
+++ b/modules/database/classes/driver/mysql/query.php
@@ -4,4 +4,7 @@
* Mysqli implementation of the database Query
* @package Database
*/
-class Query_Mysql_Driver extends Query_PDO_Driver {} \ No newline at end of file
+class Query_Mysql_Driver extends Query_PDO_Driver
+{
+
+}
diff --git a/modules/database/classes/driver/mysql/result.php b/modules/database/classes/driver/mysql/result.php
index e9de4a5..2927192 100644
--- a/modules/database/classes/driver/mysql/result.php
+++ b/modules/database/classes/driver/mysql/result.php
@@ -7,52 +7,52 @@
class Result_Mysql_Driver extends Result_Database
{
- /**
- * Initializes new result object
- *
- * @param mysqli_result $result Mysqli Result
- * @return void
- * @access public
- * @link http://php.net/manual/en/class.mysqli-result.php
- */
- public function __construct($result)
- {
- $this->_result = $result;
- }
+ /**
+ * Initializes new result object
+ *
+ * @param mysqli_result $result Mysqli Result
+ * @return void
+ * @access public
+ * @link http://php.net/manual/en/class.mysqli-result.php
+ */
+ public function __construct($result)
+ {
+ $this->_result = $result;
+ }
- /**
- * Throws exception if rewind is attempted.
- *
- * @return void
- * @access public
- * @throws Exception If rewind is attempted
- */
- public function rewind()
- {
- if ($this->_position > 0)
- {
- throw new Exception('Mysqli result cannot be rewound for unbuffered queries.');
- }
- }
+ /**
+ * Throws exception if rewind is attempted.
+ *
+ * @return void
+ * @access public
+ * @throws Exception If rewind is attempted
+ */
+ public function rewind()
+ {
+ if ($this->_position > 0)
+ {
+ throw new Exception('Mysqli result cannot be rewound for unbuffered queries.');
+ }
+ }
- /**
- * Iterates to the next row in the result set
- *
- * @return void
- * @access public
- */
- public function next()
- {
- $this->check_fetched();
- $this->_row = $this->_result->fetch_object();
- if ($this->_row)
- {
- $this->_position++;
- }
- else
- {
- $this->_result->free();
- }
- }
+ /**
+ * Iterates to the next row in the result set
+ *
+ * @return void
+ * @access public
+ */
+ public function next()
+ {
+ $this->check_fetched();
+ $this->_row = $this->_result->fetch_object();
+ if ($this->_row)
+ {
+ $this->_position++;
+ }
+ else
+ {
+ $this->_result->free();
+ }
+ }
} \ No newline at end of file
diff --git a/modules/database/classes/driver/pdo/db.php b/modules/database/classes/driver/pdo/db.php
index 5b81d66..5a920ec 100644
--- a/modules/database/classes/driver/pdo/db.php
+++ b/modules/database/classes/driver/pdo/db.php
@@ -7,125 +7,125 @@
class DB_PDO_Driver extends DB
{
- /**
- * Connection object
- * @var PDO
- * @access public
- * @link http://php.net/manual/en/class.pdo.php
- */
- public $conn;
+ /**
+ * Connection object
+ * @var PDO
+ * @access public
+ * @link http://php.net/manual/en/class.pdo.php
+ */
+ public $conn;
- /**
- * Type of the database, e.g. mysql, pgsql etc.
- * @var string
- * @access public
- */
- public $db_type;
+ /**
+ * Type of the database, e.g. mysql, pgsql etc.
+ * @var string
+ * @access public
+ */
+ public $db_type;
- /**
- * Initializes database connection
- *
- * @param string $config Name of the connection to initialize
- * @return void
- * @access public
- */
- public function __construct($config)
- {
- $this->conn = new PDO(
- Config::get("database.{$config}.connection"), Config::get("database.{$config}.user", ''), Config::get("database.{$config}.password", '')
- );
- $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
- $this->db_type = strtolower(str_replace('PDO_', '', $this->conn->getAttribute(PDO::ATTR_DRIVER_NAME)));
- if ($this->db_type != 'sqlite')
- {
- $this->conn->exec("SET NAMES utf8");
- }
- }
+ /**
+ * Initializes database connection
+ *
+ * @param string $config Name of the connection to initialize
+ * @return void
+ * @access public
+ */
+ public function __construct($config)
+ {
+ $this->conn = new PDO(
+ Config::get("database.{$config}.connection"), Config::get("database.{$config}.user", ''), Config::get("database.{$config}.password", '')
+ );
+ $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ $this->db_type = strtolower(str_replace('PDO_', '', $this->conn->getAttribute(PDO::ATTR_DRIVER_NAME)));
+ if ($this->db_type != 'sqlite')
+ {
+ $this->conn->exec("SET NAMES utf8");
+ }
+ }
- /**
- * Builds a new Query implementation
- *
- * @param string $type Query type. Available types: select,update,insert,delete,count
- * @return Query_PDO_Driver Returns a PDO implementation of a Query.
- * @access public
- * @see Query_Database
- */
- public function build_query($type)
- {
- return new Query_PDO_Driver($this, $type);
- }
+ /**
+ * Builds a new Query implementation
+ *
+ * @param string $type Query type. Available types: select,update,insert,delete,count
+ * @return Query_PDO_Driver Returns a PDO implementation of a Query.
+ * @access public
+ * @see Query_Database
+ */
+ public function build_query($type)
+ {
+ return new Query_PDO_Driver($this, $type);
+ }
- /**
- * Gets the id of the last inserted row.
- *
- * @return mixed Row id
- * @access public
- */
- public function get_insert_id()
- {
- if ($this->db_type == 'pgsql')
- {
- return $this->execute('SELECT lastval() as id')->current()->id;
- }
- return $this->conn->lastInsertId();
- }
+ /**
+ * Gets the id of the last inserted row.
+ *
+ * @return mixed Row id
+ * @access public
+ */
+ public function get_insert_id()
+ {
+ if ($this->db_type == 'pgsql')
+ {
+ return $this->execute('SELECT lastval() as id')->current()->id;
+ }
+ return $this->conn->lastInsertId();
+ }
- /**
- * Gets column names for the specified table
- *
- * @param string $table Name of the table to get columns from
- * @return array Array of column names
- * @access public
- */
- public function list_columns($table)
- {
- $columns = array();
- if ($this->db_type == 'mysql')
- {
- $table_desc = $this->execute("DESCRIBE `$table`");
- foreach ($table_desc as $column)
- {
- $columns[] = $column->Field;
- }
- }
- if ($this->db_type == 'pgsql')
- {
- $table_desc = $this->execute("select column_name from information_schema.columns where table_name = '{$table}' and table_catalog=current_database();");
- foreach ($table_desc as $column)
- {
- $columns[] = $column->column_name;
- }
- }
- if ($this->db_type == 'sqlite')
- {
- $table_desc = $this->execute("PRAGMA table_info('$table')");
- foreach ($table_desc as $column)
- {
- $columns[] = $column->name;
- }
- }
- return $columns;
- }
+ /**
+ * Gets column names for the specified table
+ *
+ * @param string $table Name of the table to get columns from
+ * @return array Array of column names
+ * @access public
+ */
+ public function list_columns($table)
+ {
+ $columns = array();
+ if ($this->db_type == 'mysql')
+ {
+ $table_desc = $this->execute("DESCRIBE `$table`");
+ foreach ($table_desc as $column)
+ {
+ $columns[] = $column->Field;
+ }
+ }
+ if ($this->db_type == 'pgsql')
+ {
+ $table_desc = $this->execute("select column_name from information_schema.columns where table_name = '{$table}' and table_catalog=current_database();");
+ foreach ($table_desc as $column)
+ {
+ $columns[] = $column->column_name;
+ }
+ }
+ if ($this->db_type == 'sqlite')
+ {
+ $table_desc = $this->execute("PRAGMA table_info('$table')");
+ foreach ($table_desc as $column)
+ {
+ $columns[] = $column->name;
+ }
+ }
+ return $columns;
+ }
- /**
- * Executes a prepared statement query
- *
- * @param string $query A prepared statement query
- * @param array $params Parameters for the query
- * @return Result_PDO_Driver PDO implementation of a database result
- * @access public
- * @throws Exception If the query resulted in an error
- * @see Database_Result
- */
- public function execute($query, $params = array())
- {
- $cursor = $this->conn->prepare($query);
- if (!$cursor->execute($params))
- {
- $error = $cursor->errorInfo();
- throw new Exception("Database error:\n".$error[2]." \n in query:\n{$query}");
- }
- return new Result_PDO_Driver($cursor);
- }
+ /**
+ * Executes a prepared statement query
+ *
+ * @param string $query A prepared statement query
+ * @param array $params Parameters for the query
+ * @return Result_PDO_Driver PDO implementation of a database result
+ * @access public
+ * @throws Exception If the query resulted in an error
+ * @see Database_Result
+ */
+ public function execute($query, $params = array())
+ {
+ $cursor = $this->conn->prepare($query);
+ if (!$cursor->execute($params))
+ {
+ $error = $cursor->errorInfo();
+ throw new Exception("Database error:\n".$error[2]." \n in query:\n{$query}");
+ }
+ return new Result_PDO_Driver($cursor);
+ }
} \ No newline at end of file
diff --git a/modules/database/classes/driver/pdo/query.php b/modules/database/classes/driver/pdo/query.php
index d78316d..5d82cbf 100644
--- a/modules/database/classes/driver/pdo/query.php
+++ b/modules/database/classes/driver/pdo/query.php
@@ -7,96 +7,96 @@
class Query_PDO_Driver extends Query_Database
{
- /**
- * Type of the database, e.g. mysql, pgsql etc.
- * @var string
- * @access public
- */
- protected $_db_type;
+ /**
+ * Type of the database, e.g. mysql, pgsql etc.
+ * @var string
+ * @access public
+ */
+ protected $_db_type;
- /**
- * Character to use for quoting fields
- * @var string
- * @access public
- */
- protected $_quote;
+ /**
+ * Character to use for quoting fields
+ * @var string
+ * @access public
+ */
+ protected $_quote;
- /**
- * Creates a new query object, checks which driver we are using and set the character used for quoting
- *
- * @param DB $db Database connection
- * @param string $type Query type. Available types: select, update, insert, delete, count
- * @return void
- * @access public
- * @see Query_Database::__construct()
- */
- public function __construct($db, $type)
- {
- parent::__construct($db, $type);
- $this->_db_type = $this->_db->db_type;
- $this->_quote = $this->_db_type == 'mysql' ? '`' : '"';
- }
+ /**
+ * Creates a new query object, checks which driver we are using and set the character used for quoting
+ *
+ * @param DB $db Database connection
+ * @param string $type Query type. Available types: select, update, insert, delete, count
+ * @return void
+ * @access public
+ * @see Query_Database::__construct()
+ */
+ public function __construct($db, $type)
+ {
+ parent::__construct($db, $type);
+ $this->_db_type = $this->_db->db_type;
+ $this->_quote = $this->_db_type == 'mysql' ? '`' : '"';
+ }
- /**
- * Puts quotes around a string
- *
- * @param string $str String to be enclosed in quotes
- * @return string String surrounded with quotes
- * @access protected
- */
- protected function quote($str)
- {
- return $this->_quote.$str.$this->_quote;
- }
+ /**
+ * Puts quotes around a string
+ *
+ * @param string $str String to be enclosed in quotes
+ * @return string String surrounded with quotes
+ * @access protected
+ */
+ protected function quote($str)
+ {
+ return $this->_quote.$str.$this->_quote;
+ }
- /**
- * If a string is passed escapes a field by enclosing it in specified quotes.
- * If you pass an Expression_Database object the value will be inserted into the query unescaped
- *
- * @param mixed $field Field to be escaped or an Expression_Database object
- * if the field must not be escaped
- * @return string Escaped field representation
- * @access public
- * @see Expression_Database
- */
- public function escape_field($field)
- {
- if (is_object($field) && get_class($field) == 'Expression_Database')
- {
- return $field->value;
- }
- $field = explode('.', $field);
- if (count($field) == 1)
- {
- array_unshift($field, $this->last_alias());
- }
- $str = $this->quote($field[0]).'.';
- if (trim($field[1]) == '*')
- {
- return $str.'*';
- }
- return $str.$this->quote($field[1]);
- }
+ /**
+ * If a string is passed escapes a field by enclosing it in specified quotes.
+ * If you pass an Expression_Database object the value will be inserted into the query unescaped
+ *
+ * @param mixed $field Field to be escaped or an Expression_Database object
+ * if the field must not be escaped
+ * @return string Escaped field representation
+ * @access public
+ * @see Expression_Database
+ */
+ public function escape_field($field)
+ {
+ if (is_object($field) && get_class($field) == 'Expression_Database')
+ {
+ return $field->value;
+ }
+ $field = explode('.', $field);
+ if (count($field) == 1)
+ {
+ array_unshift($field, $this->last_alias());
+ }
+ $str = $this->quote($field[0]).'.';
+ if (trim($field[1]) == '*')
+ {
+ return $str.'*';
+ }
+ return $str.$this->quote($field[1]);
+ }
- /**
- * Replaces the value with ? and appends it to the parameters array
- * If you pass an Expression_Database object the value will be inserted into the query unescaped
- * @param mixed $val Value to be escaped or an Expression_Database object
- * if the value must not be escaped
- * @param array &$params Reference to parameters array
- * @return string Escaped value representation
- * @access public
- */
- public function escape_value($val,&$params)
- {
+ /**
+ * Replaces the value with ? and appends it to the parameters array
+ * If you pass an Expression_Database object the value will be inserted into the query unescaped
+ * @param mixed $val Value to be escaped or an Expression_Database object
+ * if the value must not be escaped
+ * @param array &$params Reference to parameters array
+ * @return string Escaped value representation
+ * @access public
+ */
+ public function escape_value($val, &$params)
+ {
if ($val instanceof Expression_Database)
- {
+ {
return $val->value;
- }
+ }
if ($val instanceof Query_Database)
- {
- return $this->subquery($val,$params);
- }
+ {
+ return $this->subquery($val, $params);
+ }
$params[] = $val;
return '?';
}
@@ -106,295 +106,296 @@ class Query_PDO_Driver extends Query_Database
*
* @param Query_Database $query Query builder for the subquery
* @param array &$params Reference to parameters array
- * @return string Subquery SQL
- * @access public
+ * @return string Subquery SQL
+ * @access public
*/
- protected function subquery($query, &$params) {
+ protected function subquery($query, &$params)
+ {
$query = $query->query();
$params = array_merge($params, $query[1]);
return "({$query[0]}) ";
}
-
+
/**
* Gets the SQL for a table to select from
*
* @param string|Expression_Database|Query_Database|array $table Table representation
* @param array &$params Reference to parameters array
* @param string &alias Alias for this table
- * @return string Table SQL
- * @access public
+ * @return string Table SQL
+ * @access public
*/
- public function escape_table($table, &$params) {
- $alias=null;
- if (is_array($table)) {
+ public function escape_table($table, &$params)
+ {
+ $alias = null;
+ if (is_array($table))
+ {
$alias = $table[1];
$table = $table[0];
}
-
- if (is_string($table)){
+
+ if (is_string($table))
+ {
$table = $this->quote($table);
if ($alias != null)
$table.= " AS {$alias}";
return $table;
}
-
+
if ($alias == null)
$alias = $this->last_alias();
-
- if($table instanceof Query_Database)
- return "{$this->subquery($table,$params)} AS {$alias}";
-
- if($table instanceof Expression_Database)
+
+ if ($table instanceof Query_Database)
+ return "{$this->subquery($table, $params)} AS {$alias}";
+
+ if ($table instanceof Expression_Database)
return "({$table->value}) AS {$alias}";
-
+
throw new Exception("Parameter type {get_class($table)} cannot be used as a table");
}
- /**
- * Builds a query and fills the $params array with parameter values
- *
- * @return array An array with a prepared query string and an array of parameters
- * @access public
- */
+ /**
+ * Builds a query and fills the $params array with parameter values
+ *
+ * @return array An array with a prepared query string and an array of parameters
+ * @access public
+ */
public function query()
- {
-
+ {
+
$query = '';
$params = array();
-
+
if ($this->_type == 'insert')
- {
+ {
$query .= "INSERT INTO {$this->quote($this->_table)} ";
if (empty($this->_data) && $this->_db_type == 'pgsql')
- {
+ {
$query.= "DEFAULT VALUES ";
}
- else
- {
+ else
+ {
$columns = '';
$values = '';
$first = true;
- foreach($this->_data as $key => $val)
- {
+ foreach ($this->_data as $key => $val)
+ {
if (!$first)
- {
+ {
$values .= ', ';
$columns .= ', ';
}
- else
- {
+ else
+ {
$first = false;
}
$columns .= $this->quote($key);
- $values .= $this->escape_value($val,$params);
+ $values .= $this->escape_value($val, $params);
}
$query .= "({$columns}) VALUES({$values})";
}
- }
- else
- {
+ }
+ else
+ {
if ($this->_type == 'select')
- {
+ {
$query .= "SELECT ";
- if ($this->_fields==null)
- {
+ if ($this->_fields == null)
+ {
$query .= "* ";
}
- else
- {
+ else
+ {
$first = true;
foreach ($this->_fields as $f)
- {
+ {
if (!$first)
- {
+ {
$query .= ", ";
}
- else
- {
+ else
+ {
$first = false;
}
if (is_array($f))
- {
+ {
$query .= "{$this->escape_field($f[0])} AS {$f[1]} ";
}
- else
- {
+ else
+ {
$query .= "{$this->escape_field($f)} ";
}
}
}
- $query .= "FROM {$this->escape_table($this->_table,$params)} ";
+ $query .= "FROM {$this->escape_table($this->_table, $params)} ";
}
if ($this->_type == 'count')
- {
- $query .= "SELECT COUNT(*) as {$this->quote('count')} FROM {$this->escape_table($this->_table,$params)} ";
+ {
+ $query .= "SELECT COUNT(*) as {$this->quote('count')} FROM {$this->escape_table($this->_table, $params)} ";
}
-
+
if ($this->_type == 'delete')
- {
- if ($this->_db_type!='sqlite')
- {
+ {
+ if ($this->_db_type != 'sqlite')
+ {
$query .= "DELETE {$this->last_alias()}.* FROM {$this->quote($this->_table)} ";
}
- else
- {
+ else
+ {
if (!empty($this->_joins))
- {
+ {
throw new Exception("SQLite doesn't support deleting a table with JOIN in the query");
- }
+ }
$query .= "DELETE FROM {$this->quote($this->_table)} ";
}
}
- if ($this->_type=='update')
- {
+ if ($this->_type == 'update')
+ {
$query .= "UPDATE {$this->quote($this->_table)} SET ";
$first = true;
- foreach ($this->_data as $key=>$val){
+ foreach ($this->_data as $key => $val)
+ {
if (!$first)
- {
+ {
$query.=", ";
}
- else
- {
- $first=false;
+ else
+ {
+ $first = false;
}
- $query .= "{$this->quote($key)} = {$this->escape_value($val,$params)}";
+ $query .= "{$this->quote($key)} = {$this->escape_value($val, $params)}";
}
$query .= " ";
}
-
+
foreach ($this->_joins as $join)
- {
+ {
$table = $join[0];
- $table = $this->escape_table($table,$params);
- $query .= strtoupper($join[1])." JOIN {$table} ON {$this->get_condition_query($join[2],$params,true,true)} ";
+ $table = $this->escape_table($table, $params);
+ $query .= strtoupper($join[1])." JOIN {$table} ON {$this->get_condition_query($join[2], $params, true, true)} ";
}
if (!empty($this->_conditions))
- {
- $query .= "WHERE {$this->get_condition_query($this->_conditions,$params,true)} ";
+ {
+ $query .= "WHERE {$this->get_condition_query($this->_conditions, $params, true)} ";
}
- if (($this->_type == 'select' || $this->_type == 'count') && $this->_group_by!=null)
- {
+ if (($this->_type == 'select' || $this->_type == 'count') && $this->_group_by != null)
+ {
$query .= "GROUP BY {$this->escape_field($this->_group_by)} ";
}
- if (($this->_type == 'select' || $this->_type == 'count') && !empty($this->_having))
- {
- $query .= "HAVING {$this->get_condition_query($this->_having,$params,true)} ";
+ if (($this->_type == 'select' || $this->_type == 'count') && !empty($this->_having))
+ {
+ $query .= "HAVING {$this->get_condition_query($this->_having, $params, true)} ";
}
-
+
if ($this->_type == 'select' && !empty($this->_orderby))
- {
+ {
$query .= "ORDER BY ";
$first = true;
foreach ($this->_orderby as $order)
- {
+ {
if (!$first)
- {
+ {
$query .= ',';
}
- else
- {
+ else
+ {
$first = false;
}
$query .= $this->escape_field($order[0])." ";
if (isset($order[1]))
- {
+ {
$dir = strtoupper($order[1]);
$query .= $dir." ";
}
}
}
-
+
if (count($this->_union) > 0 && ($this->_type == 'select'))
- {
+ {
$query = "({$query}) ";
foreach ($this->_union as $union)
- {
- $query .= $union[1]?"UNION ALL ":"UNION ";
+ {
+ $query .= $union[1] ? "UNION ALL " : "UNION ";
if (is_subclass_of($union[0], 'Query_Database'))
- {
- $query .= $this->subquery($union[0],$params);
+ {
+ $query .= $this->subquery($union[0], $params);
}
- elseif(is_subclass_of($union[0], 'Expression_Database'))
- {
+ elseif (is_subclass_of($union[0], 'Expression_Database'))
+ {
$query .= "({$union[0]->value}) ";
}
- else
- {
+ else
+ {
throw new Exception("You can only use query builder instances or DB::expr for unions");
}
}
}
-
+
if ($this->_type != 'count')
- {
+ {
if ($this->_limit != null)
- {
+ {
$query .= "LIMIT {$this->_limit} ";
- }
+ }
if ($this->_offset != null)
- {
+ {
$query .= "OFFSET {$this->_offset} ";
- }
+ }
}
-
}
-
- return array($query,$params);
- }
+ return array($query, $params);
+ }
- /**
- * Recursively parses conditions array into a query string
- *
- * @param array $p Element of the cobditions array
- * @param array &$params Reference to parameters array
- * @param boolean $skip_first_operator Flag to skip the first logical operator in a query
- * to prevent AND or OR to be at the beginning of the query
- * @param boolean $value_is_field Flag if the the value in the logical operations should
- * be treated as a field. E.g. for joins where the fields are
- * compared between themselves and not with actual values
- * @return string String representation of the conditions
- * @access public
- * @throws Exception If condition cannot be parsed
- */
- public function get_condition_query($p,&$params,$skip_first_operator,$value_is_field = false)
- {
+ /**
+ * Recursively parses conditions array into a query string
+ *
+ * @param array $p Element of the cobditions array
+ * @param array &$params Reference to parameters array
+ * @param boolean $skip_first_operator Flag to skip the first logical operator in a query
+ * to prevent AND or OR to be at the beginning of the query
+ * @param boolean $value_is_field Flag if the the value in the logical operations should
+ * be treated as a field. E.g. for joins where the fields are
+ * compared between themselves and not with actual values
+ * @return string String representation of the conditions
+ * @access public
+ * @throws Exception If condition cannot be parsed
+ */
+ public function get_condition_query($p, &$params, $skip_first_operator, $value_is_field = false)
+ {
if (isset($p['field']))
- {
+ {
if ($value_is_field)
- {
+ {
$param = $this->escape_field($p['value']);
}
- else
- {
+ else
+ {
$param = $this->escape_value($p['value'], $params);
}
return $this->escape_field($p['field']).' '.$p['operator'].' '.$param;
}
if (isset($p['logic']))
- {
+ {
return ($skip_first_operator ? '' : strtoupper($p['logic']).' ')
- .$this->get_condition_query($p['conditions'], $params, false, $value_is_field);
+ .$this->get_condition_query($p['conditions'], $params, false, $value_is_field);
}
-
+
$conds = '';
$skip = $skip_first_operator || (count($p) > 1);
- foreach($p as $q)
- {
- $conds .= $this->get_condition_query($q,$params,$skip,$value_is_field).' ';
+ foreach ($p as $q)
+ {
+ $conds .= $this->get_condition_query($q, $params, $skip, $value_is_field).' ';
$skip = false;
}
if (count($p) > 1 && !$skip_first_operator)
- {
+ {
return "( ".$conds.")";
- }
+ }
return $conds;
throw new Exception("Cannot parse condition:\n".var_export($p, true));
}
-
-
} \ No newline at end of file
diff --git a/modules/database/classes/driver/pdo/result.php b/modules/database/classes/driver/pdo/result.php
index d64c479..fda813c 100644
--- a/modules/database/classes/driver/pdo/result.php
+++ b/modules/database/classes/driver/pdo/result.php
@@ -7,52 +7,52 @@
class Result_PDO_Driver extends Result_Database
{
- /**
- * Initializes new result object
- *
- * @param PDOStatement $stmt PDO Statement
- * @return void
- * @access public
- * @link http://php.net/manual/en/class.pdostatement.php
- */
- public function __construct($stmt)
- {
- $this->_result = $stmt;
- }
+ /**
+ * Initializes new result object
+ *
+ * @param PDOStatement $stmt PDO Statement
+ * @return void
+ * @access public
+ * @link http://php.net/manual/en/class.pdostatement.php
+ */
+ public function __construct($stmt)
+ {
+ $this->_result = $stmt;
+ }
- /**
- * Throws exception if rewind is attempted.
- *
- * @return void
- * @access public
- * @throws Exception If rewind is attempted
- */
- public function rewind()
- {
- if ($this->_position > 0)
- {
- throw new Exception('PDO statement cannot be rewound for unbuffered queries');
- }
- }
+ /**
+ * Throws exception if rewind is attempted.
+ *
+ * @return void
+ * @access public
+ * @throws Exception If rewind is attempted
+ */
+ public function rewind()
+ {
+ if ($this->_position > 0)
+ {
+ throw new Exception('PDO statement cannot be rewound for unbuffered queries');
+ }
+ }
- /**
- * Iterates to the next row in the result set
- *
- * @return void
- * @access public
- */
- public function next()
- {
- $this->check_fetched();
- $this->_row = $this->_result->fetchObject();
- if ($this->_row)
- {
- $this->_position++;
- }
- else
- {
- $this->_result->closeCursor();
- }
- }
+ /**
+ * Iterates to the next row in the result set
+ *
+ * @return void
+ * @access public
+ */
+ public function next()
+ {
+ $this->check_fetched();
+ $this->_row = $this->_result->fetchObject();
+ if ($this->_row)
+ {
+ $this->_position++;
+ }
+ else
+ {
+ $this->_result->closeCursor();
+ }
+ }
} \ No newline at end of file
diff --git a/modules/orm/classes/orm.php b/modules/orm/classes/orm.php
index 96bfd1e..f975fc1 100644
--- a/modules/orm/classes/orm.php
+++ b/modules/orm/classes/orm.php
@@ -22,791 +22,792 @@
class ORM
{
- /**
- * Specifies which table the model will use, can be overridden
- * @var string
- * @access public
- */
- public $table = null;
-
- /**
- * Specifies which connection the model will use, can be overridden
- * but a model can have relationships only with models utilizing the same connection
- * @var string
- * @access public
- */
- public $connection = 'default';
-
- /**
- * Specifies which column is treated as PRIMARY KEY
- * @var string
- * @access public
- */
- public $id_field = 'id';
-
- /**
- * You can define 'Belongs to' relationships buy changing this array
- * @var array
- * @access protected
- */
- protected $belongs_to = array();
-
- /**
- * You can define 'Has one' relationships buy changing this array
- * @var array
- * @access protected
- */
- protected $has_one = array();
-
- /**
- * You can define 'Has many' relationships buy changing this array
- * @var array
- * @access protected
- */
- protected $has_many = array();
-
- /**
- * Associated query builder
- * @var Query_Database
- * @access public
- */
- public $query;
-
- /**
- * The name of the model
- * @var string
- * @access public
- */
- public $model_name;
-
- /**
- * Cached properties
- * @var array
- * @access public
- */
- public $cached = array();
-
- /**
- * An instance of the database connection
- * @var DB
- * @access protected
- */
- protected $db;
-
- /**
- * Current row returned by the database
- * @var array
- * @access protected
- */
- protected $_row = array();
-
- /**
- * A flag whether the row was loaded from the database
- * @var boolean
- * @access protected
- */
- protected $_loaded = false;
-
- /**
- * Relationships to be preloaded
- * @var array
- * @access protected
- */
- protected $_with = array();
-
- /**
- * Cached column names for tables
- * @var array
- * @access protected
- */
- protected static $_column_cache = array();
-
- /**
- * Constructs the model. To use ORM it is enough to
- * just create a model like this:
- * <code>
- * class Fairy_Model extends ORM { }
- * </code>
- * By default it will assume that the name of your table
- * is the plural form of the models' name, the PRIMARY KEY is id,
- * and will use the 'default' connection. This behaviour is easy to be
- * changed by overriding $table, $id and $db properties.
- *
- * @return void
- * @access public
- * @ see $table
- * @ see $id
- * @ see $db
- */
- public function __construct()
- {
- $this->query = DB::instance($this->connection)->build_query('select');
- $this->model_name = strtolower(get_class($this));
- if (substr($this->model_name, -6) == '_model')
- {
- $this->model_name = substr($this->model_name, 0, -6);
- }
- if ($this->table == null)
- {
- $this->table = ORM::plural($this->model_name);
- }
- $this->query->table($this->table);
-
- foreach (array('belongs_to', 'has_one', 'has_many') as $rels)
- {
- $normalized = array();
- foreach ($this->$rels as $key => $rel)
- {
- if (!is_array($rel))
- {
- $key = $rel;
- $rel = array();
- }
- $normalized[$key] = $rel;
- if (!isset($rel['model']))
- {
- $rel['model'] = $normalized[$key]['model'] = $rels == 'has_many' ? ORM::singular($key) : $key;
- }
-
- $normalized[$key]['type'] = $rels;
- if (!isset($rel['key']))
- {
- $normalized[$key]['key'] = $rels != 'belongs_to' ? ($this->model_name.'_id') : $rel['model'].'_id';
- }
-
- if ($rels == 'has_many' && isset($rel['through']))
- {
- if (!isset($rel['foreign_key']))
- {
- $normalized[$key]['foreign_key'] = $rel['model'].'_id';
- }
- }
-
- $normalized[$key]['name'] = $key;
- }
- $this->$rels = $normalized;
- }
- }
-
- /**
- * Magic method for call Query_Database methods
- *
- * @param string $method Method to call
- * @param array $arguments Arguments passed to the method
- * @return mixed Returns self if parameters were passed. If no parameters where passed returns
- * current value for the associated parameter
- * @throws Exception If method doesn't exist
- * @access public
- */
- public function __call($method, $arguments)
- {
- if (!in_array($method, array('limit', 'offset', 'order_by', 'where')))
- {
- throw new Exception("Method '{$method}' doesn't exist on .".get_class($this));
- }
- $res = call_user_func_array(array($this->query, $method), $arguments);
- if (is_subclass_of($res, 'Query_Database'))
- {
- return $this;
- }
- return $res;
- }
-
- /**
- * Finds all rows that meet set criteria.
- *
- * @return Result_ORM Returns Result_ORM that you can use in a 'foreach' loop.
- * @throw Exception If the relationship specified using with() does not exist or is not of the belongs_to or has_one type
- * @access public
- */
- public function find_all()
- {
- $paths = array();
- if (!empty($this->_with))
- {
- $fields = array();
- $this_alias = $this->query->last_alias();
- foreach ($this->columns() as $column)
- {
- $fields[] = array("{$this_alias}.{$column}", "{$this_alias}__{$column}");
- }
- foreach ($this->_with as $target)
- {
- $model = $this;
- $model_alias = $this_alias;
- $rels = explode('.', $target);
- foreach ($rels as $key => $rel_name)
- {
- $path = implode('.', array_slice($rels, 0, $key + 1));
- if (isset($paths[$path]))
- {
- $model = $paths[$path]['model'];
- $model_alias = $paths[$path]['alias'];
- continue;
- }
- $alias = $this->query->add_alias();
- $model_rels = array_merge($model->has_one, $model->has_many, $model->belongs_to);
- $rel = Misc::arr($model_rels, $rel_name, false);
-
- if (!$rel)
- {
- throw new Exception("Model '{$model->model_name}' doesn't have a '{$rel_name}' relation defined");
- }
- if ($rel['type'] == 'has_many')
- {
- throw new Exception("Relationship '{$rel_name}' is of has_many type and cannot be preloaded view with()");
- }
- $rel_model = ORM::factory($rel['model']);
-
- if ($rel['type'] == 'belongs_to')
- {
- $this->query->join(array($rel_model->table, $alias), array(
- $model_alias.'.'.$rel['key'],
- $alias.'.'.$rel_model->id_field,
- ), 'left');
- }
- else
- {
- $this->query->join(array($rel_model->table, $alias), array(
- $model_alias.'.'.$model->id_field,
- $alias.'.'.$rel['key'],
- ), 'left');
- }
-
- foreach ($rel_model->columns() as $column)
- {
- $fields[] = array("{$alias}.{$column}", "{$alias}__{$column}");
- }
- $model = $rel_model;
- $model_alias = $alias;
- $paths[$path] = array('alias' => $alias, 'model' => $model);
- }
- }
-
- call_user_func_array(array($this->query, 'fields'), $fields);
- }
-
- return new Result_ORM(get_class($this), $res = $this->query->execute(), $paths);
- }
-
- /**
- * Searches for the first row that meets set criteria. If no rows match it still returns an ORM object
- * but with its loaded() flag being False. calling save() on such an object will insert a new row.
- *
- * @return ORM Found item or new object of the current model but with loaded() flag being False
- * @access public
- */
- public function find()
- {
- $set_limit = $this->limit();
- $res = $this->limit(1)->find_all()->current();
- $this->limit($set_limit);
- return $res;
- }
-
- /**
- * Counts all rows that meet set criteria. Ignores limit and offset.
- *
- * @return int Number of rows
- * @access public
- */
- public function count_all()
- {
- $query = clone $this->query;
- $query->type('count');
- return $query->execute();
- }
-
- /**
- * Checks if the item is considered to be loaded from the database
- *
- * @return boolean Returns True if the item was loaded
- * @access public
- */
- public function loaded()
- {
- return $this->_loaded;
- }
-
- /**
- * Returns the row associated with current ORM item as an associative array
- *
- * @return array Associative array representing the row
- * @access public
- */
- public function as_array()
- {
- return $this->_row;
- }
-
- /**
- * Returns a clone of query builder that is being used to set conditions.
- * It is useful for example if you let ORM manage building a complex query using it's relationship
- * system, then you get the clone of that query and alter it to your liking,
- * so there is no need to writing relationship joins yourself.
- *
- * @return Query_Database A clone of the current query builder
- * @access public
- */
- public function query()
- {
- return clone $this->query;
- }
-
- /**
- * You can override this method to return additional properties that you would like to use
- * in your model. One advantage for using this instead of just overriding __get() is that
- * in this way the properties also get cached.
- *
- * @param string $property The name of the property to get
- * @return void
- * @access public
- */
- public function get($property)
- {
-
- }
-
- /**
- * Magic method that allows accessing row columns as properties and also facilitates
- * access to relationships and custom properties defined in get() method.
- * If a relationship is being accessed, it will return an ORM model of the related table
- * and automatically alter its query so that all your previously set conditions will remain
-
- * @param string $column Name of the column, property or relationship to get
- * @return mixed
- * @access public
- * @throws Exception If neither property nor a relationship with such name is found
- */
- public function __get($column)
- {
- if (array_key_exists($column, $this->_row))
- {
- return $this->_row[$column];
- }
- if (array_key_exists($column, $this->cached))
- {
- return $this->cached[$column];
- }
- if (($val = $this->get($column)) !== null)
- {
- $this->cached[$column] = $val;
- return $val;
- }
- $relations = array_merge($this->has_one, $this->has_many, $this->belongs_to);
- if ($target = Misc::arr($relations, $column, false))
- {
- $model = ORM::factory($target['model']);
- $model->query = clone $this->query;
- if ($this->loaded())
- {
- $model->query->where($this->id_field, $this->_row[$this->id_field]);
- }
- if ($target['type'] == 'has_many' && isset($target['through']))
- {
- $last_alias = $model->query->last_alias();
- $through_alias = $model->query->add_alias();
- $new_alias = $model->query->add_alias();
- $model->query->join(array($target['through'], $through_alias), array(
- $last_alias.'.'.$this->id_field,
- $through_alias.'.'.$target['key'],
- ), 'inner');
- $model->query->join(array($model->table, $new_alias), array(
- $through_alias.'.'.$target['foreign_key'],
- $new_alias.'.'.$model->id_field,
- ), 'inner');
- }
- else
- {
- $last_alias = $model->query->last_alias();
- $new_alias = $model->query->add_alias();
- if ($target['type'] == 'belongs_to')
- {
- $model->query->join(array($model->table, $new_alias), array(
- $last_alias.'.'.$target['key'],
- $new_alias.'.'.$model->id_field,
- ), 'inner');
- }
- else
- {
- $model->query->join(array($model->table, $new_alias), array(
- $last_alias.'.'.$this->id_field,
- $new_alias.'.'.$target['key'],
- ), 'inner');
- }
- }
- $model->query->fields("$new_alias.*");
- if ($target['type'] != 'has_many' && $this->loaded())
- {
- $model = $model->find();
- $this->cached[$column] = $model;
- }
- return $model;
- }
-
- throw new Exception("Property {$column} not found on {$this->model_name} model.");
- }
-
- /**
- * Magic method to update record values when set as properties or to add an ORM item to
- * a relation. By assigning an ORM object to a relationship a relationship is created between the
- * current item and the passed one Using properties this way is a shortcut to the add() method.
- *
- * @param string $column Column or relationship name
- * @param mixed $val Column value or an ORM item to be added to a relation
- * @return void
- * @access public
- * @see add()
- */
- public function __set($column, $val)
- {
- $relations = array_merge($this->has_one, $this->has_many, $this->belongs_to);
- if (array_key_exists($column, $relations))
- {
- $this->add($column, $val);
- }
- else
- {
- $this->_row[$column] = $val;
- }
- $this->cached = array();
- }
-
- /**
- * Create a relationship between current item and an other one
- *
- * @param string $relation Name of the relationship
- * @param ORM $model ORM item to create a relationship with
- * @return void
- * @access public
- * @throws Exception Exception If relationship is not defined
- * @throws Exception Exception If current item is not in the database yet (isn't considered loaded())
- * @throws Exception Exception If passed item is not in the database yet (isn't considered loaded())
- */
- public function add($relation, $model)
- {
-
- $rels = array_merge($this->has_one, $this->has_many, $this->belongs_to);
- $rel = Misc::arr($rels, $relation, false);
- if (!$rel)
- {
- throw new Exception("Model doesn't have a '{$relation}' relation defined");
- }
-
- if ($rel['type'] == 'belongs_to')
- {
-
- if (!$model->loaded())
- {
- throw new Exception("Model must be loaded before added to a belongs_to relationship. Probably you haven't saved it.");
- }
-
- $key = $rel['key'];
- $this->$key = $model->_row[$this->id_field];
- if ($this->loaded())
- {
- $this->save();
- }
- }
- elseif (isset($rel['through']))
- {
-
- if (!$this->loaded())
- {
- throw new Exception("Model must be loaded before you try adding 'through' relationships to it. Probably you haven't saved it.");
- }
- if (!$model->loaded())
- {
- throw new Exception("Model must be loaded before added to a 'through' relationship. Probably you haven't saved it.");
- }
-
- $exists = DB::instance($this->connection)->build_query('count')
- ->table($rel['through'])
- ->where(array(
- array($rel['key'], $this->_row[$this->id_field]),
- array($rel['foreign_key'], $model->_row[$model->id_field])
- ))
- ->execute();
- if (!$exists)
- {
- DB::instance($this->connection)->build_query('insert')
- ->table($rel['through'])
- ->data(array(
- $rel['key'] => $this->_row[$this->id_field],
- $rel['foreign_key'] => $model->_row[$model->id_field]
- ))
- ->execute();
- }
- }
- else
- {
-
- if (!$this->loaded())
- {
- throw new Exception("Model must be loaded before you try adding 'has_many' relationships to it. Probably you haven't saved it.");
- }
-
- $key = $rel['key'];
- $model->$key = $this->_row[$this->id_field];
- if ($model->loaded())
- {
- $model->save();
- }
- }
- $this->cached = array();
- }
-
- /**
- * Removes a relationship between current item and the passed one
- *
- * @param string $relation Name of the relationship
- * @param ORM $model ORM item to remove relationship with. Can be omitted for 'belongs_to' relationships
- * @return void
- * @access public
- * @throws Exception Exception If realtionship is not defined
- * @throws Exception Exception If current item is not in the database yet (isn't considered loaded())
- * @throws Exception Exception If passed item is not in the database yet (isn't considered loaded())
- */
- public function remove($relation, $model = null)
- {
-
- if (!$this->loaded())
- {
- throw new Exception("Model must be loaded before you try removing relationships from it.");
- }
-
- $rels = array_merge($this->has_one, $this->has_many, $this->belongs_to);
- $rel = Misc::arr($rels, $relation, false);
- if (!$rel)
- {
- throw new Exception("Model doesn't have a '{$relation}' relation defined");
- }
-
- if ($rel['type'] != 'belongs_to' && (!$model || !$model->loaded()))
- {
- throw new Exception("Model must be loaded before being removed from a has_one or has_many relationship.");
- }
- if ($rel['type'] == 'belongs_to')
- {
- $key = $rel['key'];
- $this->$key = null;
- $this->save();
- }
- elseif (isset($rel['through']))
- {
- DB::instance($this->connection)->build_query('delete')
- ->table($rel['through'])
- ->where(array(
- array($rel['key'], $this->_row[$this->id_field]),
- array($rel['foreign_key'], $model->_row[$model->id_field])
- ))
- ->execute();
- }
- else
- {
- $key = $rel['key'];
- $model->$key = null;
- $model->save();
- }
- $this->cached = array();
- }
-
- /**
- * Gets name column names of the table associated with the model.
- *
- * @return array Array of column names
- * @access public
- */
- public function columns()
- {
- if (!isset(ORM::$_column_cache[$this->table]))
- {
- ORM::$_column_cache[$this->table] = DB::instance($this->connection)->list_columns($this->table);
- }
- return ORM::$_column_cache[$this->table];
- }
-
- /**
- * Defines which relationships should be preloaded. You can only preload
- * belongs_to and has_one relationships. You can use the dot notation to
- * preload deep relationsips, e.g. 'tree.protector' will preload the tree
- * that a fairy lives in and also preload the protector of that tree.
- *
- * @param string $relationsip,... List of relationships to preload
- * @return ORM Returns itself
- * @access public
- */
- public function with()
- {
- $this->_with = func_get_args();
- return $this;
- }
-
- /**
- * Deletes current item from the database
- *
- * @return void
- * @access public
- * @throws Exception If the item is not in the database, e.g. is not loaded()
- */
- public function delete()
- {
- if (!$this->loaded())
- {
- throw new Exception("Cannot delete an item that wasn't selected from database");
- }
- DB::instance($this->connection)->build_query('delete')
- ->table($this->table)
- ->where($this->id_field, $this->_row[$this->id_field])
- ->execute();
- $this->cached = array();
- }
-
- /**
- * Deletes all items that meet set conditions. Use in the same way
- * as you would a find_all() method.
- *
- * @return ORM Returns self
- * @access public
- */
- public function delete_all()
- {
- $query = clone $this->query;
- $query->type('delete');
- $query->execute();
- return $this;
- }
-
- /**
- * Saves the item back to the database. If item is loaded() it will result
- * in an update, otherwise a new row will be inserted
- *
- * @return ORM Returns self
- * @access public
- */
- public function save()
- {
- if ($this->loaded())
- {
- $query = DB::instance($this->connection)->build_query('update')
- ->table($this->table)
- ->where($this->id_field, $this->_row[$this->id_field]);
- }
- else
- {
- $query = DB::instance($this->connection)->build_query('insert')
- ->table($this->table);
- }
- $query->data($this->_row);
- $query->execute();
-
- if ($this->loaded())
- {
- $id = $this->_row[$this->id_field];
- }
- else
- {
- $id = DB::instance($this->connection)->get_insert_id();
- }
- $row = (array) DB::instance($this->connection)->build_query('select')
- ->table($this->table)
- ->where($this->id_field, $id)->execute()->current();
- $this->values($row, true);
- return $this;
- }
-
- /**
- * Batch updates item columns using an associative array
- *
- * @param array $row Associative array of key => value pairs
- * @param boolean $set_loaded Flag to consider the ORM item loaded. Useful if you selected
- * the row from the database and want to wrap it in ORM
- * @return ORM Returns self
- * @access public
- */
- public function values($row, $set_loaded = false)
- {
- $this->_row = array_merge($this->_row, $row);
- if ($set_loaded)
- {
- $this->_loaded = true;
- }
- $this->cached = array();
- return $this;
- }
-
- /**
- * Initializes ORM model by name, and optionally fetches an item by id
- *
- * @param string $name Model name
- * @param mixed $id If set ORM will try to load the item with this id from the database
- * @return ORM ORM model, either empty or preloaded
- * @access public
- * @static
- */
- public static function factory($name, $id = null)
- {
- $model = $name.'_Model';
- $model = new $model;
- if ($id != null)
- {
- $model = $model->where($model->id_field, $id)->find();
- $model->values(array($model->id_field => $id));
- }
- return $model;
- }
-
- /**
- * Gets plural form of a noun
- *
- * @param string $str Noun to get a plural form of
- * @return string Plural form
- * @access private
- * @static
- */
- private static function plural($str)
- {
- $regexes = array(
- '/^(.*?[sxz])$/i' => '\\1es',
- '/^(.*?[^aeioudgkprt]h)$/i' => '\\1es',
- '/^(.*?[^aeiou])y$/i' => '\\1ies',
- );
- foreach ($regexes as $key => $val)
- {
- $str = preg_replace($key, $val, $str, -1, $count);
- if ($count)
- {
- return $str;
- }
- }
- return $str.'s';
- }
-
- /**
- * Gets singular form of a noun
- *
- * @param string $str Noun to get singular form of
- * @return string Singular form of the noun
- * @access private
- * @static
- */
- private static function singular($str)
- {
- $regexes = array(
- '/^(.*?us)$/i' => '\\1',
- '/^(.*?[sxz])es$/i' => '\\1',
- '/^(.*?[^aeioudgkprt]h)es$/i' => '\\1',
- '/^(.*?[^aeiou])ies$/i' => '\\1y',
- '/^(.*?)s$/' => '\\1',
- );
- foreach ($regexes as $key => $val)
- {
- $str = preg_replace($key, $val, $str, -1, $count);
- if ($count)
- {
- return $str;
- }
- }
- return $str;
- }
+ /**
+ * Specifies which table the model will use, can be overridden
+ * @var string
+ * @access public
+ */
+ public $table = null;
+
+ /**
+ * Specifies which connection the model will use, can be overridden
+ * but a model can have relationships only with models utilizing the same connection
+ * @var string
+ * @access public
+ */
+ public $connection = 'default';
+
+ /**
+ * Specifies which column is treated as PRIMARY KEY
+ * @var string
+ * @access public
+ */
+ public $id_field = 'id';
+
+ /**
+ * You can define 'Belongs to' relationships buy changing this array
+ * @var array
+ * @access protected
+ */
+ protected $belongs_to = array();
+
+ /**
+ * You can define 'Has one' relationships buy changing this array
+ * @var array
+ * @access protected
+ */
+ protected $has_one = array();
+
+ /**
+ * You can define 'Has many' relationships buy changing this array
+ * @var array
+ * @access protected
+ */
+ protected $has_many = array();
+
+ /**
+ * Associated query builder
+ * @var Query_Database
+ * @access public
+ */
+ public $query;
+
+ /**
+ * The name of the model
+ * @var string
+ * @access public
+ */
+ public $model_name;
+
+ /**
+ * Cached properties
+ * @var array
+ * @access public
+ */
+ public $cached = array();
+
+ /**
+ * An instance of the database connection
+ * @var DB
+ * @access protected
+ */
+ protected $db;
+
+ /**
+ * Current row returned by the database
+ * @var array
+ * @access protected
+ */
+ protected $_row = array();
+
+ /**
+ * A flag whether the row was loaded from the database
+ * @var boolean
+ * @access protected
+ */
+ protected $_loaded = false;
+
+ /**
+ * Relationships to be preloaded
+ * @var array
+ * @access protected
+ */
+ protected $_with = array();
+
+ /**
+ * Cached column names for tables
+ * @var array
+ * @access protected
+ */
+ protected static $_column_cache = array();
+
+ /**
+ * Constructs the model. To use ORM it is enough to
+ * just create a model like this:
+ * <code>
+ * class Fairy_Model extends ORM { }
+ * </code>
+ * By default it will assume that the name of your table
+ * is the plural form of the models' name, the PRIMARY KEY is id,
+ * and will use the 'default' connection. This behaviour is easy to be
+ * changed by overriding $table, $id and $db properties.
+ *
+ * @return void
+ * @access public
+ * @ see $table
+ * @ see $id
+ * @ see $db
+ */
+ public function __construct()
+ {
+ $this->query = DB::instance($this->connection)->build_query('select');
+ $this->model_name = strtolower(get_class($this));
+ if (substr($this->model_name, -6) == '_model')
+ {
+ $this->model_name = substr($this->model_name, 0, -6);
+ }
+ if ($this->table == null)
+ {
+ $this->table = ORM::plural($this->model_name);
+ }
+ $this->query->table($this->table);
+
+ foreach (array('belongs_to', 'has_one', 'has_many') as $rels)
+ {
+ $normalized = array();
+ foreach ($this->$rels as $key => $rel)
+ {
+ if (!is_array($rel))
+ {
+ $key = $rel;
+ $rel = array();
+ }
+ $normalized[$key] = $rel;
+ if (!isset($rel['model']))
+ {
+ $rel['model'] = $normalized[$key]['model'] = $rels == 'has_many' ? ORM::singular($key) : $key;
+ }
+
+ $normalized[$key]['type'] = $rels;
+ if (!isset($rel['key']))
+ {
+ $normalized[$key]['key'] = $rels != 'belongs_to' ? ($this->model_name.'_id') : $rel['model'].'_id';
+ }
+
+ if ($rels == 'has_many' && isset($rel['through']))
+ {
+ if (!isset($rel['foreign_key']))
+ {
+ $normalized[$key]['foreign_key'] = $rel['model'].'_id';
+ }
+ }
+
+ $normalized[$key]['name'] = $key;
+ }
+ $this->$rels = $normalized;
+ }
+ }
+
+ /**
+ * Magic method for call Query_Database methods
+ *
+ * @param string $method Method to call
+ * @param array $arguments Arguments passed to the method
+ * @return mixed Returns self if parameters were passed. If no parameters where passed returns
+ * current value for the associated parameter
+ * @throws Exception If method doesn't exist
+ * @access public
+ */
+ public function __call($method, $arguments)
+ {
+ if (!in_array($method, array('limit', 'offset', 'order_by', 'where')))
+ {
+ throw new Exception("Method '{$method}' doesn't exist on .".get_class($this));
+ }
+ $res = call_user_func_array(array($this->query, $method), $arguments);
+ if (is_subclass_of($res, 'Query_Database'))
+ {
+ return $this;
+ }
+ return $res;
+ }
+
+ /**
+ * Finds all rows that meet set criteria.
+ *
+ * @return Result_ORM Returns Result_ORM that you can use in a 'foreach' loop.
+ * @throw Exception If the relationship specified using with() does not exist or is not of the belongs_to or has_one type
+ * @access public
+ */
+ public function find_all()
+ {
+ $paths = array();
+ if (!empty($this->_with))
+ {
+ $fields = array();
+ $this_alias = $this->query->last_alias();
+ foreach ($this->columns() as $column)
+ {
+ $fields[] = array("{$this_alias}.{$column}", "{$this_alias}__{$column}");
+ }
+ foreach ($this->_with as $target)
+ {
+ $model = $this;
+ $model_alias = $this_alias;
+ $rels = explode('.', $target);
+ foreach ($rels as $key => $rel_name)
+ {
+ $path = implode('.', array_slice($rels, 0, $key + 1));
+ if (isset($paths[$path]))
+ {
+ $model = $paths[$path]['model'];
+ $model_alias = $paths[$path]['alias'];
+ continue;
+ }
+ $alias = $this->query->add_alias();
+ $model_rels = array_merge($model->has_one, $model->has_many, $model->belongs_to);
+ $rel = Misc::arr($model_rels, $rel_name, false);
+
+ if (!$rel)
+ {
+ throw new Exception("Model '{$model->model_name}' doesn't have a '{$rel_name}' relation defined");
+ }
+ if ($rel['type'] == 'has_many')
+ {
+ throw new Exception("Relationship '{$rel_name}' is of has_many type and cannot be preloaded view with()");
+ }
+ $rel_model = ORM::factory($rel['model']);
+
+ if ($rel['type'] == 'belongs_to')
+ {
+ $this->query->join(array($rel_model->table, $alias), array(
+ $model_alias.'.'.$rel['key'],
+ $alias.'.'.$rel_model->id_field,
+ ), 'left');
+ }
+ else
+ {
+ $this->query->join(array($rel_model->table, $alias), array(
+ $model_alias.'.'.$model->id_field,
+ $alias.'.'.$rel['key'],
+ ), 'left');
+ }
+
+ foreach ($rel_model->columns() as $column)
+ {
+ $fields[] = array("{$alias}.{$column}", "{$alias}__{$column}");
+ }
+ $model = $rel_model;
+ $model_alias = $alias;
+ $paths[$path] = array('alias' => $alias, 'model' => $model);
+ }
+ }
+
+ call_user_func_array(array($this->query, 'fields'), $fields);
+ }
+
+ return new Result_ORM(get_class($this), $res = $this->query->execute(), $paths);
+ }
+
+ /**
+ * Searches for the first row that meets set criteria. If no rows match it still returns an ORM object
+ * but with its loaded() flag being False. calling save() on such an object will insert a new row.
+ *
+ * @return ORM Found item or new object of the current model but with loaded() flag being False
+ * @access public
+ */
+ public function find()
+ {
+ $set_limit = $this->limit();
+ $res = $this->limit(1)->find_all()->current();
+ $this->limit($set_limit);
+ return $res;
+ }
+
+ /**
+ * Counts all rows that meet set criteria. Ignores limit and offset.
+ *
+ * @return int Number of rows
+ * @access public
+ */
+ public function count_all()
+ {
+ $query = clone $this->query;
+ $query->type('count');
+ return $query->execute();
+ }
+
+ /**
+ * Checks if the item is considered to be loaded from the database
+ *
+ * @return boolean Returns True if the item was loaded
+ * @access public
+ */
+ public function loaded()
+ {
+ return $this->_loaded;
+ }
+
+ /**
+ * Returns the row associated with current ORM item as an associative array
+ *
+ * @return array Associative array representing the row
+ * @access public
+ */
+ public function as_array()
+ {
+ return $this->_row;
+ }
+
+ /**
+ * Returns a clone of query builder that is being used to set conditions.
+ * It is useful for example if you let ORM manage building a complex query using it's relationship
+ * system, then you get the clone of that query and alter it to your liking,
+ * so there is no need to writing relationship joins yourself.
+ *
+ * @return Query_Database A clone of the current query builder
+ * @access public
+ */
+ public function query()
+ {
+ return clone $this->query;
+ }
+
+ /**
+ * You can override this method to return additional properties that you would like to use
+ * in your model. One advantage for using this instead of just overriding __get() is that
+ * in this way the properties also get cached.
+ *
+ * @param string $property The name of the property to get
+ * @return void
+ * @access public
+ */
+ public function get($property)
+ {
+
+ }
+
+ /**
+ * Magic method that allows accessing row columns as properties and also facilitates
+ * access to relationships and custom properties defined in get() method.
+ * If a relationship is being accessed, it will return an ORM model of the related table
+ * and automatically alter its query so that all your previously set conditions will remain
+
+ * @param string $column Name of the column, property or relationship to get
+ * @return mixed
+ * @access public
+ * @throws Exception If neither property nor a relationship with such name is found
+ */
+ public function __get($column)
+ {
+ if (array_key_exists($column, $this->_row))
+ {
+ return $this->_row[$column];
+ }
+ if (array_key_exists($column, $this->cached))
+ {
+ return $this->cached[$column];
+ }
+ if (($val = $this->get($column)) !== null)
+ {
+ $this->cached[$column] = $val;
+ return $val;
+ }
+ $relations = array_merge($this->has_one, $this->has_many, $this->belongs_to);
+ if ($target = Misc::arr($relations, $column, false))
+ {
+ $model = ORM::factory($target['model']);
+ $model->query = clone $this->query;
+ if ($this->loaded())
+ {
+ $model->query->where($this->id_field, $this->_row[$this->id_field]);
+ }
+ if ($target['type'] == 'has_many' && isset($target['through']))
+ {
+ $last_alias = $model->query->last_alias();
+ $through_alias = $model->query->add_alias();
+ $new_alias = $model->query->add_alias();
+ $model->query->join(array($target['through'], $through_alias), array(
+ $last_alias.'.'.$this->id_field,
+ $through_alias.'.'.$target['key'],
+ ), 'inner');
+ $model->query->join(array($model->table, $new_alias), array(
+ $through_alias.'.'.$target['foreign_key'],
+ $new_alias.'.'.$model->id_field,
+ ), 'inner');
+ }
+ else
+ {
+ $last_alias = $model->query->last_alias();
+ $new_alias = $model->query->add_alias();
+ if ($target['type'] == 'belongs_to')
+ {
+ $model->query->join(array($model->table, $new_alias), array(
+ $last_alias.'.'.$target['key'],
+ $new_alias.'.'.$model->id_field,
+ ), 'inner');
+ }
+ else
+ {
+ $model->query->join(array($model->table, $new_alias), array(
+ $last_alias.'.'.$this->id_field,
+ $new_alias.'.'.$target['key'],
+ ), 'inner');
+ }
+ }
+ $model->query->fields("$new_alias.*");
+ if ($target['type'] != 'has_many' && $this->loaded())
+ {
+ $model = $model->find();
+ $this->cached[$column] = $model;
+ }
+ return $model;
+ }
+
+ throw new Exception("Property {$column} not found on {$this->model_name} model.");
+ }
+
+ /**
+ * Magic method to update record values when set as properties or to add an ORM item to
+ * a relation. By assigning an ORM object to a relationship a relationship is created between the
+ * current item and the passed one Using properties this way is a shortcut to the add() method.
+ *
+ * @param string $column Column or relationship name
+ * @param mixed $val Column value or an ORM item to be added to a relation
+ * @return void
+ * @access public
+ * @see add()
+ */
+ public function __set($column, $val)
+ {
+ $relations = array_merge($this->has_one, $this->has_many, $this->belongs_to);
+ if (array_key_exists($column, $relations))
+ {
+ $this->add($column, $val);
+ }
+ else
+ {
+ $this->_row[$column] = $val;
+ }
+ $this->cached = array();
+ }
+
+ /**
+ * Create a relationship between current item and an other one
+ *
+ * @param string $relation Name of the relationship
+ * @param ORM $model ORM item to create a relationship with
+ * @return void
+ * @access public
+ * @throws Exception Exception If relationship is not defined
+ * @throws Exception Exception If current item is not in the database yet (isn't considered loaded())
+ * @throws Exception Exception If passed item is not in the database yet (isn't considered loaded())
+ */
+ public function add($relation, $model)
+ {
+
+ $rels = array_merge($this->has_one, $this->has_many, $this->belongs_to);
+ $rel = Misc::arr($rels, $relation, false);
+ if (!$rel)
+ {
+ throw new Exception("Model doesn't have a '{$relation}' relation defined");
+ }
+
+ if ($rel['type'] == 'belongs_to')
+ {
+
+ if (!$model->loaded())
+ {
+ throw new Exception("Model must be loaded before added to a belongs_to relationship. Probably you haven't saved it.");
+ }
+
+ $key = $rel['key'];
+ $this->$key = $model->_row[$this->id_field];
+ if ($this->loaded())
+ {
+ $this->save();
+ }
+ }
+ elseif (isset($rel['through']))
+ {
+
+ if (!$this->loaded())
+ {
+ throw new Exception("Model must be loaded before you try adding 'through' relationships to it. Probably you haven't saved it.");
+ }
+ if (!$model->loaded())
+ {
+ throw new Exception("Model must be loaded before added to a 'through' relationship. Probably you haven't saved it.");
+ }
+
+ $exists = DB::instance($this->connection)->build_query('count')
+ ->table($rel['through'])
+ ->where(array(
+ array($rel['key'], $this->_row[$this->id_field]),
+ array($rel['foreign_key'], $model->_row[$model->id_field])
+ ))
+ ->execute();
+ if (!$exists)
+ {
+ DB::instance($this->connection)->build_query('insert')
+ ->table($rel['through'])
+ ->data(array(
+ $rel['key'] => $this->_row[$this->id_field],
+ $rel['foreign_key'] => $model->_row[$model->id_field]
+ ))
+ ->execute();
+ }
+ }
+ else
+ {
+
+ if (!$this->loaded())
+ {
+ throw new Exception("Model must be loaded before you try adding 'has_many' relationships to it. Probably you haven't saved it.");
+ }
+
+ $key = $rel['key'];
+ $model->$key = $this->_row[$this->id_field];
+ if ($model->loaded())
+ {
+ $model->save();
+ }
+ }
+ $this->cached = array();
+ }
+
+ /**
+ * Removes a relationship between current item and the passed one
+ *
+ * @param string $relation Name of the relationship
+ * @param ORM $model ORM item to remove relationship with. Can be omitted for 'belongs_to' relationships
+ * @return void
+ * @access public
+ * @throws Exception Exception If realtionship is not defined
+ * @throws Exception Exception If current item is not in the database yet (isn't considered loaded())
+ * @throws Exception Exception If passed item is not in the database yet (isn't considered loaded())
+ */
+ public function remove($relation, $model = null)
+ {
+
+ if (!$this->loaded())
+ {
+ throw new Exception("Model must be loaded before you try removing relationships from it.");
+ }
+
+ $rels = array_merge($this->has_one, $this->has_many, $this->belongs_to);
+ $rel = Misc::arr($rels, $relation, false);
+ if (!$rel)
+ {
+ throw new Exception("Model doesn't have a '{$relation}' relation defined");
+ }
+
+ if ($rel['type'] != 'belongs_to' && (!$model || !$model->loaded()))
+ {
+ throw new Exception("Model must be loaded before being removed from a has_one or has_many relationship.");
+ }
+ if ($rel['type'] == 'belongs_to')
+ {
+ $key = $rel['key'];
+ $this->$key = null;
+ $this->save();
+ }
+ elseif (isset($rel['through']))
+ {
+ DB::instance($this->connection)->build_query('delete')
+ ->table($rel['through'])
+ ->where(array(
+ array($rel['key'], $this->_row[$this->id_field]),
+ array($rel['foreign_key'], $model->_row[$model->id_field])
+ ))
+ ->execute();
+ }
+ else
+ {
+ $key = $rel['key'];
+ $model->$key = null;
+ $model->save();
+ }
+ $this->cached = array();
+ }
+
+ /**
+ * Gets name column names of the table associated with the model.
+ *
+ * @return array Array of column names
+ * @access public
+ */
+ public function columns()
+ {
+ if (!isset(ORM::$_column_cache[$this->table]))
+ {
+ ORM::$_column_cache[$this->table] = DB::instance($this->connection)->list_columns($this->table);
+ }
+ return ORM::$_column_cache[$this->table];
+ }
+
+ /**
+ * Defines which relationships should be preloaded. You can only preload
+ * belongs_to and has_one relationships. You can use the dot notation to
+ * preload deep relationsips, e.g. 'tree.protector' will preload the tree
+ * that a fairy lives in and also preload the protector of that tree.
+ *
+ * @param string $relationsip,... List of relationships to preload
+ * @return ORM Returns itself
+ * @access public
+ */
+ public function with()
+ {
+ $this->_with = func_get_args();
+ return $this;
+ }
+
+ /**
+ * Deletes current item from the database
+ *
+ * @return void
+ * @access public
+ * @throws Exception If the item is not in the database, e.g. is not loaded()
+ */
+ public function delete()
+ {
+ if (!$this->loaded())
+ {
+ throw new Exception("Cannot delete an item that wasn't selected from database");
+ }
+ DB::instance($this->connection)->build_query('delete')
+ ->table($this->table)
+ ->where($this->id_field, $this->_row[$this->id_field])
+ ->execute();
+ $this->cached = array();
+ }
+
+ /**
+ * Deletes all items that meet set conditions. Use in the same way
+ * as you would a find_all() method.
+ *
+ * @return ORM Returns self
+ * @access public
+ */
+ public function delete_all()
+ {
+ $query = clone $this->query;
+ $query->type('delete');
+ $query->execute();
+ return $this;
+ }
+
+ /**
+ * Saves the item back to the database. If item is loaded() it will result
+ * in an update, otherwise a new row will be inserted
+ *
+ * @return ORM Returns self
+ * @access public
+ */
+ public function save()
+ {
+ if ($this->loaded())
+ {
+ $query = DB::instance($this->connection)->build_query('update')
+ ->table($this->table)
+ ->where($this->id_field, $this->_row[$this->id_field]);
+ }
+ else
+ {
+ $query = DB::instance($this->connection)->build_query('insert')
+ ->table($this->table);
+ }
+ $query->data($this->_row);
+ $query->execute();
+
+ if ($this->loaded())
+ {
+ $id = $this->_row[$this->id_field];
+ }
+ else
+ {
+ $id = DB::instance($this->connection)->get_insert_id();
+ }
+ $row = (array) DB::instance($this->connection)->build_query('select')
+ ->table($this->table)
+ ->where($this->id_field, $id)->execute()->current();
+ $this->values($row, true);
+ return $this;
+ }
+
+ /**
+ * Batch updates item columns using an associative array
+ *
+ * @param array $row Associative array of key => value pairs
+ * @param boolean $set_loaded Flag to consider the ORM item loaded. Useful if you selected
+ * the row from the database and want to wrap it in ORM
+ * @return ORM Returns self
+ * @access public
+ */
+ public function values($row, $set_loaded = false)
+ {
+ $this->_row = array_merge($this->_row, $row);
+ if ($set_loaded)
+ {
+ $this->_loaded = true;
+ }
+ $this->cached = array();
+ return $this;
+ }
+
+ /**
+ * Initializes ORM model by name, and optionally fetches an item by id
+ *
+ * @param string $name Model name
+ * @param mixed $id If set ORM will try to load the item with this id from the database
+ * @return ORM ORM model, either empty or preloaded
+ * @access public
+ * @static
+ */
+ public static function factory($name, $id = null)
+ {
+ $model = $name.'_Model';
+ $model = new $model;
+ if ($id != null)
+ {
+ $model = $model->where($model->id_field, $id)->find();
+ $model->values(array($model->id_field => $id));
+ }
+ return $model;
+ }
+
+ /**
+ * Gets plural form of a noun
+ *
+ * @param string $str Noun to get a plural form of
+ * @return string Plural form
+ * @access private
+ * @static
+ */
+ private static function plural($str)
+ {
+ $regexes = array(
+ '/^(.*?[sxz])$/i' => '\\1es',
+ '/^(.*?[^aeioudgkprt]h)$/i' => '\\1es',
+ '/^(.*?[^aeiou])y$/i' => '\\1ies',
+ );
+ foreach ($regexes as $key => $val)
+ {
+ $str = preg_replace($key, $val, $str, -1, $count);
+ if ($count)
+ {
+ return $str;
+ }
+ }
+ return $str.'s';
+ }
+
+ /**
+ * Gets singular form of a noun
+ *
+ * @param string $str Noun to get singular form of
+ * @return string Singular form of the noun
+ * @access private
+ * @static
+ */
+ private static function singular($str)
+ {
+ $regexes = array(
+ '/^(.*?us)$/i' => '\\1',
+ '/^(.*?[sxz])es$/i' => '\\1',
+ '/^(.*?[^aeioudgkprt]h)es$/i' => '\\1',
+ '/^(.*?[^aeiou])ies$/i' => '\\1y',
+ '/^(.*?)s$/' => '\\1',
+ );
+ foreach ($regexes as $key => $val)
+ {
+ $str = preg_replace($key, $val, $str, -1, $count);
+ if ($count)
+ {
+ return $str;
+ }
+ }
+ return $str;
+ }
+
} \ No newline at end of file
diff --git a/modules/orm/classes/orm/result.php b/modules/orm/classes/orm/result.php
index 47757cf..cb0754c 100644
--- a/modules/orm/classes/orm/result.php
+++ b/modules/orm/classes/orm/result.php
@@ -12,211 +12,211 @@
class Result_ORM implements Iterator
{
- /**
- * Name of the model that the rows belong to
- * @var string
- * @access private
- */
- private $_model;
-
- /**
- * Database result
- * @var Result_Database
- * @access private
- */
- private $_dbresult;
-
- /**
- * Rules for preloaded relationships
- * @var array
- * @access private
- */
- private $_with = array();
-
- /**
- * Initialized an Result_ORM with which model to use and which result to
- * iterate over
- *
- * @param string $model Model name
- * @param Result_Database $dbresult Database result
- * @param array $with Array of rules for preloaded relationships
- * @return void
- * @access public
- */
- public function __construct($model, $dbresult, $with = array())
- {
- $this->_model = $model;
- $this->_dbresult = $dbresult;
- foreach ($with as $path => $rel)
- {
- $this->_with[] = array(
- 'path' => explode('.', $path),
- 'path_count' => count(explode('.', $path)),
- 'model' => $rel['model'],
- 'columns' => $rel['model']->columns(),
- );
- }
- }
-
- /**
- * Rewinds database cursor to the first row
- *
- * @return void
- * @access public
- */
- function rewind()
- {
- $this->_dbresult->rewind();
- }
-
- /**
- * Gets an ORM Model of the current row
- *
- * @return ORM Model of the current row of the result set
- * @access public
- */
- function current()
- {
- $model = new $this->_model;
-
- if (!$this->_dbresult->valid())
- {
- return $model;
- }
-
- if (empty($this->_with))
- {
- return $model->values((array) $this->_dbresult->current(), true);
- }
-
- $data = (array) $this->_dbresult->current();
-
- $model_data = array();
- foreach ($model->columns() as $column)
- {
- $model_data[$column] = array_shift($data);
- }
- $model->values($model_data, true);
-
- foreach ($this->_with as $rel)
- {
- $rel_data = array();
- foreach ($rel['columns'] as $column)
- {
- $rel_data[$column] = array_shift($data);
- }
- $rel['model']->values($rel_data, true);
-
- $owner = $model;
- foreach ($rel['path'] as $key => $child)
- {
- if ($key == $rel['path_count'] - 1)
- {
- $owner->cached[$child] = $rel['model'];
- }
- else
- {
- $owner = $owner->cached[$child];
- }
- }
- }
-
- return $model;
- }
-
- /**
- * Gets current rows' index number
- *
- * @return int Row number
- * @access public
- */
- function key()
- {
- return $this->_dbresult->key();
- }
-
- /**
- * Iterates to the next row in the result
- *
- * @return void
- * @access public
- */
- function next()
- {
- $this->_dbresult->next();
- }
-
- /**
- * Checks if current row is valid.
- *
- * @return bool returns false if we reach the end of the result set.
- * @access public
- */
- function valid()
- {
- return $this->_dbresult->valid();
- }
-
- /**
- * Returns an array of all rows as ORM objects if $rows is False,
- * or just an array of result rows with each row being a standard object,
- * this can be useful for functions like json_encode.
- *
- * @param boolean $rows Whether to return just rows and not ORM objects
- * @return array Array of ORM objects or standard objects representing rows
- * @access public
- */
- public function as_array($rows = false)
- {
- if (!$rows)
- {
- $arr = array();
- foreach ($this as $row)
- $arr[] = $row;
- return $arr;
- }
-
- if (empty($this->_with))
- {
- return $this->_dbresult->as_array();
- }
-
- $arr = array();
- $model = new $this->_model;
- foreach ($this->_dbresult as $data)
- {
- $row = new stdClass;
- $data = (array) $data;
- foreach ($model->columns() as $column)
- {
- $row->$column = array_shift($data);
- }
-
- foreach ($this->_with as $rel)
- {
- $rel_data = new StdClass;
- foreach ($rel['columns'] as $column)
- {
- $rel_data->$column = array_shift($data);
- }
-
- $owner = &$row;
- foreach ($rel['path'] as $key => $child)
- {
- if ($key == $rel['path_count'] - 1)
- {
- $owner->$child = $rel_data;
- }
- else
- {
- $owner = &$owner->$child;
- }
- }
- }
- $arr[] = $row;
- }
-
- return $arr;
- }
+ /**
+ * Name of the model that the rows belong to
+ * @var string
+ * @access private
+ */
+ private $_model;
+
+ /**
+ * Database result
+ * @var Result_Database
+ * @access private
+ */
+ private $_dbresult;
+
+ /**
+ * Rules for preloaded relationships
+ * @var array
+ * @access private
+ */
+ private $_with = array();
+
+ /**
+ * Initialized an Result_ORM with which model to use and which result to
+ * iterate over
+ *
+ * @param string $model Model name
+ * @param Result_Database $dbresult Database result
+ * @param array $with Array of rules for preloaded relationships
+ * @return void
+ * @access public
+ */
+ public function __construct($model, $dbresult, $with = array())
+ {
+ $this->_model = $model;
+ $this->_dbresult = $dbresult;
+ foreach ($with as $path => $rel)
+ {
+ $this->_with[] = array(
+ 'path' => explode('.', $path),
+ 'path_count' => count(explode('.', $path)),
+ 'model' => $rel['model'],
+ 'columns' => $rel['model']->columns(),
+ );
+ }
+ }
+
+ /**
+ * Rewinds database cursor to the first row
+ *
+ * @return void
+ * @access public
+ */
+ function rewind()
+ {
+ $this->_dbresult->rewind();
+ }
+
+ /**
+ * Gets an ORM Model of the current row
+ *
+ * @return ORM Model of the current row of the result set
+ * @access public
+ */
+ function current()
+ {
+ $model = new $this->_model;
+
+ if (!$this->_dbresult->valid())
+ {
+ return $model;
+ }
+
+ if (empty($this->_with))
+ {
+ return $model->values((array) $this->_dbresult->current(), true);
+ }
+
+ $data = (array) $this->_dbresult->current();
+
+ $model_data = array();
+ foreach ($model->columns() as $column)
+ {
+ $model_data[$column] = array_shift($data);
+ }
+ $model->values($model_data, true);
+
+ foreach ($this->_with as $rel)
+ {
+ $rel_data = array();
+ foreach ($rel['columns'] as $column)
+ {
+ $rel_data[$column] = array_shift($data);
+ }
+ $rel['model']->values($rel_data, true);
+
+ $owner = $model;
+ foreach ($rel['path'] as $key => $child)
+ {
+ if ($key == $rel['path_count'] - 1)
+ {
+ $owner->cached[$child] = $rel['model'];
+ }
+ else
+ {
+ $owner = $owner->cached[$child];
+ }
+ }
+ }
+
+ return $model;
+ }
+
+ /**
+ * Gets current rows' index number
+ *
+ * @return int Row number
+ * @access public
+ */
+ function key()
+ {
+ return $this->_dbresult->key();
+ }
+
+ /**
+ * Iterates to the next row in the result
+ *
+ * @return void
+ * @access public
+ */
+ function next()
+ {
+ $this->_dbresult->next();
+ }
+
+ /**
+ * Checks if current row is valid.
+ *
+ * @return bool returns false if we reach the end of the result set.
+ * @access public
+ */
+ function valid()
+ {
+ return $this->_dbresult->valid();
+ }
+
+ /**
+ * Returns an array of all rows as ORM objects if $rows is False,
+ * or just an array of result rows with each row being a standard object,
+ * this can be useful for functions like json_encode.
+ *
+ * @param boolean $rows Whether to return just rows and not ORM objects
+ * @return array Array of ORM objects or standard objects representing rows
+ * @access public
+ */
+ public function as_array($rows = false)
+ {
+ if (!$rows)
+ {
+ $arr = array();
+ foreach ($this as $row)
+ $arr[] = $row;
+ return $arr;
+ }
+
+ if (empty($this->_with))
+ {
+ return $this->_dbresult->as_array();
+ }
+
+ $arr = array();
+ $model = new $this->_model;
+ foreach ($this->_dbresult as $data)
+ {
+ $row = new stdClass;
+ $data = (array) $data;
+ foreach ($model->columns() as $column)
+ {
+ $row->$column = array_shift($data);
+ }
+
+ foreach ($this->_with as $rel)
+ {
+ $rel_data = new StdClass;
+ foreach ($rel['columns'] as $column)
+ {
+ $rel_data->$column = array_shift($data);
+ }
+
+ $owner = &$row;
+ foreach ($rel['path'] as $key => $child)
+ {
+ if ($key == $rel['path_count'] - 1)
+ {
+ $owner->$child = $rel_data;
+ }
+ else
+ {
+ $owner = &$owner->$child;
+ }
+ }
+ }
+ $arr[] = $row;
+ }
+
+ return $arr;
+ }
} \ No newline at end of file