Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Branch: master
Fetching contributors…

Cannot retrieve contributors at this time

338 lines (276 sloc) 11.279 kB
<?php
define('SCAR_BASE', dirname(__FILE__).DIRECTORY_SEPARATOR);
define('SCAR_LIB', SCAR_BASE.'lib'.DIRECTORY_SEPARATOR);
define('SCAR_DB', SCAR_BASE.'db'.DIRECTORY_SEPARATOR);
include SCAR_LIB . 'exceptions.php';
include SCAR_LIB . 'inflector.php';
include SCAR_LIB . 'constants.php';
include SCAR_LIB . 'sql.php';
include SCAR_LIB . 'datastore.php';
include SCAR_LIB . 'repository.php';
include SCAR_LIB . 'scargeneric.php';
/**
* SCAR Factory and Bridge Class
* The SCAR Object is a static object that:
* - creates new SCAR_Generic Objects
* - runs queries for SCAR_Generic Objects
* - can retrieve tables and columns for databases
* - can escape strings
* - serves as a bridge for multiple DB types
*
* It should be used as the start of any SCAR retrieval chain, using the format
* SCAR::get('tables') and from that point forward, you will be working with
* SCAR_Generic objects. To trigger an insert, use the format SCAR::make('object')
* to get a SCAR_Generic object geared towards inserting data.
**/
class SCAR {
/**
* contains an array of timings for events as they happen
* useful for benchmarking
**/
public static $timings = array();
/**
* Specify a config path for the application or retrieve the config path
* @param $cfg string a string to set the config path to
* @return string
**/
public static function config($cfg = null) {
static $config;
if (!isset($config)) {
$config = null;
}
if ($cfg === null) {
return $config;
}
$config = $cfg;
return $config;
}
/**
* Record a timestamp for benchmarking
* if $finish is provided, then it will be the time lapsed since
* mark was called last for $method without $finish.
* @param string $method the token we are timing
* @param boolean $finish if true, the time lapse will be recorded to self::$timings
**/
public static function mark($method, $finish = false) {
static $timings;
if (!isset($timings)) {
$timings = array();
}
$time = microtime(true);
$uuid = 't'.$method;
if (!$finish) {
$timings[$uuid] = $time;
return;
}
$end_time = floatval($time - $timings[$uuid]);
SCAR::$timings[] = array('m' => $method, 't' => $end_time);
}
/**
* Create a SCAR_Generic object from a class name
* this function is useful when you know the class name
* and want to create an object (for insert).
* @param $name string a class name, ie Author
* @return SCAR_Generic
**/
public static function make($name) {
return SCAR::get(Inflector::tableize($name));
}
/**
* Get a collection of objects, via a SCAR object from a table
* this function creates a SCAR object based on the table
* @param $name string a name of a table to create an object for
* @param $columns string [optional] a list of columns to limit to
* @return SCAR_Generic
* @throws SCAR_Object_Not_Found_Exception
**/
public static function get($name, $columns = null) {
static $repository;
$datastore = SCAR::datastore();
$klass = Inflector::classify($name);
if (class_exists($klass)) {
$k = new $klass();
$k->columns($columns);
$k->datastore($datastore);
return $k;
}
// class does not exist, check the repository
if (!isset($repository)) {
self::mark('repository');
$repository = new SCAR_Repository(SCAR::config());
self::mark('repository', true);
}
$k = $repository->get($klass);
if ($k === null) {
throw new SCAR_Object_Not_Found_Exception(Inflector::camelize($name));
}
$k->columns($columns);
$k->datastore($datastore);
return $k;
}
/**
* Loads a Sub-Scheme object.
* This isolates DB specific methods into static classes which SCAR
* can then call. This serves as a factory method, attempting to load
* schemes out of the db/ directory
* @param $scheme string The scheme type to load, ie 'mysql'
* @throws SCAR_Scheme_Not_Found_Exception
**/
public static function load($scheme) {
$klass = 'SCAR_'.$scheme;
if (!class_exists($klass)) {
$file = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'db' . DIRECTORY_SEPARATOR . strtolower($scheme) . '.php';
if (!file_exists($file)) {
throw new SCAR_Scheme_Not_Found_Exception($scheme);
}
include $file;
if (!class_exists($klass)) {
throw new SCAR_Scheme_Not_Found_Exception($scheme);
}
}
}
/**
* Makes the SCAR Datastore a Singleton to the SCAR class
* This is a retrieval point for the SCAR_Datastore object,
* ensuring one persistent copy exists within a deployment of
* SCAR.
* @return SCAR_Datastore
**/
public static function datastore() {
static $datastore;
if (!isset($datastore)) {
self::mark('datastore');
$datastore = new SCAR_Datastore();
self::mark('datastore', true);
}
return $datastore;
}
/**
* Opens a connection to a database via a subscheme
* @param $dsn string a scheme://user:pass@host/db formatted string
* @return a connection object reference for that db combination
* @throws SCAR_Connection_Exception
**/
public static function connect($dsn) {
static $connectors;
if (!isset($connectors)) {
$connectors = array();
}
$uri = parse_url($dsn);
if (!isset($uri['port'])) {
$uri['port'] = null;
}
SCAR::load($uri['scheme']);
$hash = md5(strtolower(serialize(ksort($uri))));
if (!isset($connectors[$hash])) {
self::mark('connect');
$connector = call_user_func_array(array('SCAR_'.$uri['scheme'], 'connect'), array($uri));
if (!$connector) {
throw new SCAR_Connection_Exception($dsn);
}
$connectors[$hash] = $connector;
self::mark('connect', true);
}
return $connectors[$hash];
}
/**
* Calls a scheme specific escape function
* @param $dsn string a formatted scheme://user:pass@host/db string
* @param $string string what we want to escape for SQL
* @return string
**/
public static function escape($dsn, $string) {
$uri = parse_url($dsn);
SCAR::load($uri['scheme']);
return call_user_func_array(array('SCAR_'.$uri['scheme'], 'escape'), array($string));
}
/**
* Runs a scheme specific query and normalizes the results for SCAR objects
* @param $dsn string a scheme://user:pass@host/db formatted string
* @param $sql string the SQL to run
* @param $pk_list array the primary key list for the object
* @return array
* @throws SCAR_Query_Exception
**/
public static function query($dsn, $sql, $pk_list) {
// var_dump($sql);
self::mark($sql);
$i_am = substr($sql, 0, 6);
$is_update = ($i_am == 'UPDATE');
$is_select = ($i_am == 'SELECT');
$is_insert = ($i_am == 'INSERT');
$db = SCAR::connect($dsn);
// var_dump('QUERY: '.$sql);
$uri = parse_url($dsn);
SCAR::load($uri['scheme']);
$rs = call_user_func_array(array('SCAR_'.$uri['scheme'], 'query'), array($db, $sql));
if (!$rs) { throw new SCAR_Query_Exception($dsn, $sql); }
$results = array();
$keys = array();
if ($is_select) {
while ($row = call_user_func_array(array('SCAR_'.$uri['scheme'], 'row'), array($rs))) {
$store_pk = implode(',', $pk_list);
$pk_val = '';
foreach ($pk_list as $pk) {
$pk_val .= $row[$pk].',';
}
$pk_val = trim($pk_val, ',');
$keys[$store_pk][] = $pk_val;
$results[$pk_val] = $row;
}
}
self::mark($sql, true);
return array(
'keys' => $keys,
'data' => $results,
'rows' => ($is_select) ? call_user_func_array(array('SCAR_'.$uri['scheme'], 'count'), array($rs)) : false,
'next' => ($is_insert) ? call_user_func_array(array('SCAR_'.$uri['scheme'], 'nextid'), array($db)) : false,
'affected' => ($is_update || $is_insert) ? call_user_func_array(array('SCAR_'.$uri['scheme'], 'affected'), array($db)) : false,
);
}
/**
* Calls a scheme specific show tables command
* @param $dsn string a scheme://user:pass@host/db formatted string
* @return array
**/
public static function showTables($dsn) {
$db = SCAR::connect($dsn);
$uri = parse_url($dsn);
SCAR::load($uri['scheme']);
self::mark('showtables: '.$dsn);
$sql = call_user_func_array(array('SCAR_'.$uri['scheme'], 'showTables'), array());
$rs = call_user_func_array(array('SCAR_'.$uri['scheme'], 'query'), array($db, $sql));
$tables = array();
while ($row = call_user_func_array(array('SCAR_'.$uri['scheme'], 'row'), array($rs))) {
$tables[] = $row;
}
self::mark('showtables: '.$dsn, true);
self::mark('parsetables: '.$dsn);
$results = call_user_func_array(array('SCAR_'.$uri['scheme'], 'parseShowTables'), array($tables));
self::mark('parsetables: '.$dsn, true);
return $results;
}
/**
* Calls a scheme specific version of showing the columns in a database
* @param $dsn string a scheme://user:pass@host/db formatted string
* @param $table string a table name to get the columns for
* @return array
**/
public static function showColumns($dsn, $table) {
$db = SCAR::connect($dsn);
$uri = parse_url($dsn);
SCAR::load($uri['scheme']);
self::mark('showcolumns: '.$dsn.' tbl: '.$table);
$sql = call_user_func_array(array('SCAR_'.$uri['scheme'], 'showColumns'), array($table));
$rs = call_user_func_array(array('SCAR_'.$uri['scheme'], 'query'), array($db, $sql));
$columns = array();
while ($row = call_user_func_array(array('SCAR_'.$uri['scheme'], 'row'), array($rs))) {
$columns[] = $row;
}
self::mark('showcolumns: '.$dsn.' tbl: '.$table, true);
self::mark('parsecolumns: '.$dsn.' tbl: '.$table);
$results = call_user_func_array(array('SCAR_'.$uri['scheme'], 'parseShowColumns'), array($columns));
self::mark('parsecolumns: '.$dsn.' tbl: '.$table, true);
return $results;
}
}
Jump to Line
Something went wrong with that request. Please try again.