Skip to content

Instantly share code, notes, and snippets.

@kenaniah
Created April 17, 2012 23:37
Show Gist options
  • Save kenaniah/2409921 to your computer and use it in GitHub Desktop.
Save kenaniah/2409921 to your computer and use it in GitHub Desktop.
Example PDO Database Extension
<?php
/**
* Database abstraction and query result classes (requires PHP 5.3)
*
* This class is built primarily for PostgreSQL 8.4+
* Compatibility with other database types is not guaranteed
*
* @author Kenaniah Cerny <kenaniah@gmail.com>
* @version 1.2.0
* @license http://creativecommons.org/licenses/by-sa/3.0/
* @copyright Copyright (c) 2009, Kenaniah Cerny
* @requires Cache
* @requires Registry
*/
class Database extends \PDO {
/**
* Whether or not statement-level debugging is enabled on this connection
* @var boolean
*/
public $debug = false;
/**
* What level should errors be thrown
* @var integer
*/
protected $error_level = E_USER_WARNING;
/**
* Name of the relation in which files may be stored
* Example PostgreSQL schema:
*
* CREATE TABLE public.files (
* id SERIAL PRIMARY KEY,
* name TEXT NOT NULL,
* mime TEXT NOT NULL,
* file BYTEA NOT NULL,
* );
*
* @var string
*/
protected $files_table = "files";
/**
* Sets the default fetch mode for queries
* @var integer
*/
protected $default_fetch_mode = PDO::FETCH_ASSOC;
/**
* Array that tracks database connection instances
* @internal
* @var array (keys: name of instance, values: database connection)
*/
private static $connections = array();
/**
* Internal array that stores connection configuration information
* Format:
* array(
* 'connection1' => array(
* 'driver' => 'pgsql'
* 'host' => 'localhost' //Optional. Attempts to use the UDS when absent
* 'user' => 'username'
* 'pass' => 'password'
* 'db' => 'db_name',
* 'cache' => new Cache //Optional. Accepts an instance of the Cache class
* ),
* 'connection2' => ...
* )
* @see $this->setConfig()
* @var array
*/
private static $config = array();
/**
* Holds the resulting instance of DatabaseStatement
* @var DatabaseStatement
*/
private $stmt;
/**
* Tracks whether or not an open database transaction is still in good standing
* @var boolean
*/
private $good_trans = null;
/**
* Tracks the virtual transaction nesting level
* @var integer
*/
private $nested_transactions = 0;
/**
* Tracks the original error returned by the database driver in a transaction
* @var PDOException
*/
private $transaction_error = null;
/**
* Tracks the name of this database connection
* @see self::getInstance()
* @var string
*/
private $instance_name = null;
/**
* Determines whether or not errors are thrown immediately in a transaction
* When true, errors are thrown as soon as they are encountered
* When false, errors are suppressed until the end of the transaction
* @see $this->commit()
* @see $this->completeTrans()
*/
private $throw_errors = false;
/**
* Instance of the cache implementation for this connection
* If not provided, caching is disabled
* @var Cache
*/
private $cache = null;
/**
* Tracks the number of queries processed by this connection
* @var integer
*/
protected $num_queries = 0;
/**
* Tracks the total number of queries processed by all connections
* @var integer
*/
protected static $total_queries = 0;
/**
* Tracks the query execution time for this connection
* @var float
*/
protected $time = 0;
/**
* Tracks the total execution time accross all connections
* @var float
*/
protected static $total_time = 0;
/**
* Human-readable connection details
* @var string
*/
protected $string = "";
/**
* Controlls whether or not the metadata schema should be used
* @var boolean
*/
protected $use_meta_schema = false;
/**
* Tracks the type of server we are connected to
* @var string
*/
protected $server_type;
/**
* Tracks the server's version number
* @var string
*/
protected $server_version;
/**
* Sets the connection configuration array. This must be set before using getInstance()
* @param array $config
* @see self::$config
*/
static function setConfig(array $config){
self::$config = $config;
}
/**
* PDO Constructor
* @param $dsn
* @param $username
* @param $password
* @param array $params Connection parameters
* @param Cache $cache The caching instance to use for this connection
*/
function __construct($dsn, $username, $password, $params = array(), Cache $cache = null) {
//Supply any additional connection parameters
switch(substr($dsn, 0, 5)):
case 'mysql':
$params[PDO::MYSQL_ATTR_FOUND_ROWS] = true;
break;
endswitch;
//Initialize the connection
parent::__construct($dsn, $username, $password, $params);
//Grab server information
$this->server_type = $this->getAttribute(PDO::ATTR_DRIVER_NAME);
$this->server_version = $this->getAttribute(PDO::ATTR_SERVER_VERSION);
$this->string = "Connected to " . $username . "@" . $dsn . ". Server version " . $this->server_version;
//Change the error mode to always throw exceptions
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//Use legacy bytea_output format if running PostgreSQL 9.0 or higher
if($this->server_type == 'pgsql' && version_compare($this->server_version, '9.0', '>=')):
$this->execute("SET bytea_output = escape");
endif;
//Set the cache
$this->cache = $cache ?: with(Registry::get('injector'))->cache;
}
/**
* Returns a database instance using lazy instantiation
* @param string $name a database connection name (to be read from config)
*/
static function getInstance($name = 'main'){
//Attempt to return an existing connection
if(array_key_exists($name, self::$connections)):
return self::$connections[$name];
endif;
//Attempt to create a new connection
$config = Registry::get('config');
if(!array_key_exists($name, self::$config)):
user_error("No configuration found for connection: " . $name);
endif;
//Grab the connection information
$conn = self::$config[$name];
//Check if host is defined (otherwise use the Unix Domain Socket)
$host = "";
if(isset($conn['host']) && $conn['host']):
$host = ";host=" . $conn['host'];
endif;
if(isset($conn['port']) && $conn['port']):
$host.= ";port=" . $conn['port'];
endif;
//Instantiate this connection
$db = new Database($conn['driver'].":dbname=".$conn['name'].$host, $conn['user'], $conn['pass']);
$db->instance_name = $name;
$db->use_meta_schema = !empty($conn['use_meta_schema']);
//Save to the connection pool
self::$connections[$name] = $db;
//Return the Database instance
return $db;
}
/**
* Returns the name of this database connection instance
*/
public function getInstanceName(){
return $this->instance_name;
}
/**
* Returns whether or not this connection uses a meta schema
*/
public function usesMetaSchema(){
return $this->use_meta_schema;
}
/**
* Sets the cache instance to be used by getCached
* @see $this->getCached()
*/
public function setCacheInstance(Cache $cache){
$this->cache = $cache;
}
/**
* Returns the cache instance
*/
public function getCacheInstance(){
return $this->cache;
}
/**
* Prepares an SQL statement
* @param string $sql
* @see PDO::prepare()
*/
function prepare($sql) {
$stmt = parent::prepare($sql, array(
PDO::ATTR_STATEMENT_CLASS => array(__NAMESPACE__.'\DatabaseStatement'),
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);
if(!$stmt):
//Output the statement and the error message if debugging is enabled
if($this->debug):
var_dump("Statement: \n" . str_replace("\r", "", $sql));
endif;
//If the statement failed to compile, log it in the PHP error log
user_error("Failed to compile database statement - " . $this->errormsg(), $this->error_level);
else:
//Set the default fetch mode for this statement
$stmt->setFetchMode($this->default_fetch_mode);
endif;
//Return the statement (or false if not compiled)
return $stmt;
}
/**
* Prepares and executes an SQL statement with the parameters provided
* @param string $sql
* @param array $params
*/
function execute($sql, $params = array()) {
//Track the number of queries attempted
$this->num_queries++;
self::$total_queries++;
$debug = "";
//Output the statement and any parameters if debugging is enabled
if($this->debug):
$debug .= "Statement:\n".str_replace("\r", "", $sql)."\nParams: ".$this->fmt((array) $params);
endif;
//Attempt to execute the statement
try {
$t1 = microtime(true);
$stmt = $this->prepare($sql);
$val = $stmt->execute((array) $params);
$t = microtime(true) - $t1;
$this->time += $t;
self::$total_time += $t;
if($this->debug):
$debug .= "\nExecution: " . number_format($t * 1000, 2) . "ms";
$debug .= "\nError: " . $stmt->errormsg();
var_dump($debug);
endif;
//Did we receive an error from the database?
if($stmt->errorCode() != '00000'):
//If the statement failed to compile, log it in the PHP error log
user_error("Failed to execute database statement with error code [".$stmt->errorCode()."] - " . $stmt->errormsg(), $this->error_level);
endif;
if(!$val) return false;
} catch (PDOException $e){
$t = microtime(true) - $t1;
$this->time += $t;
self::$total_time += $t;
if($this->debug):
$debug .= "\nExecution: " . number_format($t * 1000, 2) . "ms";
$debug .= "\nError: " . $stmt->errormsg();
var_dump($debug);
endif;
//If inside a transaction, record the error and mark the transaction as failed
//The error will be thrown if requested
if($this->nested_transactions){
user_error("Failed to execute database statement - " . $e->getMessage(), $this->error_level);
if(!$this->transaction_error) $this->transaction_error = $e;
$this->failTrans();
}
else throw $e;
//Throw the error if requested (and not thrown yet)
if($this->throw_errors) throw $e;
}
//Cache the DatabaseStatement internally
$this->stmt = $stmt;
//Return the DatabaseStatement
return $stmt;
}
/**
* Saves a file to the database and returns the file id
* @param array $file An uploaded file reference (compatible with $_FILES['<filename>'])
* @param string $files_table The qualified name of the files table. Defaults to $this->files_table.
*/
function saveFile($file, $files_table = null){
$sql = "INSERT INTO ".($files_table ?: $this->files_table)." (name, mime, file)
VALUES (?, ?, ?)
RETURNING id";
$stmt = $this->prepare($sql);
$stmt->bindParam(1, $file['name'], PDO::PARAM_STR);
$stmt->bindParam(2, $file['type'], PDO::PARAM_STR);
$stmt->bindParam(3, fopen($file['tmp_name'], 'rb'), PDO::PARAM_LOB);
$stmt->execute();
return $stmt->fetch(PDO::FETCH_COLUMN);
}
/**
* Enables / disables statement debugging for this instance
* @param $boolean Whether or not to output debugging information
*/
function debug($boolean){
$this->debug = (bool) $boolean;
return $this;
}
/**
* Enables / disables throwing errors when they are encountered
* @param boolean $boolean Whether or not to throw exceptions on errors
*/
function throwErrors($boolean){
$this->throw_errors = (bool) $boolean;
}
/**
* Caches the full output of a query by serializing the query and its params
* Should only be used with SELECT queries on small, generally static, datasets.
* @param $sql
* @param $params
* @param $expiry Number of seconds before cache expires
* @param $mode Optional mode for which to run the query
*/
function getCached($sql, $params = array(), $expiry = null, $mode = 'getAll'){
//Define the cache key
$cache_name = "sql-" . md5($sql . serialize((array) $params));
//Define the cache
$db = $this;
$this->cache->set(
$cache_name,
function() use ($db, $mode, $sql, $params){
return $db->$mode($sql, $params);
},
$expiry
);
//Return the value
return $this->cache->$cache_name;
}
/**
* Returns the value of the first column of the first row
* of the database result.
* @param $sql
* @param $params
*/
function getOne($sql, $params = array()){
$stmt = $this->execute($sql, $params);
return $stmt ? $stmt->getOne() : false;
}
/**
* Fetches a single column (the first column) of a result set
* @param $sql
* @param $params
*/
function getCol($sql, $params = array()){
$stmt = $this->execute($sql, $params);
return $stmt ? $stmt->getCol() : false;
}
/**
* Fetches rows in associative array format
* @param $sql
* @param $params
*/
function getAssoc($sql, $params = array()){
$stmt = $this->execute($sql, $params);
return $stmt ? $stmt->getAssoc() : false;
}
/**
* Fetches rows in array format with columns
* indexed by ordinal position
* @param $sql
* @param $params
*/
function getArray($sql, $params = array()){
$stmt = $this->execute($sql, $params);
return $stmt ? $stmt->getArray() : false;
}
/**
* Fetches all rows in associative array format
* @param $sql
* @param $params
*/
function getAll($sql, $params = array()){
return $this->getAssoc($sql, $params);
}
/**
* Fetches rows in array format where the first column
* is the key name and all other columns are values
* @param $sql
* @param $params
*/
function getKeyPair($sql, $params = array()){
$stmt = $this->execute($sql, $params);
return $stmt ? $stmt->getKeyPair() : false;
}
/**
* Fetches rows in multi-dimensional format where the first
* column is the key name and all other colums are grouped
* into associative arrays for each row
* @param $sql
* @param $params
*/
function getGroup($sql, $params = array()){
$stmt = $this->execute($sql, $params);
return $stmt ? $stmt->getGroup() : false;
}
/**
* Fetches only the first row and returns it as an
* associative array
* @param $sql
* @param $params
*/
function getRow($sql, $params = array()){
$stmt = $this->execute($sql, $params);
return $stmt ? $stmt->getRow() : false;
}
/**
* Internal function used for formatting parameters in debug output
* @param array $params
*/
private function fmt(array $params){
$arr = array();
foreach((array) $params as $k=>$v){
if(is_null($v)) $v = "NULL";
elseif(is_bool($v)) $v = $v ? "TRUE" : "FALSE";
$arr[] = "[".$k."] => ".$v;
}
return "Array(\n\t".join("\n\t", $arr)."\n)";
}
/**
* Returns the number of affected rows from an executed statement
*/
function affectedRows(){
return $this->stmt ? $this->stmt->rowcount() : false;
}
/**
* Automated statement processing
*
* @param string $table The table name to operate on
* @param array $params See below:
* Params array takes the following fields:
*
* - mode INSERT, UPDATE, REPLACE (Update or Insert), or NEW (Insert if not exists)
*
* - where Can be a string or key-value set. Not used on INSERTs
* If key-value set and numerically indexed, uses values from data
* If key-value and keys are named, uses its own values
*
* - params An array of param values for the where clause
*
* - returning Optional string defining what to return from query.
* Uses PostgreSQL's RETURNING construct
* - return_mode Mode by which to return values from the query (getOne, getAll, getCol, etc.)
*
* This method will return either a boolean indicating success, an array
* containing the data requested by returning, or a boolean FALSE indicating
* a failed query.
*
* @param array $data The data (row) to be sent to the table
*/
function autoExecute($table, $params, $data = array()){
$fields = array(); //Temp array for field names
$values = array(); //Temp array for field values
$set = array(); //Temp array for update sets
$ins = array(); //Insert value arguments
$params['table'] = $table;
$params['data'] = $data;
$params['mode'] = isset($params['mode']) ? $params['mode'] : null;
$params['where'] = isset($params['where']) ? $params['where'] : null;
$params['params'] = isset($params['params']) ? (array) $params['params'] : array();
$params['returning'] = isset($params['returning']) ? $params['returning'] : null;
$params['return_mode'] = isset($params['return_mode']) ? $params['return_mode'] : 'getRow';
//MySQL driver does not allow anything but execute() to be called on prepared statements
if($this->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql'):
$params['return_mode'] = 'execute';
endif;
//Parse the data set and prepare it for different query types
foreach((array) $params['data'] as $field => $val):
$fields[] = $field;
$values[] = $val;
$ins[] = "?";
$set[] = $field . " = ?";
endforeach;
//Check for and convert the array/object version of the where clause param
if(is_object($params['where']) || is_array($params['where'])):
$clause = array();
$params['params'] = array(); //Reset the parameters list
foreach($params['where'] as $key => $val):
if(is_numeric($key)):
//Numerically indexed elements use their values as field names
//and values from the data array as param values
$field = $val;
$params['params'][] = $params['data'][$val];
else:
//Named elements use their own names and values
$field = $key;
$params['params'][] = $val;
endif;
$clause[] = $field . " = ?";
endforeach;
$params['where'] = join(" AND ", $clause);
endif;
//Figure out what type of query we want to run
$mode = strtoupper($params['mode']);
switch($mode):
case 'NEW':
case 'INSERT':
//Build the insert query
if(count($fields)):
$sql = "INSERT INTO\n\t" . $params['table']
. "\n(\n\t" . join(",\n\t", $fields) . "\n)"
. "\nSELECT\n\t" . join(",\n\t", $ins);
else:
$sql = "INSERT INTO " . $params['table']
. " DEFAULT VALUES";
endif;
//Do we need to add a conditional check?
if($mode == "NEW" && count($fields)):
$sql .= "\nWHERE NOT EXISTS ("
. "\n\tSELECT 1 FROM " . $params['table']
. "\n\tWHERE " . $params['where']
. "\n)";
//Add in where clause params
$values = array_merge($values, $params['params']);
endif;
//Do we need to add a returning clause?
if(isset($params['returning']) && $params['returning']):
$sql .= "\nRETURNING\n\t" . $params['returning'];
endif;
$result = $this->$params['return_mode']($sql, $values);
//Return our result
if($params['returning']):
return $result;
else:
return $result !== false;
endif;
break;
case 'UPDATE':
if(!count($fields)) return false;
//Build the update query
$sql = "UPDATE\n\t" . $params['table']
. "\nSET\n\t" . join(",\n\t", $set)
. "\nWHERE\n\t" . $params['where'];
//Do we need to add a returning clause?
if(isset($params['returning']) && $params['returning']):
$sql .= "\nRETURNING\n\t" . $params['returning'];
endif;
//Add in where clause params
$values = array_merge($values, $params['params']);
$result = $this->$params['return_mode']($sql, $values);
//Return our result
if($params['returning']):
return $result;
else:
return $result !== false;
endif;
break;
case 'REPLACE': //UPDATE or INSERT
//Attempt an UPDATE
$params['mode'] = "UPDATE";
$result = $this->autoExecute($params['table'], $params, $params['data']);
//Attempt an INSERT if UPDATE didn't match anything
if($this->affectedRows() === 0):
$params['mode'] = "INSERT";
$result = $this->autoExecute($params['table'], $params, $params['data']);
endif;
return $result;
break;
case 'DELETE':
//Don't run if we don't have a where clause
if(!$params['where']) return false;
//Build the delete query
$sql = "DELETE FROM\n\t" . $params['table']
. "\nWHERE\n\t" . $params['where'];
//Do we need to add a returning clause?
if($params['returning']):
$sql .= "\nRETURNING\n\t" . $params['returning'];
endif;
$result = $this->$params['return_mode']($sql, $params['params']);
//Return our result
if($params['returning']):
return $result;
else:
return $result !== false;
endif;
break;
default:
user_error('AutoExecute called incorrectly', E_USER_ERROR);
break;
endswitch;
}
/**
* @see $this->startTrans()
* @see PDO::beginTransaction()
*/
function beginTransaction(){
$this->startTrans();
}
/**
* Starts a smart transaction handler. Transaction nesting is emulated
* by this class.
*/
function startTrans(){
//Increment the virtual nested transaction level
$this->nested_transactions++;
if($this->debug):
var_dump("Starting transaction. Nesting level: " . $this->nested_transactions);
endif;
//Do we need to begin an actual transaction?
if($this->nested_transactions === 1):
parent::beginTransaction();
$this->good_trans = true;
endif;
}
/**
* Returns TRUE if the transaction will attempt to commit, and
* FALSE if the transaction will be rolled back upon completion.
*/
function isGoodTrans(){
return $this->good_trans;
}
/**
* Marks a transaction as failed. Transaction will be rolled back
* upon completion.
*/
function failTrans(){
if($this->nested_transactions) $this->good_trans = false;
}
/**
* @see $this->rollbackTrans()
*/
function rollback(){
$this->rollbackTrans();
}
/**
* Rolls back the entire transaction and completes the current nested
* transaction. If there are no more nested transactions, an actual
* rollback is issued to the database.
*/
function rollbackTrans(){
//Check to make sure we actually have a transaction open
if($this->nested_transactions):
$this->nested_transactions--;
if($this->debug):
var_dump("Rollback requested. New nesting level: " . $this->nested_transactions);
endif;
//Mark the transaction as failed
$this->good_trans = false;
//If this was the last transaction, issue the rollback
if($this->nested_transactions === 0):
$this->good_trans = null;
parent::rollback();
if($this->debug):
var_dump("Transaction rolled back.");
endif;
$this->transaction_error = null;
endif;
endif;
}
/**
* Clears the nested transactions stack and issues a rollback to the database.
*/
function fullRollback(){
while($this->nested_transactions) $this->rollbackTrans();
}
/**
* Returns the number of nested transactions:
* 0 - There is no transaction in progress
* 1 - There is one transaction pending
* >1 - There are nested (virtual) transactions in progress
*/
function getTransactionLevel(){
return $this->nested_transactions;
}
/**
* Commits the transaction or throws the last exception on failure
*/
function commit(){
$error = $this->transaction_error;
$ok = $this->completeTrans();
if(!$ok && $this->transaction_error) throw $error;
return true;
}
/**
* Completes the current transaction
* Issues a commit or rollback to the database on the last transaction
* @param string $message A message to attach to the session upon success
* @return boolean indicating success
*/
function completeTrans($message = "Your changes have been saved successfully."){
//Ensure that we have at least one transaction pending
if(!$this->nested_transactions) return;
//Do we actually need to attempt to commit the transaction?
if($this->nested_transactions === 1):
//Check if transaction was marked for failure or attempt to commit it
if(Notifications::errorsExist() || !$this->good_trans || !parent::commit()):
//Add a global error to the session space
if($this->errormsg()):
Notifications::addError("Could not save to database: " . $this->errormsg());
endif;
if($this->debug):
var_dump("Transaction failed: " . $this->errormsg());
endif;
//Roll back the failed transaction
$this->rollbackTrans();
return false;
endif;
//Transaction was committed successfully
$this->nested_transactions--;
$this->good_trans = null;
//Add a success message
Notifications::addSuccess($message);
if($this->debug):
var_dump("Transaction committed.");
endif;
return true;
else:
//Don't take action just yet as we are still nested
$this->nested_transactions--;
if($this->debug):
var_dump("Virtual commit. New nesting level: " . $this->nested_transactions);
endif;
endif;
//Return the pending transaction status
return $this->good_trans;
}
/**
* Returns the text of the most recently encountered error
*/
function errormsg(){
//If an error for the transaction is defined, return that
if($this->transaction_error):
return $this->transaction_error->getMessage();
endif;
//Return the error message from the driver
$msg = $this->errorInfo();
return $msg[2];
}
/**
* Returns the number of queries processed by this connection
*/
function getNumQueries(){
return $this->num_queries;
}
/**
* Returns the total number of queries processed by all connections
*/
static function getTotalQueries(){
return self::$total_queries;
}
/**
* Returns the total execution time in microseconds
*/
static function getTotalTime(){
return self::$total_time;
}
/**
* Outputs basic connection details
*/
function __toString(){
return self::getInstanceName() . ": " . $this->string;
}
/**
* Helper method that helps clean up 1:n relationships
* @param string $table
* @param string $where
* @param mixed $where_params
* @param array $keep_ids
*/
function removeOldRecords($table, $where, $where_params, array $keep_ids){
$delete_sql = "DELETE FROM " . $table . " WHERE " . $where;
if($keep_ids) $delete_sql .= " AND id NOT IN (" . join(", ", array_fill(0, count($keep_ids), "?")) . ")";
return $this->execute($delete_sql, array_merge((array) $where_params, $keep_ids));
}
}
/**
* This class generates the objects that are returned from statements
* executed using the driver above.
*/
class DatabaseStatement extends \PDOStatement implements \Countable {
/**
* Binds passed parameters according to their PHP type and executes
* the prepared statement
* @see PDOStatement::execute()
*/
function execute($params = array()) {
$i = 1;
foreach($params as $k => $v):
$mode = PDO::PARAM_STR;
if(is_null($v)) $mode = PDO::PARAM_NULL;
elseif(is_bool($v)) $mode = PDO::PARAM_BOOL;
elseif(is_resource($v)) $mode = PDO::PARAM_LOB;
elseif(preg_match('/^\d*$/', $v) == 1) $mode = PDO::PARAM_INT;
$this->bindParam($i, $params[$k], $mode);
$i++;
endforeach;
$ok = parent::execute();
return $ok ? $this : false;
}
/**
* Returns the value of the first column of the first row
*/
function getOne() {
return $this->fetchColumn(0);
}
/**
* Returns an array of values of the column found at $index
* position.
* @param $index Ordinal position of column to be returned
*/
function getCol($index=0) {
return $this->fetchAll(PDO::FETCH_COLUMN, $index);
}
/**
* Returns all rows in numeric array format
*/
function getArray(){
return $this->fetchAll(PDO::FETCH_NUM);
}
/**
* Returns all rows in associative array format
*/
function getAll(){
return $this->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Returns all rows in associative array format
*/
function getAssoc() {
return $this->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Returns rows in multi-dimensional format where the first
* column is the key name and all other colums are grouped
* into associative arrays for each row
*/
function getGroup() {
return $this->fetchAll(PDO::FETCH_GROUP);
}
/**
* Returns a single row in associative format
*/
function getRow(){
return $this->fetch(PDO::FETCH_ASSOC);
}
/**
* Fetches rows in array format where the first column
* is the key name and all other columns are values
*/
function getKeyPair(){
//Emulate key pair support since PDO's FETCH_KEY_PAIR does something different
$tmp = $this->fetchAll(PDO::FETCH_ASSOC);
$arr = array();
for($i = 0; $i < count($tmp); $i++){
$arr[array_shift($tmp[$i])] = count($tmp[$i]) > 1 ? $tmp[$i] : array_shift($tmp[$i]);
}
return $arr;
}
/**
* Returns the number of rows returned by this statement
* @see Countable::count()
*/
function count(){
return $this->rowCount();
}
/**
* Returns the text of the most recently encountered error
*/
function errormsg(){
$msg = $this->errorInfo();
return $msg[2];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment