<?php
// {{{ Header
/*
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| SIERRA : PHP Application Framework http://code.google.com/p/sierra-php |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| Copyright 2005 Jason Read |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.|
| See the License for the specific language governing permissions and |
| limitations under the License. |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
*/
// }}}
// {{{ Constants
/**
* Constant that identifies the default date format that should be used
* when inserting into date type columns. Child SRA_Database* objects may or
* may not use this same format. If they do not, they must have and use their
* own constant identifying this value.
* @type string
* @access public
*/
define('SRA_DB_DATE_FORMAT', 'Y-m-d');
/**
* Constant that identifies the default date/time format that should be used
* when inserting into timestamp type columns. Child SRA_Database* objects may or
* may not use this same format. If they do not, they must have and use their
* own constant identifying this value.
* @type string
* @access public
*/
define('SRA_DB_TIME_FORMAT', 'Y-m-d H:i:s');
/**
* Identifies (for internal SRA_Database class use only) that an database
* server's connection status is currently closed.
* @type int
* @access private
*/
define('_SRA_DB_CONNECTION_CLOSED', 1);
/**
* Identifies (for internal SRA_Database class use only) that a database server
* is currently in an error status (cannot be used).
* @type int
* @access private
*/
define('_SRA_DB_CONNECTION_ERROR', 2);
/**
* Identifies (for internal SRA_Database class use only) that an database
* server's connection status is currently open.
* @type int
* @access private
*/
define('_SRA_DB_CONNECTION_OPEN', 4);
/**
* the default db host
* @type string
*/
define('SRA_DB_DEFAULT_HOST', '127.0.0.1');
/**
* Constant that identifies database objects of type mssql.
* @type string
* @access public
*/
define('SRA_DB_TYPE_MSSQL', 'mssql');
/**
* Constant that identifies database objects of type mysql.
* @type string
* @access public
*/
define('SRA_DB_TYPE_MYSQL', 'mysql');
/**
* Constant that identifies database objects of type postgresql.
* @type string
* @access public
*/
define('SRA_DB_TYPE_POSTGRESQL', 'pgsql');
/**
* Constant that identifies database objects of type sqlite.
* @type string
* @access public
*/
define('SRA_DB_TYPE_SQLITE', 'sqlite');
/**
* the default values for boolean FALSE data types (the first value is the value
* that will be inserted into columns of that type. for more information, see
* the "db" element "boolean-false" and "boolean-true" attribute definitions in
* sierra-config*.dtd
* @type string
* @access public
*/
define('SRA_DB_BOOL_FALSE_VALS', "'0' 0");
/**
* the default PHP representation for boolean FALSE values
* @type mixed
* @access public
*/
define('SRA_DB_BOOL_FALSE', FALSE);
/**
* same as SRA_DB_BOOL_FALSE_VALS for TRUE
* @type string
* @access public
*/
define('SRA_DB_BOOL_TRUE_VALS', "'1' 1");
/**
* the default PHP representation for boolean TRUE values
* @type mixed
* @access public
*/
define('SRA_DB_BOOL_TRUE', TRUE);
/**
* Debug constant
* @type boolean
* @access public
*/
define('SRA_DB_DEBUG', FALSE);
// }}}
// {{{ Includes
include_once(SRA_LIB_DIR .'/sql/SRA_ResultSet.php');
include_once(SRA_LIB_DIR .'/sql/SRA_ExecuteSet.php');
// }}}
// {{{ SRA_Database
/**
* This abstract class is used for DB abstraction.
* A SRA_Database wrapper class used to encapsulate database specific
* functions and methods. Because this is an abstract class it will never
* be instantiated by itself, but rather child SRA_Database* objects will be
* instantiated which contain specific functionality for one database
* server type.
*
* @author Jason Read <hide@address.com>
* @package sierra.sql
*/
class SRA_Database {
// {{{ Properties
/**
* values for boolean FALSE
*
* @type array
* @access private
*/
var $_boolFalseVals;
/**
* PHP representation for boolean FALSE
*
* @type mixed
* @access private
*/
var $_boolFalse;
/**
* values for boolean TRUE
*
* @type array
* @access private
*/
var $_boolTrueVals;
/**
* PHP representation for boolean TRUE
*
* @type mixed
* @access private
*/
var $_boolTrue;
/**
* See the sierra-conf.dtd for more details
*
* @type string[]
* @access protected
*/
var $_config;
/**
* This attribute references the connections to database servers for
* this database object. If more than 1 read-write database server is
* provided in the _config attribute, this array will be instantiated
* and handled based on the replication options specified in the
* _replicationOptions attribute.
* @type Object[]
* @access private
*/
var $_dbs;
/**
* This attribute is used to keep track of whether or not the SRA_Database
* object is currently in the middle of a transaction. This attribute
* may affect the behavior of the SRA_Database*::execute method calls
* (dependent on the SRA_Database type). For more info see the
* startTransactin and commit method api.
* @type boolean
* @access protected
*/
var $_inTransaction = FALSE;
/**
* Used to store fetch table cache
* @type array
* @access protected
*/
var $_fetchCache = array();
/**
* The SRA_TimeZone to use for Date* types
* @type SRA_TimeZone
* @access protected
*/
var $_timeZone;
// }}}
// {{{ SRA_Database()
/**
* do NOT instantiate this, or any of the SRA_Database* classes directly.
* instead, use the singleton SRA_Database::getDatabase method to obtain a
* reference
* @access private
*/
function SRA_Database() {}
// }}}
// {{{ applyLimitAndOffset
/**
* Returns the query properly formatted with LIMIT and OFFSET sql
* constraints if valid and specified
*
* @param string $query the sql query to apply the constraints to
* @param int $limit the LIMIT constraint
* @param int $offset the OFFSET constraint
* @access public
* @return string
*/
function applyLimitAndOffset($query, $limit, $offset) {
if (!strstr(strtolower($query), ' limit ') && !strstr(strtolower($query), ' offset ')) {
if ($limit > 0) {
$query .= " LIMIT ${limit}";
}
if ($offset > 0) {
$query .= " OFFSET ${offset}";
}
}
return $query;
}
// }}}
// {{{ clearCache()
/**
* clears any query cache in the database instance
* @return void
*/
function clearCache() {
$this->_fetchCache = array();
}
// }}}
// {{{ close()
/**
* Closes all of the db connections, release all resources. To close
* the database connections this method calls the child closeConn
* method for every databases connection in the _dbs
* arrays. This method returns an SRA_Error object if any errors occur.
* Otherwise it returns nothing.
*
* @access public
* @return void
*/
function close()
{
// Close all connections in _dbs.
$this->_dbs = is_array($this->_dbs) ? $this->_dbs : array($this->_dbs);
$keys = array_keys($this->_dbs);
foreach ($keys as $key)
{
$this->_closeConn($this->_dbs[$key]);
unset($this->_dbs[$key]);
}
}
// }}}
// {{{ commit()
/**
* Abstract method that commits the database changes done during a
* transaction that is in progress. This method MUST be implemented in
* the child SRA_Database* classes.One important element in this method is
* that, similiar to the SRA_Database*::execute/SRA_Database::processUpdate
* methods, this is a pass up - pass down query. This means that the
* SRA_Database* method will initially be called (with no conn parameter
* specified). This method will then simply call (and return) the
* SRA_Database::processCommit method (which in turn will call the
* SRA_Database*::commit method with the conn parameter specified for each
* of the replication servers).
*
* This method MUST set the _inTransaction flag to FALSE
*
* @param object $conn the database connection object to commit the
* transaction for. If not specified this method will simply return
* the SRA_Database(parent)::processCommit method (which will in turn call
* this method for all of the replication servers).
* @access public
* @return void
*/
function commit($conn=NULL)
{
// SRA_Error.
$msg = "SRA_Database::commit(): This method is abstract.";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// }}}
// {{{ convert()
/**
* generic convert method. this simply makes a passthru call to the correct
* convert* method based on the $type specified. this method does not need
* to be overriden by subclasses
*
* @param string $type the data type
* @param mixed $data the data to convert
* @access public
* @return string
*/
function convert($type, $data) {
switch ($type) {
case SRA_DATA_TYPE_BLOB :
return $this->convertBlob($data);
case SRA_DATA_TYPE_BOOLEAN :
return $this->convertBoolean($data);
case SRA_DATA_TYPE_TIME :
return $this->convertTime($data);
case SRA_DATA_TYPE_DATE :
return $this->convertDate($data);
case SRA_DATA_TYPE_FLOAT :
return $this->convertFloat($data);
case SRA_DATA_TYPE_INT :
return $this->convertInt($data);
case SRA_DATA_TYPE_STRING :
return $this->convertText($data);
default:
$msg = "SRA_Database::convert: SRA_Error - Invalid type: ${type}";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
}
// }}}
// {{{ convertBlob()
/**
* Convert a blob to the underlying db type. Call this method to
* prepare blob values for insertion. Returns an SRA_Error object if the
* blob parameter is not a blob. This is an abstract method that must
* be implemented by the child SRA_Database* classes.
*
* @param string $blob the blob value to convert.
* @access public
* @return string
*/
function convertBlob($blob)
{
// SRA_Error.
$msg = "SRA_Database::convertBlob(): This method is abstract.";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// }}}
// {{{ convertBoolean()
/**
* Convert a boolean to the underlying db type. Call this method to
* prepare boolean values for insertion. for more information, see the "db" element
* "boolean-false" and "boolean-true" attribute definitions in sierra-config*.dtd
* this method can be overriden by the corresponding db implementation
*
* @param boolean $bool boolean value to convert
* @access public
* @return string
*/
function convertBoolean($bool) {
if (SRA_Util::convertBoolean($bool) || $bool === $this->_boolTrue) {
$val = $this->_boolTrueVals[0];
}
else if (isset($bool)) {
$val = $this->_boolFalseVals[0];
}
else {
$val = NULL;
}
return is_string($val) ? "'${val}'" : (isset($val) ? $val : 'NULL');
}
// }}}
// {{{ convertDate
/**
* Convert a dateOnly SRA_GregorianDate object into a database readable
* string. This format is required for insertion into the database. this is an
* abstract method that must be implemented by the child SRA_Database*
* classes. This method returns an SRA_Error object if the $dateTime parameter
* is not a valid SRA_GregorianDate object
* @param SRA_GregorianDate $dateTime the date to convert
* @access public
* @return string
*/
function convertDate($dateTime) {
// SRA_Error.
$msg = "SRA_Database::convertDate(): This method is abstract.";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// }}}
// {{{ convertTime
/**
* Convert a date/time SRA_GregorianDate object into a database readable
* string using the db timezone. This format is required for insertion into
* the database. this is an abstract method that must be implemented by the
* child SRA_Database* classes. This method returns an SRA_Error object if the
* $dateTime parameter is not a valid SRA_GregorianDate object
* @param SRA_GregorianDate $dateTime the time to convert
* @access public
* @return string
*/
function convertTime($dateTime) {
// SRA_Error.
$msg = "SRA_Database::convertDate(): This method is abstract.";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// }}}
// {{{ convertFloat()
/**
* Convert a Float to the underlying db type. Call this method to
* prepare Float values for insertion. Returns an SRA_Error if the float
* parameter is not a number. This is an abstract method that must be
* implemented by the child SRA_Database* classes.
*
* @param float $value the float to prepare.
* @access public
* @return string
*/
function convertFloat($value)
{
// SRA_Error.
$msg = "SRA_Database::convertFloat(): This method is abstract.";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// }}}
// {{{ convertInt()
/**
* Added for consistency between types. No actual conversion is necessary
* for an Integer so this method simply returns the value passed. If a
* subclass requires any conversion, this method can be overriden.
*
* @param int $value the int to prepare.
* @access public
* @return string
*/
function convertInt($value)
{
return $value === NULL ? 'NULL' : $value;
}
// }}}
// {{{ convertText()
/**
* Convert a text string to the underlying db string type. Escape any
* characters that would crash the query. Call this method to prepare
* text values for insertion. This is an abstract method that must be
* implemented by the child SRA_Database* classes.
*
* @param string $text string to convert.
* @access public
* @return string
*/
function convertText($text)
{
// SRA_Error.
$msg = "SRA_Database::convertText(): This method is abstract.";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// }}}
// {{{ execute()
/**
* Abstract method used to executes a SQL query. If an error occurs
* during execution, this method will log a new error with the SQL
* query as part of the error message, and return an error object.
* Otherwise it returns an SRA_ExecuteSet object which will contain the
* number of rows affected by the query and possibly the
* sequenceColumn value is this is an insert query and an auto
* incremental column is being used (see SRA_Database::execute::query api
* for more detail). This method is used with queries that don't
* return a result set / RecordSet object. Because this method is
* abstract, it MUST be implemented by the child SRA_Database* object.
* This method also will either auto commit the query, or buffer it
* based on what is specified by the _autoCommit attribute.
*
* The basic flow of a SRA_Database*::execute method is that it is called
* by another class (db parameter is null), this method calls the
* parent::processUpdate method, this method then runs the update
* query (by calling the child execute method with a db connection
* parameter specified) for each of the active replication servers. It
* then returns either the number of records affected (as returned by
* the first execute call), or an SRA_Error object (if returned by all
* execute calls). If an SRA_Error occurs, the query will be written to a
* buffer file for future processing. If a buffer file already exists
* for any db server, the query will be written directly to that file
* (execute will not be called at all). Buffer files are routinely
* processed by the BGP and deleted when successful (when db server
* accepts all queries).
*
* @param string $query the query to execute. This should be an
* update/insert/ or delete query.
* @param int $errorLevel this optional parameter defines the error
* level of the SRA_Error object that should will be created if the db
* query fails. The default value is SRA_ERROR_PROBLEM. This value may
* be set to SRA_ERROR_OPERATIONAL if you do not wish for the error to
* be logged.
* @param string $incCol if the query is an insert query, and a db
* managed auto-incremental column is being used by the table being
* inserted into, and this value is needed by the Object calling the
* method, this value will correspond with the name of the
* auto-incremental column.
*
* If this parameter is specified, and an INSERT query is being
* performed, this method will attempt to retrieve the value of the
* incremental column that was used by the database during the insert
* and add this value to the resultant SRA_ExecuteSet object.
* @param object $conn this parameter will be null when the execute
* method is initially called by another object. However, when the
* call is passed up to SRA_Database::processUpdate method, this method
* will pass the query back down to the SRA_Database*::execute method with
* the conn parameter specified (one call for each replication
* server). At this time the SRA_Database*::execute method will actually
* attempt to process that query running the database specified
* execute command and returning applicable # of rows that were
* affected by the query (or an SRA_Error object). These return values
* will then be passed back down to the original call to the execute
* method and returned to the original calling object.
* @access public
* @return SRA_ExecuteSet
*/
function &execute($query, $incCol=FALSE, $errorLevel=SRA_ERROR_PROBLEM, $conn=NULL)
{
// SRA_Error.
$msg = "SRA_Database::execute(): This method is abstract.";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// }}}
// {{{ fetch()
/**
* This abstract method executes a SQL query when implemented by a child
* SRA_Database* class. If an error occurs during execution, this method will
* log a new error with the SQL query as part of the error message, and
* return an error object. Otherwise it returns a reference to a RecordSet
* object.
*
* @param string $query the SQL query to execute.
* @param array $types the data types in sequential order that will be returned
* by this query. These types can be any of the SRA_DATA_TYPE_*
* constants. if not specified, all types will be assumed to be text
* (SRA_DATA_TYPE_STRING)
* @param int $limit only return a maximum of this # of rows
* @param int $offset skip that many rows before beginning to return rows
* THE FIRST ROW IS AN OFFSET OF 0
* @param boolean $getActualCount whether or not to set the ACTUAL # of
* rows in the resulting SRA_ResultSet instance if $limit or $offset
* constraints are used
* @param int $errorLevel this optional parameter defines the error
* level of the SRA_Error object that should will be created if the db
* query fails. The default value is SRA_ERROR_PROBLEM. This value may
* be set to SRA_ERROR_OPERATIONAL if you do not wish for the error to
* be logged.
* @access public
* @return SRA_ResultSet
*/
function &fetch($query, $types=NULL, $limit=FALSE, $offset=FALSE, $getActualCount=TRUE, $errorLevel=SRA_ERROR_PROBLEM)
{
// SRA_Error.
$msg = "SRA_Database::fetch(): This method is abstract.";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// }}}
// {{{ getColumnDefinition()
/**
* provides an sql statement defining the data type, constraints, and
* referential integrity (optional) for a given SRA_SchemaColumn. this method
* may be implemented by each of the underlying database types if the
* default MYSQL implementation does not suffice
*
* @param SRA_SchemaTable $table the SRA_SchemaTable that the column belongs to
* @param SRA_SchemaColumn $column the SRA_SchemaColumn to create the definition for
* @param boolean $dbRefIntegrity whether or not referential integrity should
* be enforced at the database layer
* @param boolean $addCheckConstraint whether or not to add a check constraint
* to the column definition
* @access public
* @return string
*/
function getColumnDefinition(& $table, & $column, $dbRefIntegrity = TRUE, $addCheckConstraint = TRUE) {
$def = '';
// default return type is for mysql
if ($column->getColumnType()) {
$def = $column->getColumnType();
}
else {
$type = $column->getType();
switch ($type) {
case SRA_DATA_TYPE_BLOB:
$def = 'BLOB';
break;
case SRA_DATA_TYPE_BOOLEAN:
$def = 'ENUM(' . $this->convertBoolean(TRUE) . ',' . $this->convertBoolean(FALSE) . ')';
break;
case SRA_DATA_TYPE_DATE:
$def = 'DATE';
break;
case SRA_DATA_TYPE_TIME:
$def = 'TIMESTAMP';
break;
case SRA_DATA_TYPE_FLOAT:
$def = 'DOUBLE';
break;
case SRA_DATA_TYPE_INT:
$def = 'INT';
break;
case SRA_DATA_TYPE_STRING:
$def = $column->hasValidator('maxLength') ? 'VARCHAR(' . $column->getVars('maxLength') . ')' : 'TEXT';
break;
}
}
$def .= $column->hasValidator('required') || $table->isPrimaryKey($column->getName()) ? ' NOT NULL' : '';
$default = $column->getDefault();
if ($default && (is_numeric($default) || substr($default, 0, 1) == '"' || substr($default, 0, 1) == "'")) {
if ($column->getType() == SRA_DATA_TYPE_BOOLEAN) {
$default = SRA_Util::convertBoolean(eval('return ' . $default . ';')) ? $this->convertBoolean(TRUE) : $this->convertBoolean(FALSE);
}
$def .= ' DEFAULT ';
$def .= $column->getType() == SRA_DATA_TYPE_INT ? $default : "'" . str_replace("'", "\'", SRA_Util::stripQuotes(SRA_Util::stripQuotes($default), "'", "'")) . "'";
}
else if (!$column->hasValidator('required') && !$column->isSequence() && !$table->isPrimaryKey($column->getName())) {
$def .= ' DEFAULT ' . ($column->getType() == SRA_DATA_TYPE_DATE || $column->getType() == SRA_DATA_TYPE_TIME ? '0' : 'NULL');
}
if ($column->isSequence()) {
$def .= ' AUTO_INCREMENT';
}
if ($dbRefIntegrity && $column->getReferences()) {
$def .= ' REFERENCES ' . $column->getReferences();
$def .= $column->isOnDeleteCascade() ? ' ON DELETE CASCADE' : ' ON DELETE SET NULL';
}
// add CHECK constraints (not supported by mysql)
if ($addCheckConstraint) {
// max validator
if ($column->hasValidator('max')) {
$def .= ' CHECK (' . $column->getName() . ' <= ' . $column->getVars('max') . ')';
}
// min validator
else if ($column->hasValidator('min')) {
$def .= ' CHECK (' . $column->getName() . ' >= ' . $column->getVars('min') . ')';
}
// range validator
else if ($column->hasValidator('range')) {
$def .= ' CHECK (' . $column->getName() . ' BETWEEN ' . $column->getVars('min') . ' AND ' . $column->getVars('max') . ')';
}
}
return $def;
}
// }}}
// {{{ getQueryValue
/**
* used to retrieve a single query value. returns NULL if the query does not
* return a row
* @param SRA_Database $db the SRA_Database connection
* @param string $query the query to return the value from. this query
* should only have one column. the value of the first column/first row will
* be returned
* @param string $type the data type for the column being retrieved
* @access public
* @return string
*/
function getQueryValue(& $db, $query, $type=SRA_DATA_TYPE_STRING) {
if (SRA_ResultSet::isValid($results =& $db->fetch($query, array($type))) && $results->count()) {
$row =& $results->next();
return $row[0];
}
return NULL;
}
// }}}
// {{{ getTableDefinition()
/**
* provides an sql statement defining the constraints for a given
* SRA_SchemaTable. this method may be implemented by each of the underlying
* database types if the default implementation does not suffice
*
* @param SRA_SchemaTable $table the SRA_SchemaTable to create the definition for
* @param boolean $dbRefIntegrity whether or not referential integrity should
* be enforced at the database layer
* @access public
* @return string
*/
function getTableDefinition(& $table, $dbRefIntegrity = TRUE) {
$def = '';
$pk = $table->getPrimaryKey();
if (is_array($pk) && count($pk)) {
$def = 'PRIMARY KEY (';
$started = FALSE;
foreach ($pk as $primaryKey) {
$def .= $started ? ',' : '';
$def .= $primaryKey;
$started = TRUE;
}
$def .= ')';
}
else if (!is_array($pk) && $pk) {
$def = "PRIMARY KEY (${pk})";
}
return $def;
}
// }}}
// {{{ getRecordCount()
/**
* returns total # of records returned for a given query
*
* @param SRA_Database $db the SRA_Database connection
* @param string $query the query
* @access public
* @return int
*/
function getRecordCount(&$db, $query) {
if (!strpos(strtolower($query), ' having ')) {
$parseQuery = SRA_Database::parseQuery($query);
$pieces = explode(' ', $parseQuery['orderConstraint']);
$col = 'count(*)';
$groupFound = FALSE;
foreach ($pieces as $piece) {
$eval = strtolower(trim($piece));
if (!$eval || $eval == 'by') {
continue;
}
if ($eval == 'group') {
$groupFound = TRUE;
continue;
}
if ($groupFound) {
$col = "count(distinct ${piece})";
break;
}
}
$parseQuery['select'] = array($col => $col);
return SRA_Database::getQueryValue($db, SRA_Database::reverseParseQuery($parseQuery, FALSE), SRA_DATA_TYPE_INT);
}
else {
$results =& $db->fetch($query);
return $results->getTotalCount();
}
}
// }}}
// {{{ _getAppDbConnection()
/**
* This method is called by the child SRA_Database* classes to retrieve a
* database connection to utilize for a query. This method manages all
* of the connections as well as replication. This method will also
* run the additional execute queries if the application side updates
* are enabled for replication (i.e. returns first read-write database
* object, then opens connection to remaining read-write servers, and
* executes the query for each of those servers by calling the child
* SRA_Database*::execute method).
* @param string $query the query statement that the database
* object is intended for. This query is evaluated is replication is
* in place and an appropriate database object returned. If left
* blank, it will be assumed that the query is an update query and
* requires a valid read-write connection.
* @access protected
* @return object
*/
function _getAppDbConnection($query='') {
if (!is_resource($this->_dbs)) {
$config=array();
$config['host'] = $this->_config['host'];
$config['server'] = $this->_config['host'];
$config['name'] = isset($this->_config['name']) ? $this->_config['name'] : $this->_config['key'];
$config['user'] = $this->_config['user'];
$config['password'] = $this->_config['password'];
$config['port'] = $this->_config['port'];
$this->_dbs = $this->_openConn($config);
if (SRA_Error::isError($this->_dbs)) {
$errorLevel = SRA_ERROR_PROBLEM;
// Check log file for any special error levels to set
if (isset($this->_config['error-level'])) {
$errorLevel = $this->_config['error-level'];
}
$msg = "SRA_Database::_getAppDbConnection(): Problem connecting to db.";
return(SRA_Error::logError($msg, __FILE__, __LINE__, $errorLevel));
}
}
return($this->_dbs);
}
// }}}
// {{{ getNextSequence()
/**
* Abstract method used to return the next sequence value from the database sequence specified.
* If an error occurs during execution, this method will log a new error with the SQL query as
* part of the error message, and return an error object. Otherwise it returns an integer value
* representing the next sequence value. Because this method is abstract, it MUST be implemented
* by the child SRA_Database* object. This method also will either auto commit the query, or buffer
* it based on what is specified by the _autoCommit attribute. See the SRA_Database::execute api for
* more details on the flow of the nextSequence methods.
*
* @param string $sequence the name of the sequence to return the next value for.
* @param int $errorLevel this optional parameter defines the error level of the SRA_Error object
* that should will be created if the db query fails. The default value is SRA_ERROR_PROBLEM. This
* value may be set to SRA_ERROR_OPERATIONAL if you do not wish for the error to be logged.
* @param object $conn this parameter will be null when the getNextSequence method is initially
* called by another object. However, when the call is passed up to SRA_Database::processGetNextSequence
* method, this method will pass the query back down to the SRA_Database*::getNextSequence method with the
* conn parameter specified (one call for each replication server). At this time the
* SRA_Database*::getNextSequence method will actually attempt to process that query running the database
* specified sequence query and returning applicable sequence value. This return value will then be
* passed back down to the original call to the getNextSequence method and returned to the original
* calling object.
* @access public
* @return int
*/
function getNextSequence($sequence, $errorLevel = SRA_ERROR_PROBLEM, $conn = FALSE)
{
$msg = "SRA_Database::getNextSequence(): This method is abstract.";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// }}}
// {{{ getDefaultPort
/**
* Static method that returns the default port for the database type
* specified
*
* @param string $dbType the database type. must correspond with one of the
* SRA_DB_TYPE_* constants
* @access public
* @return int
*/
function getDefaultPort($dbType) {
if (SRA_DB_TYPE_MYSQL == $dbType) {
return 3306;
}
else if (SRA_DB_TYPE_POSTGRESQL == $dbType) {
return 5432;
}
else if (SRA_DB_TYPE_MSSQL == $dbType) {
return 1433;
}
// unknown type
return FALSE;
}
// }}}
// {{{ importFile()
/**
* This method is abstract and as such must be implemented by the child SRA_Database classes. Some database
* types may not support this method. Please view the child SRA_Database object api for this method before
* using it. This method imports a delimited file into a database table using the parameters specified.
* This method returns an SRA_Error object if the file import is not successful.
*
* @param string $fileName the name of the file to import. This file must be delimited with the same
* number of columns as are in the table.
* @param string $tableName the name of the table to insert the data into.
* @param boolean $deleteFile whether or not the file should be deleted if the import is successful.
* By default this value is TRUE.
* @param string $delimiter the delimiter to use for the file import. The default value for this is a
* comma. Note: If a delimiter occurs in a data column, it should be escaped using backslash.
*
* @access public
* @return boolean
*/
function importFile($fileName, $tableName, $deleteFile=TRUE, $delimiter=",")
{
$msg = "SRA_Database::importFile(): This method is abstract.";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// }}}
// {{{ isInTransaction()
/**
* Returns a boolean value specifying if the SRA_Database object is currently in a transaction.
*
* @access public
* @return boolean
*/
function isInTransaction()
{
return $this->_inTransaction;
}
// }}}
// {{{ isType
/**
* returns TRUE if this SRA_Database instance is of the type specified
* @param int $type the type to check for. one of the SRA_DB_TYPE_*
* constants
* @access public
* @return boolean
*/
function isType($type) {
return $this->_config['type'] == $type;
}
// }}}
// {{{ isValid()
/**
* Static method that returns TRUE if the object parameter references a
* valid SRA_Database object.
*
* @param object $object the object to validate.
* @access public
* @return boolean
*/
function isValid($object) {
return (is_object($object) && (!isset($object->err) || !SRA_Error::isError($object->err)) && (strtolower(get_class($object)) == 'sra_database' || is_subclass_of($object, 'SRA_Database')));
}
// }}}
// {{{ parseQuery()
/**
* parses a query and returns it in the following format:
* array('select' => array('column1' => 'column1 alias', ... ,'columnN' => 'columnN alias'),
* 'from' => array('table1' => 'table1 alias', ... , 'tableN' => 'tableN alias'),
* 'fromConstraint' => array('tableN' => '[if a JOIN was used, the method used for the join. this should be used in place of adding tableN to the FROM clause]'),
* 'constraint' => '[everything that is part of the WHERE clause (if applicable)]',
* 'orderConstraint' => [everything after the WHERE clause (i.e. ORDER BY...)])
*
* @param string $query the query to parse
* @access public static
* @return array
*/
function parseQuery($query) {
$query = str_replace(' ', ' ', $query);
$pieces = explode(' ', $query);
$selectFound = FALSE;
$fromFound = FALSE;
$whereFound = FALSE;
$orderFound = FALSE;
$commaFound = TRUE;
$nextCommaFound = FALSE;
$select = array();
$from = array();
$fromConstraints = array();
$constraint = '';
$orderConstraint = '';
$key = FALSE;
$buffer = '';
$lastTable = FALSE;
foreach ($pieces as $piece) {
$piece = trim($piece);
$eval = strtolower(trim($piece));
if ($fromFound) {
$buffer .= ' ' . $piece;
}
if (!$whereFound && (!$eval || $eval == 'as')) {
continue;
}
if ((!$whereFound && !$commaFound && $eval == ',') || ($fromFound && ($eval == 'join' || $eval == 'straight_join' || $eval == 'left' || $eval == 'right' || $eval == 'inner' || $eval == 'outer' || $eval == 'cross' || $eval == 'natural'))) {
$commaFound = TRUE;
continue;
}
if ($nextCommaFound) {
$commaFound = TRUE;
$nextCommaFound = FALSE;
}
if (!$whereFound && !$orderFound && substr($eval,-1) == ',') {
$piece = substr($piece, 0, strlen($substr)-1);
$nextCommaFound = TRUE;
}
if (!$whereFound && $eval == 'where') {
$whereFound = TRUE;
continue;
}
if (!$orderFound && ($eval == 'order' || $eval == 'group' || $eval == 'having' || $eval == 'union' || $eval == 'intersect')) {
$orderFound = TRUE;
}
if (!$fromFound && $eval == 'from') {
$fromFound = TRUE;
$commaFound = TRUE;
$buffer = '';
continue;
}
if (!$selectFound && $eval == 'select') {
$selectFound = TRUE;
continue;
}
if ($orderFound) {
$orderConstraint .= ' ' . $piece;
}
else if ($whereFound) {
$constraint .= ' ' . $piece;
}
else if ($fromFound) {
$val = $piece;
if ($commaFound) {
$key = $val;
$commaFound = FALSE;
}
$from[$key] = $val;
$lastTable = $key;
}
else if ($selectFound) {
$val = $piece;
if ($commaFound) {
$key = $val;
$commaFound = FALSE;
$buffer = $piece;
}
$select[$key] = $val;
}
if ($lastTable && !$whereFound && !$orderFound) {
if (!isset($fromConstraints[$lastTable])) {
$fromConstraints[$lastTable] = '';
}
$fromConstraints[$lastTable] .= $buffer;
$buffer = '';
}
}
$keys = array_keys($fromConstraints);
foreach ($keys as $key) {
$fromConstraints[$key] = trim($fromConstraints[$key]);
if (SRA_Util::endsWith($fromConstraints[$key], ',')) {
$fromConstraints[$key] = substr($fromConstraints[$key], 0, -1);
}
if ($fromConstraints[$key] == $key) {
unset($fromConstraints[$key]);
}
}
$results = array('select' => $select, 'from' => $from, 'fromConstraints' => $fromConstraints, 'constraint' => trim($constraint), 'orderConstraint' => trim($orderConstraint));
return $results;
}
// }}}
// {{{ reverseParseQuery()
/**
* converts #parseQuery results into a query
*
* @param array $parseResults #parseQuery array to convert back into a query
* @param boolean $includeOrderConstraint whether or not to include any
* order constraints in the query
* @access public static
* @return string
*/
function reverseParseQuery($parseResults, $includeOrderConstraint=TRUE) {
$query = 'SELECT';
$started = FALSE;
foreach($parseResults['select'] as $col => $alias) {
$query .= ($started ? ', ' : ' ') . $col;
$query .= $col != $alias ? ' as ' . $alias : '';
$started = TRUE;
}
$query .= ' FROM';
$started = FALSE;
foreach($parseResults['from'] as $table => $alias) {
$query .= $started && !strstr(strtolower($parseResults['fromConstraints'][$table]), 'join') ? ', ' : ' ';
$query .= !isset($parseResults['fromConstraints'][$table]) ? $table . ($table != $alias ? ' ' . $alias : '') : $parseResults['fromConstraints'][$table];
$started = TRUE;
}
$query .= $parseResults['constraint'] ? ' WHERE ' . $parseResults['constraint'] : '';
if ($includeOrderConstraint) { $query .= $parseResults['orderConstraint'] ? ' ' . $parseResults['orderConstraint'] : ''; }
return $query;
}
// }}}
// {{{ unconvertBoolean()
/**
* Unconverts a boolean value from a database boolean data type column. if
* the $bool value equals (===) any of the #_boolTrueVals or #_boolFalseVals
* values for this database, the corresponding boolean value will be
* returned, otherwise, NULL will be returned. this method can be overriden
* by the corresponding db implementation
*
* @param boolean $bool boolean value to convert
* @access public
* @return boolean
*/
function unconvertBoolean($bool) {
foreach ($this->_boolTrueVals as $val) {
if ($bool === $val) {
return TRUE;
}
}
foreach ($this->_boolFalseVals as $val) {
if ($bool === $val) {
return FALSE;
}
}
return NULL;
}
// }}}
// {{{ _openConn()
/**
* This method is used to open one connection to a database server. It
* is called by the SRA_Database parent class in order to open needed
* database connections. It returns either a connection object (if
* successful) or an SRA_Error object if not.
*
* @param array $config the configuration parameters for the
* database server to be connected to. This array will/must contain
* the following values:
*
* 'server' => IP address or resolvable name of the server.
* 'port' => The database server port to use
* 'name' => The name of the database
* 'user' => The authentication user name
* 'password' => The authentication password
* 'type' => The database type
*
* @access protected
* @return object
*/
function _openConn($config)
{
// SRA_Error.
$msg = "SRA_Database::_openConn(): This method is abstract.";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// }}}
// {{{ processCommit()
/**
* This method is simliar in functionality to the
* SRA_Database::processUpdate method. It is called by the
* SRA_Database*::commit method in order to process all SRA_Database commits
* (from the current transaction). To accomplish this, this method
* simply calls the SRA_Database*::commit method once for every
* replication server. If any of the commits fail, the entire
* _queryBuffer is written to a buffer file for that database server
* for future processing.
*
* @access public
* @return void
*/
function processCommit()
{
// Step 2:
// See SRA_Database*::commit() for steps.
if (!$this->_inTransaction)
{
return(SRA_Error::logError("SRA_Database::processCommit: Failed - Cannot commit, no transaction is in process.",
__FILE__, __LINE__));
}
// Get the connection.
$conn = $this->_getAppDbConnection();
if (SRA_Error::isError($conn))
{
// SRA_Error.
$msg = "SRA_Database::processCommit() Failed to _getAppDbConnection().";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// Call $this->commit() with a connection parameter.
$result = $this->commit($conn);
if (SRA_Error::isError($result))
{
// SRA_Error.
$msg = "SRA_Database::processCommit() SRA_Error returned from commit().";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
$this->_inTransaction=FALSE;
// Returning!!!
return;
}
// }}}
// {{{ processNextSequence()
/**
* This method exists only in the SRA_Database class. It is used by the child
* classes to distribute and process any sequence queries (queries to retrieve
* a table sequence). The flow of this process is detailed in the
* SRA_Database::getNextSequence api. Basically, this is the method that manages
* these types of calls. This method is necessary in order to implement database
* replication. This method is simply the gateway between the initial
* SRA_Database*::getNextSequence method and the actual call to run the next sequence
* query. SRA_Database*::getNextSequence.
*
* @param string $sequence the name of the sequence to return the next value for.
* @param int $errorLevel defines the error level of the SRA_Error object that should
* will be created if the db query fails. This value may be set to SRA_ERROR_OPERATIONAL
* if you do not wish for the error to be logged.
* @access protected
* @return void
*/
function processNextSequence($sequence, $errorLevel)
{
// Get the connection.
$conn = $this->_getAppDbConnection("INSERT query");
if (SRA_Error::isError($conn))
{
// SRA_Error.
$msg = "SRA_Database::processNextSequence: Failed to _getAppDbConnection().";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// Call $this->getNextSequence() with a connection parameter.
$sequence = $this->getNextSequence($sequence, $errorLevel, $conn);
if (SRA_Error::isError($sequence))
{
// SRA_Error.
$msg = "SRA_Database::processNextSequence: SRA_Error returned from getNextSequence().";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
return $sequence;
}
// }}}
// {{{ processRollback()
/**
* This method is simliar in functionality to the
* SRA_Database::processUpdate method. It is called by the
* SRA_Database*::rollback method in order to process all SRA_Database
* rollbacks (from the current transaction). To accomplish this, this
* method simply calls the SRA_Database*::rollback method once for every
* replication server.
*
* @access protected
* @return void
*/
function processRollback()
{
// Step 2:
// See SRA_Database*::rollback() for steps.
if (!$this->_inTransaction)
{
return(SRA_Error::logError("SRA_Database::processRollback: Failed - Cannot commit, no transaction is in process.",
__FILE__, __LINE__));
}
// Get the connection.
$conn = $this->_getAppDbConnection();
if (SRA_Error::isError($conn))
{
// SRA_Error.
$msg = "SRA_Database::processRollback() Failed to _getAppDbConnection().";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// Call $this->startTransaction() with a connection parameter.
$result = $this->rollback($conn);
if (SRA_Error::isError($result))
{
// SRA_Error.
$msg = "SRA_Database::processRollback() SRA_Error returned from rollback().";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
$this->_inTransaction=FALSE;
// Returning!!!
return;
}
// }}}
// {{{ processUpdate()
/**
* This method exists only in the SRA_Database class. It is used by the
* child classes to distribute and process any update queries
* (INSERT/UPDATE/DELETE queries). The flow of this process is
* detailed in the SRA_Database::execute api. Basically, this is the
* method that manages any database updates. This method is necessary
* in order to implement database replication. This method is simply
* the gateway between the initial SRA_Database*::execute method and the
* actual call to execute a query. SRA_Database*::execute calls
* SRA_Database::processUpdate which calls SRA_Database*::execute.
*
* @param string $query the query to execute.
* @param string $incCol if the query is an insert query, and a db managed
* auto-incremental column is being used by the table being inserted into,
* and this value is needed by the Object calling the method, this value
* will correspond with the name of the auto-incremental column.
* @param int $errorLevel defines the error level of the SRA_Error object that should
* will be created if the db query fails. This value may be set to SRA_ERROR_OPERATIONAL
* if you do not wish for the error to be logged.
* @access protected
* @return SRA_ExecuteSet
*/
function &processUpdate($query, $incCol, $errorLevel)
{
// Step 2:
// See SRA_Database*::execute() for steps.
// Get the connection.
$conn = $this->_getAppDbConnection($query);
if (SRA_Error::isError($conn))
{
// SRA_Error.
$msg = "SRA_Database::processUpdate() Failed to _getAppDbConnection().";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// Call $this->execute() with a connection parameter.
$execute_set = $this->execute($query, $incCol, $errorLevel, $conn);
if (SRA_Error::isError($execute_set))
{
// SRA_Error.
$msg = "SRA_Database::processUpdate() SRA_Error returned from execute().";
return(SRA_Error::logError($msg, __FILE__, __LINE__, $errorLevel));
}
return($execute_set);
}
// }}}
// {{{ recordCount()
/**
* Returns the # of records that exist in a given database table for a
* given criteria
*
* @param SRA_Database $db The SRA_Database instance to query
* @param string $table the name of the table
* @param array $vals an associative array of column/value pairs to check.
* all of the values in this array must be sql ready. if this parameter is
* not specified then the return value will be the # of all of the records
* in that database table
* @param string $constraint an additional query constraint to apply (for
* example: TYPE='1')
* @access public
* @return int
*/
function recordCount(& $db, $table, $vals = FALSE, $constraint = FALSE) {
if (!SRA_Database::isValid($db)) {
$msg = "SRA_Database::recordCount: Failed - db parameter is not a valid SRA_Database object";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
if (!$table) {
$msg = "SRA_Database::recordCount: Failed - table parameter was not specified";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
$sql = "SELECT COUNT(*) FROM ${table}";
if (is_array($vals)) {
$started = FALSE;
foreach ($vals as $column => $val) {
if ($started) {
$sql .= ' AND ';
}
else {
$sql .= ' WHERE ';
}
$sql .= "${column} = ${val}";
$started = TRUE;
}
}
if ($constraint) {
if ($started) {
$sql .= ' AND ';
}
else {
$sql .= ' WHERE ';
}
$sql .= " ${constraint}";
$started = TRUE;
}
if (SRA_Error::isError($results =& $db->fetch($sql, array(SRA_DATA_TYPE_INT)))) {
return $results;
}
$row =& $results->next();
return $row[0];
}
// }}}
// {{{ rollback()
/**
* Abstract method that cancels any database changes done during a
* transaction that is in progress. This method must be implemented by
* the child SRA_Database* classes. This method returns the
* SRA_Database::processRollback method is the conn parameter is not
* specified.
*
* @param object $conn the database connection object to rollback a
* transaction for. If null (default) this method will simply return
* SRA_Database::processRollback. Otherwise it will attempt to rollback
* the transaction using the specified connection.
* @access public
* @return void
*/
function rollback($conn=NULL)
{
// SRA_Error.
$msg = "SRA_Database::rollback(): This method is abstract.";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// }}}
// {{{ startTransaction()
/**
* This method will start a new transaction for the current database
* connections. Since this action is database specific, this is an
* abstract method that must be implemented by the SRA_Database* child
* classes. One important element in this method is that, similiar to
* the SRA_Database*::execute/SRA_Database::processUpdate methods, this is a
* pass up - pass down query. This means that the SRA_Database* method
* will initially be called (with no conn parameter specified). This
* method will then simply call (and return) the
* SRA_Database::startTransactions method (which in turn will call the
* SRA_Database*::startTransaction method with the conn parameter
* specified for each of the replication servers).
*
* This method MUST set the _inTransaction flag to TRUE
*
* @param object $conn the database connection object to start the
* transaction for. If not specified this method will simply return
* the SRA_Database(parent)::startTransactions method (which will in turn
* call this method for all of the replication servers).
* @access public
* @return void
*/
function startTransaction($conn=NULL)
{
// SRA_Error.
$msg = "SRA_Database::startTransaction(): This method is abstract.";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// }}}
// {{{ startTransactions()
/**
* This method is the gateway for a child SRA_Database* object to be able
* to start a transaction. Because the SRA_Database object manages
* replication, all transactions (which imply update queries) must
* pass through all of the replcation servers. Hence, it is necessary
* to start a transaction on all of the database servers whenever a
* transaction is needed. This is accomplished by this method simply
* calling the SRA_Database::startTransaction method for each of the
* replication servers. See the SRA_Database::startTransaction api for
* more info. This method also rollsback any existing transaction.
*
* @access protected
* @return void
*/
function startTransactions()
{
// Step 2:
// See SRA_Database*::startTransaction() for steps.
if ($this->_inTransaction)
{
return(SRA_Error::logError("SRA_Database::startTransaction: Failed - Transaction cannot be started. One is already in progress.",
__FILE__, __LINE__));
}
// Get the connection.
$conn = $this->_getAppDbConnection();
if (SRA_Error::isError($conn))
{
// SRA_Error.
$msg = "SRA_Database::startTransactions() Failed to _getAppDbConnection().";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
// Call $this->startTransaction() with a connection parameter.
$result = $this->startTransaction($conn);
if (SRA_Error::isError($result))
{
// SRA_Error.
$msg = "SRA_Database::startTransactions() SRA_Error returned from startTransaction().";
return(SRA_Error::logError($msg, __FILE__, __LINE__));
}
$this->_inTransaction=TRUE;
return;
}
// }}}
// {{{ _fetchInCache()
/**
* This method is used to determine whether or not cache exists for a given
* query based on the database "table-cache" configuration element
* (see configuration description for more information)
*
* @param string $query the query
* @access protected
* @return SRA_ResultSet (if cache exists) or FALSE otherwise
*/
function & _fetchInCache($query)
{
// only check if in memory cache does not exist
if (!array_key_exists($query, $this->_fetchCache)) {
$this->_fetchCache[$query] = FALSE;
// cache parameters exist
if ($params =& $this->_getFetchCacheParams($query)) {
if (file_exists($params['file']) && ($params['expire'] == 0 || (fileMTime($params['file']) + ($param['expire']*60)) >= time())) {
// cache found
SRA_Util::printDebug("SRA_Database::_fetchInCache - Cache exist for query $query current time: " . time() . ", expire time: " . (fileMTime($params['file']) + ($param['expire']*60)), SRA_DB_DEBUG, __FILE__, __LINE__);
$this->_fetchCache[$query] = unserialize(SRA_File::tostring($params['file']));
}
else if (isset($params['file']) && isset($param['expire']) && (fileMTime($params['file']) + (((int) $param['expire'])*60)) < time()) {
SRA_Util::printDebug("SRA_Database::_fetchInCache - Cache is expired for query $query", SRA_DB_DEBUG, __FILE__, __LINE__);
}
else {
SRA_Util::printDebug("SRA_Database::_fetchInCache - Cache does not exist for query $query", SRA_DB_DEBUG, __FILE__, __LINE__);
}
}
else {
SRA_Util::printDebug("SRA_Database::_fetchInCache - Cache parameters not defined for query $query", SRA_DB_DEBUG, __FILE__, __LINE__);
}
}
else {
SRA_Util::printDebug("SRA_Database::_fetchInCache - Memory cache exists for query $query", SRA_DB_DEBUG, __FILE__, __LINE__);
}
// reset SRA_ResultSet
if (SRA_ResultSet::isValid($this->_fetchCache[$query])) {
$this->_fetchCache[$query]->reset();
}
return $this->_fetchCache[$query];
}
// }}}
// {{{ _addFetchToCache()
/**
* This method is used to write the results of a fetch to cache (if cache
* should be written at all)
*
* @param string $query the query
* @param SRA_ResultSet $results the results of the query
* @access protected
* @return void
*/
function _addFetchToCache($query, & $results)
{
// cache parameters exist
if (!$this->_fetchCache[$query] && ($params =& $this->_getFetchCacheParams($query))) {
$fp = fopen($params['file'], 'w');
fwrite($fp, serialize($results));
fclose($fp);
$this->_fetchCache[$query] =& $results;
SRA_Util::printDebug("SRA_Database::_addFetchToCache - Added cache for query $query", SRA_DB_DEBUG, __FILE__, __LINE__);
}
}
// }}}
// {{{ _getFetchCacheFileName()
/**
* This method returns the cache parameters for a given query
*
* @param string $query the query
* @access private
* @return mixed
*/
function & _getFetchCacheParams($query)
{
static $cacheParams = array();
if (!array_key_exists($query, $cacheParams)) {
$cacheParams[$query] = FALSE;
// determine which table is being queried
$tmp = explode(' ', $query);
$tables = array();
foreach ($tmp as $piece) {
if ($next && !(trim(strtolower($piece)) == 'where' || trim(strtolower($piece)) == '')) {
$tables[] = trim($piece);
}
else if ($next) {
break;
}
if (trim(strtolower($piece)) == 'from') {
$next = TRUE;
}
}
sort($tables);
$key = trim(implode(' ', $tables));
SRA_Util::printDebug("SRA_Database::_getFetchCacheParams - Looking for key: $key", SRA_DB_DEBUG, __FILE__, __LINE__);
// cache parameters have been defined
if (count($tables) && $this->_config['table-cache'][$key]) {
$dir = SRA_DIR . '/tmp/';
if ($this->_config['table-cache'][$key]['attributes']['dir']) {
$dir = $this->_config['table-cache'][$key]['attributes']['dir'];
}
$expire = $this->_config['table-cache'][$key]['attributes']['expire'];
$fileName = str_replace('<', '', str_replace('=', '', str_replace('>', '', str_replace('from', '', str_replace('select', '', str_replace('?', '', str_replace('|', '', str_replace('%', '', str_replace('/', '', str_replace('"', '', str_replace("'", '', str_replace(',', '', str_replace(';', '', str_replace('*', '', str_replace(')', '', str_replace('(', '', str_replace(' ', '', $query)))))))))))))))));
if (strlen($fileName) <=255 && strlen($fileName) > 0) {
SRA_Util::printDebug("SRA_Database::_getFetchCacheParams - Cache parameters set for key $key, file ${dir}${fileName}, expire $expire, query $query", SRA_DB_DEBUG, __FILE__, __LINE__);
$cacheParams[$query] = array('file' => $dir . $fileName, 'expire' => $expire);
}
}
}
return $cacheParams[$query];
}
// }}}
// {{{ getBooleanArray()
/**
* returns an array of possible boolean values based on the string specified
*
* @param string $str the string
* @access public static
* @return array
*/
function getBooleanArray($str) {
$vals = array();
$pieces = explode(' ', $str);
foreach ($pieces as $piece) {
// string
if (strstr($piece, "'")) {
$vals[] = str_replace("'", '', $piece);
}
else {
if (is_numeric($piece)) {
$vals[] = $piece * 1;
}
else {
$vals[] = constant($piece);
}
}
}
return $vals;
}
// }}}
// {{{ getDatabase
/**
* singleton method for this class
*
* @param array $config The database config array. See the api for the
* SRA_Database::_config attribute for more info.
* @access public static
* @return SRA_Database
*/
function & getDatabase($configs) {
// Check to make sure $configs is an array.
if (!is_array($configs)) {
$msg = "SRA_Database::getDatabase: Failed - Passed 'configs' parameter in not an array";
return SRA_Error::logError($msg, __FILE__, __LINE__);
}
// Check to make sure $configs has all of the needed elements.
if (!isset($configs['type'])) {
$msg = "SRA_Database::getDatabase: Failed - configs array doesn't contain a 'type' element";
return SRA_Error::logError($msg, __FILE__, __LINE__);
}
if (!isset($configs['host'])) {
$configs['host'] = SRA_DB_DEFAULT_HOST;
}
// switch on type.
switch ($configs['type']) {
case SRA_DB_TYPE_POSTGRESQL :
include_once(SRA_LIB_DIR . '/sql/SRA_DatabasePostgreSql.php');
$db = new SRA_DatabasePostgreSql();
break;
case SRA_DB_TYPE_MSSQL :
include_once(SRA_LIB_DIR . '/sql/SRA_DatabaseMsSql.php');
$db = new SRA_DatabaseMsSql();
break;
case SRA_DB_TYPE_SQLITE :
include_once(SRA_LIB_DIR . '/sql/SRA_DatabaseSqLite.php');
$db = new SRA_DatabaseSqLite();
break;
default:
include_once(SRA_LIB_DIR . '/sql/SRA_DatabaseMySql.php');
$db = new SRA_DatabaseMySql();
break;
}
// Now set all of the properties.
$db->_config = $configs;
if (isset($configs['gmt'])) {
$db->_timeZone =& SRA_TimeZone::getTimeZone(SRA_TIME_ZONE_GMT);
}
else {
$db->_timeZone =& SRA_Controller::getAppTimeZone();
}
$booleanFalse = SRA_DB_BOOL_FALSE_VALS;
$booleanTrue = SRA_DB_BOOL_TRUE_VALS;
if (isset($configs['bool-false'])) {
$booleanFalse = $configs['bool-false'];
}
if (isset($configs['bool-true'])) {
$booleanTrue = $configs['bool-true'];
}
$db->_boolFalseVals = SRA_Database::getBooleanArray($booleanFalse);
$db->_boolTrueVals = SRA_Database::getBooleanArray($booleanTrue);
$db->_boolFalse = SRA_DB_BOOL_FALSE;
$db->_boolTrue = SRA_DB_BOOL_TRUE;
if (isset($configs['bool-false-rep'])) {
$tmp = SRA_Database::getBooleanArray($configs['bool-false-rep']);
if (count($tmp)) {
$db->_boolFalse = $tmp[0];
}
}
if (isset($configs['bool-true-rep'])) {
$tmp = SRA_Database::getBooleanArray($configs['bool-true-rep']);
if (count($tmp)) {
$db->_boolTrue = $tmp[0];
}
}
$db->_inTransaction = FALSE;
return $db;
}
// }}}
}
// }}}
?>