Skip to content
This repository was archived by the owner on Aug 26, 2025. It is now read-only.
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 72 additions & 21 deletions lib/db.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,35 @@
See PDO docs for details: http://www.php.net/manual/en/class.pdo.php

Adds a few extensions for common batched operations.

See related `extra/tagged-sql.php` for extra post-processing magic.
*/

class db extends PDO {

private $statement;
const USR_DEF_DB_ERR = '45000';
private $statement;
const USR_DEF_DB_ERR = '45000';
const DB_NO_ERR = '00000';

/* Create (or reuse) an instance of a PDO database */
static function _instance($dsn, $user, $password, $config = null) {
global $_db;
if ($_db !== null) return $_db; // return cached

if ($config === null)
$config = array( PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8' );

try {
$_db = new db($dsn, $user, $password, $config);
$_db = new db($dsn, $user, $password, $config);
} catch (Exception $e) {
throw new Exception("Failed to connect to database.", 500, $e);
}

return $_db;
}

/* Returns an array of classes based on the given SQL and bound parameters (see PDO docs for details) */
function select($sql, $bound_parameters = array()) {
function select($sql, $bound_parameters = array()) {
$this->statement = $this->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$this->statement->execute($bound_parameters);
$resultset = $this->statement->fetchAll(PDO::FETCH_CLASS);
Expand All @@ -47,53 +47,101 @@ function select_row($sql, $bound_parameters = array()) {
elseif ($c !== 1) throw new Exception("Too many rows (".(count($r)).") returned from '$sql'", 500);
return $r[0];
}


function select_objects($sql, $bound_parameters = array()) {

$rows = $this->select($sql, $bound_parameters);

$d = '.'; $t = ':'; // delimiters for depth and type
$o = array(); // output

foreach ($rows as $r) { // each row in result set

$row = array();
$type = '';

foreach ($r as $key => $value) { // each column

if (strpos($key, $t)) {
// extract type
$p = explode($t, $key);
$type = $p[1];
$key = $p[0];
} else {
$type = null; // no type provided
}

// extract keys
$keys = strpos($key, $d) ? explode($d, $key) : array($key);

$ptr = &$row; // working pointer

// create objects as needed
foreach ($keys as $k) {
if (!isset($ptr[$k])) $ptr[$k] = array();
$ptr = &$ptr[$k];
}

// adjust type
if (!empty($type)) settype($value, $type);

// add column
if (empty($ptr)) $ptr = $value;
else $ptr[] = $value;
}

$o[] = db::array_to_object($row); // add row to output as objects
}

return $o;
}

/* Provide a wrapper for updates which is really just an alias for the query function. */
function update($sql, &$bound_parameters = array()) {
$this->query($sql, $bound_parameters);
if ($this->statement->rowCount() === 0)
throw new Exception('Update failed: resource was not found.', 404);
}
/*
/*
General query. Use this when no specific results are expected. Example: attempting to delete a resource
that may or may exist.
$bound_parameters is an array of arrays with the 'value' member as the value to bind and the 'pdoType' as

$bound_parameters is an array of arrays with the 'value' member as the value to bind and the 'pdoType' as
that parameter's PDO datatype.
*/
function query($sql, &$bound_parameters = array()) {
$this->statement = $this->prepare($sql);
if (!empty($bound_parameters)) {
if (!empty($bound_parameters)) {
foreach ($bound_parameters as $key => &$param) {
$v = $param['value']; $t = $param['pdoType'];
if (!$this->statement->bindValue($key, $v, $t))
throw new Exception("Unable to bind '$v' to named parameter ':$key'.", 500);
}
}

$this->statement->execute();
$this->errors();
$this->errors();
}

/* Provide a wrapper for inserts which is really just an alias for the query function. */
function insert($sql, &$bound_parameters = array()) {
$this->query($sql, $bound_parameters);
if ($this->statement->rowCount() === 0)
throw new Exception('Insert failed: no rows were inserted.', 500);
}

/* Provide a wrapper for deletes which is really just an alias for the query function. */
function delete($sql, &$bound_parameters = array()) {
$this->query($sql, $bound_parameters);
if ($this->statement->rowCount() === 0)
throw new Exception('Delete failed: resource does not exist.', 404);
}

/* Return the number of rows affected by the last INSERT, DELETE, or UPDATE. */
function affected_rows() {
return $this->statement->rowCount();
}

/* Throw error info pertaining to the last operation. */
private function errors() {
$e = $this->statement->errorInfo();
Expand All @@ -107,4 +155,7 @@ private function errors() {
}
else throw new Exception('Update failed for unknown reason.', 500);
}
}

// convert an array to an object (recursively)
public static function array_to_object($o) { return is_array($o) ? (object) array_map(__METHOD__, $o) : $o; }
}