diff options
Diffstat (limited to 'modules/database')
-rw-r--r-- | modules/database/classes/database/expression.php | 31 | ||||
-rw-r--r-- | modules/database/classes/database/query.php | 380 | ||||
-rw-r--r-- | modules/database/classes/database/result.php | 74 | ||||
-rw-r--r-- | modules/database/classes/db.php | 127 | ||||
-rw-r--r-- | modules/database/classes/driver/mysql/db.php | 88 | ||||
-rw-r--r-- | modules/database/classes/driver/mysql/query.php | 199 | ||||
-rw-r--r-- | modules/database/classes/driver/mysql/result.php | 47 | ||||
-rw-r--r-- | modules/database/classes/driver/pdo/db.php | 70 | ||||
-rw-r--r-- | modules/database/classes/driver/pdo/query.php | 8 | ||||
-rw-r--r-- | modules/database/classes/driver/pdo/result.php | 47 |
10 files changed, 1071 insertions, 0 deletions
diff --git a/modules/database/classes/database/expression.php b/modules/database/classes/database/expression.php new file mode 100644 index 0000000..03cfd99 --- /dev/null +++ b/modules/database/classes/database/expression.php @@ -0,0 +1,31 @@ +<?php + +/** + * This class allows you to wrap fields or values that you don't want to be escaped + * inside the query + */ +class Expression_Database{ + + /** + * Part of query that shoud 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 shoud not be escaped + * @return Expression_Database + * @access public + */ + public function __construct($value){ + $this->value=$value; + } +}
\ No newline at end of file diff --git a/modules/database/classes/database/query.php b/modules/database/classes/database/query.php new file mode 100644 index 0000000..ec36b9e --- /dev/null +++ b/modules/database/classes/database/query.php @@ -0,0 +1,380 @@ +<?php + +/** + * Query builder. It allows building queries by using methods to set specific query parameters. + * 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. + * Without arguments returns current table, returns self otherwise. + * + * @method mixed data(array $data = null) Set data for insert or update queries. + * Without arguments returns current data, returns self otherwise. + * + * @method mixed limit(int $limit = null) Set number of rows to return. + * Without arguments returns current limit, returns self otherwise. + * + * @method mixed offset(string $offset = null) Set the offset for the first row in result. + * Without arguments returns current offset, returns self otherwise. + * + * @method mixed groupby(string $groupby = null) A column to group rows by for aggregator functions. + * Without arguments returns current groupby argument, returns self otherwise. + * + * @method mixed type(string $type = null) Set query type. Available types: select, update, insert, delete, count. + * Without arguments returns current type argument, returns self otherwise. + */ +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 $_groupby; + + /** + * 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('table' => 'string','data' => 'array','limit' => 'integer','offset' => 'integer','groupby' => 'string','type' => 'string'); + + /** + * Generates a query in format tht 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 + * + * @param mixed A single field or an array of them + * @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; + }elseif (is_array($p[0])) { + $this->_fields=$p[0]; + }else { + $this->_fields=array($p[0]); + } + 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_int($val)) + $val=(int) $val; + if (gettype($val) != $this->methods[$method]) + throw new Exception("Method '{$method}' only accepts values of type: '{$this->methods[$method]}', '{$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->current()->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 aggregator 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,$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 orderby($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,$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->lastAlias().'.'.$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 lastAlias() { + if ($this->alias === null) + return $this->_table; + return 'a'.$this->alias; + } + + /** + * Generates new alias. Useful for programmatically adding aliases to joins. + * Alias is just a letter 'a' with an incremeted number. + * + * @return string New alias + * @access public + */ + public function addAlias() { + if ($this->alias === null){ + $this->alias = 0; + }else { + $this->alias++; + } + return $this->lastAlias(); + } + + + + + + +}
\ No newline at end of file diff --git a/modules/database/classes/database/result.php b/modules/database/classes/database/result.php new file mode 100644 index 0000000..ba83f25 --- /dev/null +++ b/modules/database/classes/database/result.php @@ -0,0 +1,74 @@ +<?php + +/** + * Allows to access database results in a unified way and + * provides iterator support, so it can be used inside loops like 'foreach' + */ +abstract class Result_Database implements Iterator { + + /** + * Current row number + * @var integer + * @access protected + */ + protected $_position = 0; + + /** + * Database result object + * @var mixed + * @access protected + */ + protected $_result; + + /** + * Current row + * @var object + * @access protected + */ + protected $_row; + + + /** + * Returns current row + * + * @return object Current row in result set + * @access public + */ + public function current() { + return $this->_row; + } + + /** + * Gets the number of the current row + * + * @return integer Row number + * @access public + */ + public function key() { + return $this->_position; + } + + /** + * Check if current row exists. + * + * @return bool True if row exists + * @access public + */ + public function valid() { + 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; + } + +}
\ No newline at end of file diff --git a/modules/database/classes/db.php b/modules/database/classes/db.php new file mode 100644 index 0000000..acbec0f --- /dev/null +++ b/modules/database/classes/db.php @@ -0,0 +1,127 @@ +<?php + +/** + * Daatabase related functions. Creates connections, + * executes queries and returns results. It is also the + * generic connectionc class used by drivers. + */ +abstract class DB { + + /** + * 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()); + + /** + * 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(); + + /** + * Executes a named query where parameters are passed as an associative array + * Example: + * Query: SELECT * FROM fairies where name = :name + * Params: array('name'=>'Tinkerbell'); + * + * @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 namedQuery($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); + } + + /** + * 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 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]; + } + +}
\ No newline at end of file diff --git a/modules/database/classes/driver/mysql/db.php b/modules/database/classes/driver/mysql/db.php new file mode 100644 index 0000000..553cfb9 --- /dev/null +++ b/modules/database/classes/driver/mysql/db.php @@ -0,0 +1,88 @@ +<?php + +/** + * Mysqli Database Implementation + */ +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; + + /** + * 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") + ); + } + + /** + * 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; + } + + /** + * 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(); + if (is_object($res)){ + $res=new Result_Mysql_Driver($res); + } + return $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 new file mode 100644 index 0000000..9f38cc5 --- /dev/null +++ b/modules/database/classes/driver/mysql/query.php @@ -0,0 +1,199 @@ +<?php + +/** + * Mysqli implementation of the database Query + */ +class Query_Mysql_Driver extends Query_Database{ + + /** + * If a string is passed escapes a field by enclosing it in `` quotes. + * If you pass an Expression_Database object the value will be inserted into the query uneascaped + * + * @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->lastAlias()); + $str = '`'.$field[0].'`.'; + if (trim($field[1]) == '*') + return $str.'* '; + return $str."`{$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 uneascaped + * @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 (is_object($val) && get_class($val) == 'Expression_Database') + return $val->value.' '; + $params[] = $val; + return '? '; + } + + /** + * 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->_table}`"; + $columns = ''; + $values = ''; + $first = true; + foreach($this->_data as $key => $val) { + if (!$first) { + $values.= ','; + $columns.= ','; + }else { + $first=false; + } + $columns.= "`{$key}` "; + $values.=$this->escape_value($val,$params); + } + $query.= "({$columns}) VALUES({$values})"; + }else{ + if ($this->_type == 'select'){ + $query.= "SELECT "; + if($this->_fields==null){ + $query.= "* "; + }else{ + $first = true; + foreach($this->_fields as $f) { + if (!$first) { + $query.=", "; + }else { + $first = false; + } + $query.="{$this->escape_field($f)} "; + } + } + $query.= "FROM `{$this->_table}` "; + } + if ($this->_type == 'count') { + $query.= "SELECT COUNT(*) as `count` FROM `{$this->_table}` "; + } + if($this->_type=='delete') + $query.= "DELETE FROM `{$this->_table}` "; + if($this->_type=='update'){ + $query.= "UPDATE `{$this->_table}` SET "; + $first = true; + foreach($this->_data as $key=>$val){ + if (!$first) { + $query.=','; + }else { + $first=false; + } + $query.= "`{$key}`=".$this->escape_value($val,$params); + } + } + + foreach($this->_joins as $join) { + $table = $join[0]; + if (is_array($table)){ + $table = "`{$table[0]}` as `{$table[1]}`"; + }else { + $table="`{$table}`"; + } + $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); + } + if (($this->_type == 'select' || $this->_type == 'count') && $this->_groupby!=null) { + $query.="GROUP BY ".$this->escape_field($this->_groupby); + } + 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 { + $first=false; + } + $query.= $this->escape_field($order[0]); + if (isset($order[1])) { + $dir = strtoupper($order[1]); + $query.=$dir." "; + } + } + } + if($this->_type != 'count'){ + if ($this->_limit != null) + $query.= "LIMIT {$this->_limit} "; + if ($this->_offset != null) + $query.= "OFFSET {$this->_offset} "; + } + + } + + return array($query,$params); + } + + /** + * Recursively parses conditions array into a query string + * + * @param array $p Element of the array of conditions + * @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 { + $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); + } + + $conds = ''; + $skip=$skip_first_operator||(count($p) > 1); + 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/mysql/result.php b/modules/database/classes/driver/mysql/result.php new file mode 100644 index 0000000..0fbb645 --- /dev/null +++ b/modules/database/classes/driver/mysql/result.php @@ -0,0 +1,47 @@ +<?php + +/** + * Database result implementation for Mysqli + */ +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; + $this->_row=$this->_result->fetch_object(); + } + + /** + * 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->_position++; + $this->_row=$this->_result->fetch_object(); + if ($this->_row == null) + $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 new file mode 100644 index 0000000..89c7165 --- /dev/null +++ b/modules/database/classes/driver/pdo/db.php @@ -0,0 +1,70 @@ +<?php + +/** + * PDO Database implementation. + */ +class DB_PDO_Driver extends DB{ + + /** + * Connection object + * @var PDO + * @access public + * @link http://php.net/manual/en/class.pdo.php + */ + public $conn; + + /** + * 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",'') + ); + } + + /** + * 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() { + return $this->conn->lastInsertId(); + } + + /** + * 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)) + throw new Exception("Database error: ".implode(' ',$this->conn->errorInfo())." \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 new file mode 100644 index 0000000..4a3d7c2 --- /dev/null +++ b/modules/database/classes/driver/pdo/query.php @@ -0,0 +1,8 @@ +<?php + +/** + * PDO Database Query implementation. Mimics Mysql implementation. + */ +class Query_PDO_Driver extends Query_Mysql_Driver{ + +}
\ No newline at end of file diff --git a/modules/database/classes/driver/pdo/result.php b/modules/database/classes/driver/pdo/result.php new file mode 100644 index 0000000..3270231 --- /dev/null +++ b/modules/database/classes/driver/pdo/result.php @@ -0,0 +1,47 @@ +<?php + +/** + * Database result implementation for PDO + */ +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; + $this->_row=$this->_result->fetchObject(); + } + + /** + * 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->_position++; + $this->_row=$this->_result->fetchObject(); + if ($this->_row == false) + $this->_result->closeCursor(); + } + +}
\ No newline at end of file |