Project

General

Profile

Bug #3052 » cb.database.php

krileon, 30 November 2011 20:35

 
<?php
/**
* @version $Id: cb.database.php 1631 2011-11-02 22:02:46Z beat $
* @package Community Builder
* @subpackage cb.database.php
* @author Beat and various
* @copyright (C) Beat and various, www.joomlapolis.com
* @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU/GPL version 2
*/

// no direct access
if ( ! ( defined( '_VALID_CB' ) || defined( '_JEXEC' ) || defined( '_VALID_MOS' ) ) ) { die( 'Direct Access to this location is not allowed.' ); }


/* MAMBO 4.5.2.3 FIXES + EXTENSIONS: */

/**
* Corrects bugs in mambo core database class and implements independant CB database layer ! :
* 1) NULL values from SQL tables are not loaded !
* 2) updateOrder method is buggy and does not allow to specify modified row ids to force them into the right position !
*/
class comprofilerDBTable {
var $_tbl;
var $_tbl_key;
/** Database object:
* @var CBDatabase */
var $_db;
var $_error = '';

/**
* Constructor to set table and key field
* Can be overloaded/supplemented by the child class
*
* @param string $table name of the table in the db schema relating to child class
* @param string $key name of the primary key field in the table
* @param CBdatabase $db CB Database object
*/
function comprofilerDBTable( $table, $key, &$db ) {
$this->_tbl = $table;
$this->_tbl_key = $key;
$this->_db =& $db;
}
/**
* Binds an array/hash from database to this object
*
* @param int $oid optional argument, if not specifed then the value of current key is used
* @return mixed any result from the database operation
*/
function load( $oid = null ) {
$k = $this->_tbl_key;
if ($oid !== null) {
$this->$k = $oid;
}
$oid = $this->$k;
if ($oid === null) {
return false;
}
//BB fix : resets default values to all object variables, because NULL SQL fields do not overide existing variables !
//Note: Prior to PHP 4.2.0, Uninitialized class variables will not be reported by get_class_vars().
$class_vars = get_class_vars(get_class($this));
foreach ($class_vars as $name => $value) {
if ( ($name != $k) and ($name != "_db") and ($name != "_tbl") and ($name != "_tbl_key") and ( substr( $name, 0 , 10 ) != "_history__" ) ) {
$this->$name = $value;
}
}
$this->reset();
//end of BB fix.

$query = "SELECT *"
. "\n FROM " . $this->_db->NameQuote( $this->_tbl )
. "\n WHERE " . $this->_db->NameQuote( $this->_tbl_key ) . " = " . $this->_db->Quote( $oid )
;
$this->_db->setQuery( $query );
return $this->_db->loadObject( $this );
}
/**
* If table key (id) is NULL : inserts a new row
* otherwise updates existing row in the database table
*
* Can be overridden or overloaded by the child class
*
* @param boolean $updateNulls TRUE: null object variables are also updated, FALSE: not.
* @return boolean TRUE if successful otherwise FALSE
*/
function store( $updateNulls = false ) {
$k = $this->_tbl_key;
if ( $this->$k != null ) {
$ok = $this->_db->updateObject( $this->_tbl, $this, $this->_tbl_key, $updateNulls );
} else {
$ok = $this->_db->insertObject( $this->_tbl, $this, $this->_tbl_key );
}

if ( ! $ok ) {
$this->_error = strtolower(get_class($this))."::store failed: " . $this->_db->getErrorMsg();
}
return $ok;
}
/**
* @param string $where This is expected to be a valid (and safe!) SQL expression
*/
function move( $dirn, $where = '', $ordering = 'ordering' ) {
$k = $this->_tbl_key;

$sql = "SELECT $this->_tbl_key, $ordering FROM $this->_tbl";

if ($dirn < 0) {
$sql .= "\n WHERE $ordering < " . (int) $this->$ordering;
$sql .= ($where ? "\n AND $where" : '');
$sql .= "\n ORDER BY $ordering DESC";
} else if ($dirn > 0) {
$sql .= "\n WHERE $ordering > " . (int) $this->$ordering;
$sql .= ($where ? "\n AND $where" : '');
$sql .= "\n ORDER BY $ordering";
} else {
$sql .= "\nWHERE $ordering = " . (int) $this->$ordering;
$sql .= ($where ? "\n AND $where" : '');
$sql .= "\n ORDER BY $ordering";
}

$this->_db->setQuery( $sql, 0, 1 );

$row = null;
if ($this->_db->loadObject( $row )) {
$query = "UPDATE $this->_tbl"
. "\n SET $ordering = " . (int) $row->$ordering
. "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k )
;
$this->_db->setQuery( $query );

if (!$this->_db->query()) {
$err = $this->_db->getErrorMsg();
die( $err );
}

$query = "UPDATE $this->_tbl"
. "\n SET $ordering = " . (int) $this->$ordering
. "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $row->$k )
;
$this->_db->setQuery( $query );

if (!$this->_db->query()) {
$err = $this->_db->getErrorMsg();
die( $err );
}

$this->$ordering = $row->$ordering;
} else {
$query = "UPDATE $this->_tbl"
. "\n SET $ordering = " . (int) $this->$ordering
. "\n WHERE $this->_tbl_key = " . $this->_db->Quote( $this->$k )
;
$this->_db->setQuery( $query );

if (!$this->_db->query()) {
$err = $this->_db->getErrorMsg();
die( $err );
}
}
}

/**
* Private utility method for updateOrder() back-called by usort() for comparing orderings
*/
function _cmp_obj($a, $b) {
$k = $this->_cbc_cbc_ordering_tmp;
if ( $a->$k == $b->$k ) {
return 0;
}
return ( $a->$k > $b->$k ) ? +1 : -1;
}
/**
* Compacts the ordering sequence of the selected records
*
* @param string $where Additional where query to limit ordering to a particular subset of records
* @param array $cids of table key ids which should preserve their position (in addition of the negative positions)
* @param string $ordering name of ordering column in table
* @return boolean TRUE success, FALSE failed, with error of database updated.
*/
function updateOrder( $where = '' , $cids = null, $ordering = 'ordering' ) {
$k = $this->_tbl_key;

if (!array_key_exists( $ordering, get_class_vars( strtolower(get_class( $this )) ) )) {
$this->_error = "WARNING: ".strtolower(get_class( $this ))." does not support ordering field" . $ordering . ".";
return false;
}

if ($this->_tbl == "#__content_frontpage") {
$order2 = ", content_id DESC";
} else {
$order2 = "";
}

$this->_db->setQuery( "SELECT $this->_tbl_key, $ordering FROM $this->_tbl"
. ($where ? "\nWHERE $where" : '')
. "\nORDER BY " . $ordering . $order2
);

if (!($orders = $this->_db->loadObjectList())) {
$this->_error = $this->_db->getErrorMsg();
return false;
}

$n=count( $orders );
$iOfThis = null;
if($cids !== null) {
$cidsOrderings = array(); // determine list of reserved/changed ordering numbers
for ($i=0; $i < $n; $i++) {
if (in_array($orders[$i]->$k, $cids)) {
$cidsOrderings[$orders[$i]->$k] = $orders[$i]->$ordering;
}
}

$j = 1; // change ordering numbers outside of reserved and negative ordering numbers list
for ($i=0; $i < $n; $i++) {
if ($orders[$i]->$k == $this->$k) {
// place 'this' record in the desired location at the end !
$iOfThis = $i;
if ($orders[$i]->$ordering == $j) {
$j++;
}
} else if (in_array($orders[$i]->$k, $cids)) {
if ($orders[$i]->$ordering == $j) {
$j++;
}
} else {
if ($orders[$i]->$ordering >= 0) {
$orders[$i]->$ordering = $j++;
}
while (in_array($orders[$i]->$ordering, $cidsOrderings)) {
$orders[$i]->$ordering = $j++;
}
}
}
} else {
$j = 1;
for ($i=0; $i < $n; $i++) {
if ($orders[$i]->$k == $this->$k) {
// place 'this' record in the desired location at the end !
$iOfThis = $i;
if ($orders[$i]->$ordering == $j) {
$j++;
}
} else if ($orders[$i]->$ordering != $this->$ordering && $this->$ordering > 0 && $orders[$i]->$ordering >= 0) {
$orders[$i]->$ordering = $j++;
} else if ($orders[$i]->$ordering == $this->$ordering && $this->$ordering > 0 && $orders[$i]->$ordering >= 0) {
if ($orders[$i]->$ordering == $j) {
$j++;
}
$orders[$i]->$ordering = $j++;
}
}
}
if ($iOfThis !== null) {
$orders[$iOfThis]->$ordering = min( $this->$ordering, $j );
}
// sort entries by ->$ordering:
$this->_cbc_cbc_ordering_tmp = $ordering;
usort($orders, array( $this, "_cmp_obj" ));
unset( $this->_cbc_cbc_ordering_tmp );

// compact ordering:
$j = 1;
for ($i=0; $i < $n; $i++) {
if ($orders[$i]->$ordering >= 0) {
$orders[$i]->$ordering = $j++;
}
}

for ($i=0; $i < $n; $i++) {
if (($orders[$i]->$ordering >= 0) or ($orders[$i]->$k == $this->$k)) {
$this->_db->setQuery( "UPDATE $this->_tbl"
. "\nSET $ordering='".$orders[$i]->$ordering."' WHERE $k='".$orders[$i]->$k."'"
);
$this->_db->query();
}
}

// if we didn't find to reorder the current record, make it last
if (($iOfThis === null) && ($this->$ordering > 0)) {
$order = $n+1;
$this->_db->setQuery( "UPDATE $this->_tbl"
. "\nSET $ordering='$order' WHERE $k='".$this->$k."'"
);
$this->_db->query();
}
return true;
}

/**
* Resets public properties
*
* @param mixed $value The value to set all properties to, default is null
*/
function reset( $value=null ) {
$keys = $this->getPublicProperties();
foreach ( $keys as $k ) {
$this->$k = $value;
}
}
/**
* Gets the value of the class variable
*
* @param string $var The name of the class variable
* @return mixed The value of the class var (or null if no var of that name exists)
*/
function get( $var ) {
if ( isset( $this->$var ) ) {
return $this->$var;
} else {
return null;
}
}
/**
* Sets the new value of the class variable
*
* @param string $var The name of the class variable
* @param mixed $newVal The new value to assign to the variable
*/
function set( $var, $newVal ) {
$this->$var = $newVal;
}
/**
* Returns an array of public properties
*
* @return array
*/
function getPublicProperties() {
static $keys = null;

if ( $keys === null ) {
$keys = array();
foreach ( array_keys( get_class_vars( get_class( $this ) ) ) as $k ) {
if (substr( $k, 0, 1 ) != '_') {
$keys[] = $k;
}
}
}
return $keys;
}
/**
* Generic check for whether dependancies exist for this object in the db schema
* OVERRIDE !
*
* @param int $oid key index
* @return boolean
*/
function canDelete( $oid = null ) {
return true;
}
/**
* Deletes this record (no checks)
*
* @param int $oid Key id of row to delete (otherwise it's the one of $this)
* @return boolean TRUE if OK, FALSE if error
*/
function delete( $oid = null ) {
$k = $this->_tbl_key;
if ( $oid ) {
$this->$k = (int) $oid;
}

$query = "DELETE FROM " . $this->_db->NameQuote( $this->_tbl )
. "\n WHERE " . $this->_db->NameQuote( $this->_tbl_key )
. " = "
. ( is_int( $this->$k ) ? (int) $this->$k : $this->_db->Quote( $this->$k ) )
;
$this->_db->setQuery( $query );

if ($this->_db->query()) {
return true;
} else {
$this->_error = $this->_db->getErrorMsg();
return false;
}
}

/**
* Tests if item is checked out
* @param int A user id
* @return boolean
*/
function isCheckedOut( $user_id = 0 ) {
if ( $user_id ) {
return ( $this->checked_out && ( $this->checked_out != $user_id ) );
} else {
return $this->checked_out;
}
}

/**
* Checkout object from database
*
* @param int $who
* @param int $oid
* @return unknown
*/
function checkout( $who, $oid = null ) {
if ( ! array_key_exists( 'checked_out', get_class_vars( strtolower( get_class( $this ) ) ) ) ) {
$this->_error = "WARNING: " . strtolower( get_class( $this ) ) . " does not support checkouts.";
return false;
}

$k = $this->_tbl_key;
if ( $oid !== null ) {
$this->$k = $oid;
}
$time = date( "Y-m-d H:i:s" );
$query = "UPDATE " . $this->_db->NameQuote( $this->_tbl )
. "\n SET checked_out = " . (int) $who . ", checked_out_time = " . $this->_db->Quote( $time )
. "\n WHERE " . $this->_db->NameQuote( $this->_tbl_key ) . " = " . $this->_db->Quote( $this->$k )
;
$this->_db->setQuery( $query );
return $this->_db->query();
}

function checkin( $oid = null ) {
if ( ! array_key_exists( 'checked_out', get_class_vars( strtolower( get_class( $this ) ) ) ) ) {
$this->_error = "WARNING: " . strtolower( get_class( $this ) ) . " does not support checkins.";
return false;
}
$k = $this->_tbl_key;
if ( $oid !== null ) {
$this->$k = $oid;
}
$query = "UPDATE " . $this->_db->NameQuote( $this->_tbl )
. "\n SET checked_out = 0, checked_out_time = " . $this->_db->Quote( $this->_db->getNullDate() )
. "\n WHERE " . $this->_db->NameQuote( $this->_tbl_key ) . " = " . $this->_db->Quote( $this->$k )
;
$this->_db->setQuery( $query );
return $this->_db->query();
}

// EXTENSIONS: EXPERIMENTAL IN CB 1.2, NOT PART OF API:
/**
* Loads an array of typed objects of a given class (same class as current object by default)
* which inherit from this class.
* @access private
*
* @param string $class [optional] class name
* @param string $key [optional] key name in db to use as key of array
* @param array $additionalVars [optional] array of string additional key names to add as vars to object
* @return array of objects of the same class (empty array if no objects)
*/
function & loadTrueObjects( $class = null, $key = "", $additionalVars = null ) {
if ( $additionalVars === null ) {
$additionalVars = array();
}
$objectsArray = array();
$resultsArray = $this->_db->loadAssocList( $key );
if ( is_array($resultsArray) ) {
if ( $class == null ) {
$class = get_class($this);
}
foreach ( $resultsArray as $k => $value ) {
$objectsArray[$k] = new $class( $this->_db );
// mosBindArrayToObject( $value, $objectsArray[$k], null, null, false );
$objectsArray[$k]->bind( $value, null, null, false );
foreach ( $additionalVars as $index ) {
if ( array_key_exists( $index, $value ) ) {
$objectsArray[$k]->$index = $value[$index];
}
}
}
}
return $objectsArray;
}
/**
* Check values before store method (override if needed)
* @return boolean TRUE if the object is safe for saving
*/
function check( ) {
return true;
}
/**
* Copy the named array or object content into this object as vars
* only existing vars of object are filled.
* When undefined in array, object variables are kept.
*
* WARNING: DOES addslashes / escape BY DEFAULT
*
* Can be overridden or overloaded.
*
* @param array|object $array The input array or object
* @param string $ignore Fields to ignore
* @param string $prefix Prefix for the array keys
* @param boolean $checkSlashes TRUE: if magic_quotes are ON, remove slashes (TRUE BY DEFAULT !)
* @return boolean TRUE: ok, FALSE: error on array binding
*/
function bind( $array, $ignore='', $prefix = null, $checkSlashes = true ) {
if ( is_array( $array ) || is_object( $array ) ) {
$ignore = ' ' . $ignore . ' ';
foreach ( get_object_vars( $this ) as $k => $v ) {
if( substr( $k, 0, 1 ) != '_' ) {
if ( strpos( $ignore, ' ' . $k . ' ') === false) {
$ak = $prefix . $k;
if ( is_array( $array ) && isset( $array[$ak] ) ) {
$this->$k = ( ( $checkSlashes && get_magic_quotes_gpc() ) ? cbStripslashes( $array[$ak] ) : $array[$ak] );
} elseif ( isset( $array->$ak ) ) {
$this->$k = ( ( $checkSlashes && get_magic_quotes_gpc() ) ? cbStripslashes( $array->$ak ) : $array->$ak );
}
}
}
}
} else {
$this->_error = get_class( $this ) . "::bind failed: not an array.";
return false;
}
return true;
}
/**
* @return string Returns the error message
*/
function getError() {
return $this->_error;
}
} // end class comprofilerDBTable

/**
* Provides CMS database independance and
* Corrects bugs and backwards compatibility issues in mambo core database class ! :
* 1) empty lists return empty arrays and not NULL values !
* 2) gives a coherent interface to CB, independant of various CMS flavors
*/
class CBdatabase {
/** Host CMS database class
* @var database */
var $_db;
/* @var string Holds database prefix replacer (replacing the $prefix (default '#__')). */
var $_table_prefix = '';

/**
* Database object constructor
*/
function CBdatabase( &$_CB_database ) {
$this->_db =& $_CB_database;
if ( isset( $_CB_database->_table_prefix ) ) {
$this->_table_prefix = $_CB_database->_table_prefix;
} else {
global $_CB_framework;
$this->_table_prefix = $_CB_framework->getCfg( 'dbprefix' );
}
}
/**
* Sets debug level
* @param int
*/
function debug( $level ) {
$this->_db->debug( $level );
}
/**
* @return int The error number for the most recent query
*/
function getErrorNum( ) {
return $this->_db->getErrorNum();
}
/**
* @return string The error message for the most recent query
*/
function getErrorMsg( ) {
return stripslashes( $this->_db->getErrorMsg() );
}
/**
* @param int $errorNum The error number for the most recent query
*/
function setErrorNum( $errorNum) {
if ( checkJversion() < 2 ) {
// in J1.6, this is protected:
$this->_db->_errorNum = $errorNum;
}
}
/**
* @param string $errorMsg The error message for the most recent query
*/
function setErrorMsg( $errorMsg ) {
if ( checkJversion() < 2 ) {
// in J1.6, this is protected:
$this->_db->_errorMsg = $errorMsg;
}
}
/**
* Get a database escaped string. For LIKE statemends: $db->Quote( $db->getEscaped( $text, true ) . '%', false )
*
* @param string $text
* @param boolean $escapeForLike : escape also % and _ wildcards for LIKE statements with % or _ in search strings (since CB 1.2.3)
* @return string
*/
function getEscaped( $text, $escapeForLike = false ) {
if ( $escapeForLike ) {
return str_replace(array('%','_'),array("\\%","\\_"), $this->_db->getEscaped( $text ) );
} else {
return $this->_db->getEscaped( $text );
}
}
/**
* Get a quoted database escaped string
*
* @param string $text
* @param boolean $escape
* @return string
*/
function Quote( $text, $escape = true ) {
return '\'' . ( $escape ? $this->_db->getEscaped( $text ) : $text ) . '\'';
}
/**
* Quote an identifier name (field, table, etc)
*
* @param string $s The name
* @return string The quoted name
*/
function NameQuote( $s ) {
return '`' . $s . '`';
}
/**
* Returns the zero date/time
*
* @param string $dateTime 'datetime', 'date', 'time'
* @return string Quoted null/zero date string
*/
function getNullDate( $dateTime = 'datetime' ) {
if ( $dateTime == 'datetime' ) {
return '0000-00-00 00:00:00';
} elseif ( $dateTime == 'date' ) {
return '0000-00-00';
} else {
return '00:00:00';
}
}
/**
* Sets the SQL query string for later execution.
*
* This function replaces a string identifier $prefix with the
* string held is the $this->getPrefix() class variable.
*
* @param string $sql The SQL query (casted to (string) )
* @param int $offset The offset to start selection
* @param int $limit The number of results to return
* @param string $prefix The common table prefix search for replacement string
*/
function setQuery( $sql, $offset = 0, $limit = 0, $prefix='#__' ) {
$sql = (string) $sql;
if ( in_array( checkJversion( 'product' ), array( 'Mambo', 'Elxis', 'MiaCMS' ) ) ) {
if ( $offset || $limit ) {
$sql .= " LIMIT ";
if ( $offset ) {
$sql .= ( (int) abs( $offset ) ) . ', ';
}
$sql .= ( (int) abs( $limit ) );
}
$this->_db->setQuery( $sql, $prefix );
} else {
$this->_db->setQuery( $sql, (int) abs( $offset ), (int) abs( $limit ), $prefix );
}
}
/**
* Replace $prefix with $this->getPrefix() in $sql
*
* @param string $sql SQL query
* @param string $prefix Common table prefix
*/
function replacePrefix( $sql, $prefix='#__' ) {
// Preg Pattern is: find any non-quoted (which is not including single or double quotes) string being the prefix in $sql possibly followed by a double or single quoted one:
// not including quotes:
// positive lookahead: (?<=
// not including " or ': [^"\']+
// )(
// including exactly the prefix to replace: preg_quote( $prefix, '/' )
// )(
// Followed by a double-quoted: "(?:[^\\"]|\\.)*"
// Or: |
// single-quoted: \'(?:[^\\\']|\\.)*\'
// )
// possibly: ?
$pattern = '/(?:(?<=[^"\'])|^)(' . preg_quote( $prefix, '/' ) . ')("(?:[^\\\\"]|\.)*"|\'(?:[^\\\\\']|\.)*\')?/';
return preg_replace( $pattern, $this->getPrefix() . '\\2', $sql );
}
/**
* @return string The current value of the internal SQL vairable
*/
function getQuery( ) {
return $this->_db->getQuery();
}
/**
* Execute the query
*
* @param string the query (optional, it will use the setQuery one otherwise)
* @return mixed A database resource if successful, FALSE if not.
*/
function query( $sql = null ) {
if ( $sql !== null ) {
$this->setQuery( $sql );
}
return $this->_db->query();
}
/**
* Executes a series of SQL orders, optionally as a transaction
*
* @param boolean $abort_on_error Aborts on error (true by default)
* @param boolean $p_transaction_safe Encloses all in a single transaction (false by default)
* @return boolean true: success, false: error(s)
*/
function query_batch( $abort_on_error = true, $p_transaction_safe = false) {
return $this->_db->query_batch( $abort_on_error, $p_transaction_safe );
}
/** for compatibility only: */
function queryBatch( $abort_on_error = true, $p_transaction_safe = false) {
return $this->query_batch( $abort_on_error, $p_transaction_safe );
}
/**
* @return int The number of affected rows in the previous operation
*/
function getAffectedRows( ) {
if ( is_callable( array( $this->_db, 'getAffectedRows' ) ) ) {
$affected = $this->_db->getAffectedRows();
} elseif ( get_resource_type( $this->_db->_resource ) == 'mysql link' ) {
$affected = mysql_affected_rows( $this->_db->_resource );
} else {
$affected = mysqli_affected_rows( $this->_db->_resource );
}
return $affected;
}
/**
* Returns the number of rows returned from the most recent query.
*
* @return int
*/
function getNumRows( $cur = null ) {
return $this->_db->getNumRows( $cur );
}
/**
* Explain of SQL
*
* @return string
*/
function explain( ) {
return $this->_db->explain();
}
/**
* This method loads the first field of the first row returned by the query.
*
* @return The value returned in the query or null if the query failed.
*/
function loadResult( ) {
return $this->_db->loadResult();
}
function & _nullToArray( &$resultArray ) {
if ( $resultArray === null ) { // mambo strangeness
$resultArray = array();
}
return $resultArray;
}
/**
* Load an array of single field results into an array
*/
function loadResultArray( $numinarray = 0 ) {
$resultArray = $this->_db->loadResultArray( $numinarray );
return $this->_nullToArray( $resultArray );
}
/**
* Fetch a result row as an associative array
*
* @return array
*/
function loadAssoc( ) {
if ( is_callable( array( $this->_db, 'loadAssoc' ) ) ) {
return $this->_db->loadAssoc( );
} else {
// new independant efficient implementation:
if ( ! ( $cur = $this->query() ) ) {
$result = null;
} else {
$result = $this->m_fetch_assoc( $cur );
if ( ! $result ) {
$result = null;
}
$this->m_free_result( $cur );
}
return $result;
}
}
/**
* Load a assoc list of database rows
*
* @param string The field name of a primary key
* @return array If <var>key</var> is empty as sequential list of returned records.
*/
function loadAssocList( $key = null ) {
if ( ( $key == '' ) || ( checkJversion() >= 0 ) ) {
$resultArray = $this->_db->loadAssocList( $key );
return $this->_nullToArray( $resultArray );
} else {
// mambo 4.5.2 - 4.6.2 has a bug in key:
if ( ! ( $cur = $this->query() ) ) {
return null;
}
$array = array();
while ( is_array( $row = $this->m_fetch_assoc( $cur ) ) ) {
if ( $key ) {
$array[$row[$key]] = $row; // $row->key is not an object, but an array
} else {
$array[] = $row;
}
}
$this->m_free_result( $cur );
return $array;
}
}
/**
* This global function loads the first row of a query into an object
*
* If an object is passed to this function, the returned row is bound to the existing elements of <var>object</var>.
* If <var>object</var> has a value of null, then all of the returned query fields returned in the object.
* @param stdClass $object
* @return boolean Success
*/
function loadObject( &$object ) {
// return $this->_db->loadObject( $object );
$cur = $this->query();
if ( ! $cur ) {
return false;
}
if ( $object != null ) {
$array = $this->m_fetch_assoc( $cur );
$this->m_free_result( $cur );
if ( is_array( $array ) ) {

foreach ( get_object_vars( $object ) as $k => $v) {
if( substr( $k, 0, 1 ) != '_' ) {
if ( isset( $array[$k] ) ) {
$object->$k = $array[$k];
}
}
}
return true;
}
} else {
$object = $this->m_fetch_object( $cur );
$this->m_free_result( $cur );
if ( is_object( $object ) ) {
return true;
} else {
$object = null;
}
}
return false;
}
/**
* Load a list of database objects
* If $key is not empty then the returned array is indexed by the value
* the database key. Returns NULL if the query fails.
*
* @param string|array $key The field name of a primary key, if array contains keys for sub-arrays: e.g. array( 'a', 'b' ) will store into $array[$row->a][$row->b]
* @param string|null $className The name of the class to instantiate, set the properties of and return. If not specified, a stdClass object is returned
* @param array|null $ctor_params An optional array of parameters to pass to the constructor for class_name objects
* @param boolean $lowerCaseIndex default: FALSE: keep case, TRUE: lowercase array indexes (only valid if $key is string and not array)
* @return array If $key is empty as sequential list of returned records.
*/
function loadObjectList( $key = null, $className = null, $ctor_params = null, $lowerCaseIndex = false ) {
if ( ! ( $cur = $this->query() ) ) {
return null;
}
$array = array();
if ( ! $key ) {
while ( is_object( $row = $this->m_fetch_object( $cur, $className, $ctor_params ) ) ) {
$array[] = $row;
}
} elseif ( is_array( $key ) ) {
if ( count( $key == 2 ) ) {
list( $ka, $kb ) = $key;
while ( is_object( $row = $this->m_fetch_object( $cur, $className, $ctor_params ) ) ) {
$array[$row->$ka][$row->$kb] = $row;
}
} elseif ( count( $key == 3 ) ) {
list( $ka, $kb, $kc ) = $key;
while ( is_object( $row = $this->m_fetch_object( $cur, $className, $ctor_params ) ) ) {
$array[$row->$ka][$row->$kb][$row->$kc] = $row;
}
}
} elseif ( $lowerCaseIndex ) {
while ( is_object( $row = $this->m_fetch_object( $cur, $className, $ctor_params ) ) ) {
$array[strtolower($row->$key)] = $row;
}
} else {
while ( is_object( $row = $this->m_fetch_object( $cur, $className, $ctor_params ) ) ) {
$array[$row->$key] = $row;
}
}
$this->m_free_result( $cur );
return $array;
}
/**
* @return The first row of the query.
*/
function loadRow( ) {
return $this->_db->loadRow();
}
/**
* Load a list of database rows (numeric column indexing)
* @param string The field name of a primary key
* @return array If <var>key</var> is empty as sequential list of returned records.
* If <var>key</var> is not empty then the returned array is indexed by the value
* the database key. Returns <var>null</var> if the query fails.
*/
function loadRowList( $key = null ) {
$resultArray = $this->_db->loadRowList( $key );
return $this->_nullToArray( $resultArray );
}
/**
* Insert an object into database
*
* @param string $table This is expected to be a valid (and safe!) table name
* @param stdClass $object
* @param string $keyName
* @param boolean $verbose
* @param boolean TRUE if insert succeeded, FALSE when error
*/
function insertObject( $table, &$object, $keyName = NULL, $verbose=false ) {
return $this->_db->insertObject( $table, $object, $keyName, $verbose );
}
/**
* Updates an object into a database
*
* @param string $table This is expected to be a valid (and safe!) table name
* @param stdClass $object
* @param string $keyName
* @param boolean $updateNulls
* @return mixed A database resource if successful, FALSE if not.
*/
function updateObject( $table, &$object, $keyName, $updateNulls=true ) {
// return $this->_db->updateObject( $table, $object, $keyName, $updateNulls );
$fmtsql = 'UPDATE ' . $this->NameQuote( $table ) . ' SET %s WHERE %s';
$tmp = array();
foreach (get_object_vars( $object ) as $k => $v) {
if( is_array($v) or is_object($v) or $k[0] == '_' ) { // internal or NA field
continue;
}
if( $k == $keyName ) { // PK not to be updated
$where = $keyName . '=' . $this->Quote( $v );
continue;
}
if( $v === NULL ) {
if ( ! $updateNulls ) {
continue;
}
$val = 'NULL'; // this case was missing in Mambo
// } elseif( $v == '' ) { // this Mambo&Joomla error was triggering '' for int 0 !
// $val = "''";
} elseif( is_int( $v ) ) {
$val = (int) $v;
} else {
$val = $this->Quote( $v );
}
$tmp[] = $this->NameQuote( $k ) . '=' . $val;
}
$this->setQuery( sprintf( $fmtsql, implode( ",", $tmp ) , $where ) );
return $this->query();
}

/**
* Returns the formatted standard error message of SQL
* @param boolean $showSQL If TRUE, displays the last SQL statement sent to the database
* @return string A standised error message
*/
function stderr( $showSQL = false ) {
return $this->_db->stderr( $showSQL );
}
/**
* Returns the insert_id() from Mysql
*
* @return int
*/
function insertid( ) {
return $this->_db->insertid();
}
/**
* Returns the version of MySQL
*
* @return string
*/
function getVersion( ) {
return $this->_db->getVersion();
}
function versionCompare( $minimumVersionCompare ) {
static $version = null;
if ( $version === null ) {
$version = preg_replace( '/^([0-9\.]+).*/', '\\1', $this->getVersion() );
}
return version_compare( $version, $minimumVersionCompare, '>=' );
}
/**
* Get tables prefix (so that '#__' can be replaced by this
* @since 1.7
*
* @return string Database table prefix.
*
*/
function getPrefix() {
return $this->_table_prefix;
}
/**
* Returns a list of tables, with the prefix changed if needed.
*
* @param string $tableName Name of table (SQL LIKE pattern), null: all tables
* @param string $prefix Prefix to change back
* @return array A list of all the tables in the database
*/
function getTableList( $tableName = null, $prefix = '#__' ) {
$this->setQuery( 'SHOW TABLES' . ( $tableName ? ' LIKE ' . $this->Quote( $this->replacePrefix( $tableName, $prefix ) ) : '' ) );
$tables = $this->loadResultArray();
if ( $prefix ) {
foreach ( $tables as $k => $n ) {
$tables[$k] = preg_replace( '/^(' . $this->getPrefix() . ')/', $prefix, $n );
}
}
return $tables;
}
/**
* Returns the status of all tables, with the prefix changed if needed.
*
* @param string $tableName Name of table (SQL LIKE pattern), null: all tables
* @param string $prefix Prefix to change back
* @return array A list of all the table statuses in the database
*/
function getTableStatus( $tableName = null, $prefix = '#__' ) {
$this->setQuery( 'SHOW TABLE STATUS' . ( $tableName ? ' LIKE ' . $this->Quote( $this->replacePrefix( $tableName, $prefix ) ) : '' ) );
$tables = $this->loadObjectList();
if ( $prefix ) {
foreach ( $tables as $k => $n ) {
$tables[$k]->Name = preg_replace( '/^(' . $this->getPrefix() . ')/', $prefix, $n->Name );
}
}
return $tables;
}
/**
* @param array A list of valid (and safe!) table names
* @return array A list the create SQL for the tables
*/
function getTableCreate( $tables ) {
$createQueries = array();
foreach ( $tables as $tableName ) {
$this->setQuery( 'SHOW CREATE table ' . $this->NameQuote( $tableName ) );
$this->query();
$createQueries[$tableName] = $this->loadResultArray( 1 );
}
return $createQueries;
}
/**
* Gets the fields as in DESCRIBE of MySQL
*
* @param array|string $tables A (list of) table names
* @param boolean $onlyType TRUE: only type without size, FALSE: full DESCRIBE MySql
* @return array EITHER: array( tablename => array( fieldname => fieldtype ) ) or of => fieldDESCRIBE
*/
function getTableFields( $tables, $onlyType = true ) {
$result = array();
$tables = (array) $tables;
foreach ( $tables as $tbl ) {
$this->setQuery( 'SHOW' . ( ( ! $onlyType ) && $this->versionCompare( '4.1' ) ? ' FULL' : '' ) . ' COLUMNS FROM ' . $this->NameQuote( $tbl ) );
$result[$tbl] = $this->loadObjectList( 'Field' );
if ( is_array( $result[$tbl] ) && $onlyType ) {
foreach ( $result[$tbl] as $k => $fld ) {
$result[$tbl][$k] = preg_replace( '/[(0-9)]/','', $fld->Type );
}
}
}
return $result;
}
/**
* Gets the index of the table
*
* @param array|string $tables A (list of) table names
* @return array As
*/
function getTableIndex( $table, $prefix = '#__' ) {
$this->setQuery( 'SHOW INDEX FROM ' . $this->NameQuote( $table ) );
$indexes = $this->loadObjectList();
if ( $prefix ) {
foreach ( $indexes as $k => $n ) {
$indexes[$k]->Table = preg_replace( '/^(' . $this->getPrefix() . ')/', $prefix, $n->Table );
}
}
return $indexes;
}
/**
* Fudge method for ADOdb compatibility
*/
function GenID( $foo1=null, $foo2=null ) {
return '0';
}
/**
* Checks if database's collation is case-INsensitive
* WARNING: individual table's fields might have a different collation
*
* @return boolean TRUE if case INsensitive
*/
function isDbCollationCaseInsensitive( ) {
static $result = null;

if ( $result === null ) {
$query = "SELECT IF('a'='A', 1, 0);";
$this->setQuery( $query );
$result = $this->loadResult();
}
return ( $result == 1 );
}
/**
* mysql/mysqli_fetch_assoc function
*
* @param mysql_result $cur The result resource that is being evaluated. This result comes from a call to mysql_query().
* @return array|boolean|null False OR null if no more
*/
function m_fetch_assoc( &$cur ) {
if ( is_object( $cur ) && get_class( $cur ) == 'mysqli_result' ) {
return mysqli_fetch_assoc( $cur );
} else {
return mysql_fetch_assoc( $cur );
}
}
/**
* mysql / mysqli fetch_object
*
* @param mysql_result $cur The result resource that is being evaluated. This result comes from a call to mysql_query()
* @param string|null $className The name of the class to instantiate, set the properties of and return. If not specified, a stdClass object is returned
* @param array|null $ctor_params An optional array of parameters to pass to the constructor for class_name objects
* @return object|boolean|null False OR null if no more
*/
function m_fetch_object( &$cur, $className = null, $ctor_params = null ) {
static $phpVersion5 = null;
if ( is_object( $cur ) && ( get_class( $cur ) == 'mysqli_result' ) ) {
// MySqli is PHP 5 only:
if ( $className === null ) {
return mysqli_fetch_object( $cur );
} else {
return mysqli_fetch_object( $cur, $className, $ctor_params );
}
} else {
// MySql:
if ( $className === null ) {
return mysql_fetch_object( $cur );
} elseif ( $phpVersion5 || ( true === ( $phpVersion5 = ( 1 == version_compare( phpversion(), '5.0.0', '>=' ) ) ) ) ) {
return mysql_fetch_object( $cur, $className, $ctor_params );
} else {
$objArr = $this->m_fetch_assoc( $cur );
if ( ! is_array( $objArr ) ) {
return $objArr;
}
$obj = $this->_m_new_class( $className, $ctor_params );
foreach ( $objArr as $k => $v) {
$obj->$k = $v;
}
return $obj;
}
}
}
/**
* Emulation of a Reflection class for PHP 4 only
*
* In PHP 5.1.3+ that could be made as:
* $reflectionObj = new ReflectionClass($className);
* $obj = $reflectionObj->newInstanceArgs($cp);
* But as mysql_fetch_object handles it already in PHP 5.0, it's not needed.
*
* @param string $className
* @param array $cp
* @return object
*/
function _m_new_class( $className, &$cp ) {
if ( $cp === null ) {
return new $className();
} elseif ( is_array( $cp ) ) {
switch ( count( $cp ) ) {
case 0:
return new $className();
break;
case 1:
return new $className( $cp[0] );
break;
case 2:
return new $className( $cp[0], $cp[1] );
break;
case 3:
return new $className( $cp[0], $cp[1], $cp[2] );
break;
case 4:
return new $className( $cp[0], $cp[1], $cp[2], $cp[3] );
break;
case 5:
return new $className( $cp[0], $cp[1], $cp[2], $cp[3], $cp[4] );
break;
case 6:
return new $className( $cp[0], $cp[1], $cp[2], $cp[3], $cp[4], $cp[5] );
break;
case 7:
return new $className( $cp[0], $cp[1], $cp[2], $cp[3], $cp[4], $cp[5], $cp[6] );
break;
case 8:
return new $className( $cp[0], $cp[1], $cp[2], $cp[3], $cp[4], $cp[5], $cp[6], $cp[7] );
break;
case 9:
return new $className( $cp[0], $cp[1], $cp[2], $cp[3], $cp[4], $cp[5], $cp[6], $cp[7], $cp[8] );
break;
case 10:
return new $className( $cp[0], $cp[1], $cp[2], $cp[3], $cp[4], $cp[5], $cp[6], $cp[7], $cp[8], $cp[9] );
break;

default:
trigger_error( 'CBdatabase::m_fetch_object: constructor parameters count to large', E_USER_ERROR );
exit;
break;
}
}
}
function m_free_result( &$cur ) {
if ( is_object( $cur ) && get_class( $cur ) == 'mysqli_result' ) {
mysqli_free_result( $cur );
} else {
mysql_free_result( $cur );
}
}
} // class CBdatabase

// ----- NO MORE CLASSES OR FUNCTIONS PASSED THIS POINT -----
// Post class declaration initialisations
// some version of PHP don't allow the instantiation of classes
// before they are defined

global $_CB_database, $_CB_framework;
/** @global CBdatabase $_CB_Database */
$_CB_database = new CBdatabase( $_CB_framework->_cmsDatabase );

?>
(2-2/2)