pickles/classes/Model.php
Josh Sherman 99aa78b6fa Built in caching for primary key queries
Selects done against a primary key will automatically cache to Memcached (haven't tried it, but it should fail gracefully) indexed by the model name and the primary key ([NAMESPACE-]MODEL-PKEY). Any updates or deletes against the same primary key will purge the cache automatically. The major caveat here is the case of mass updates which would result in stale data. As it stands the data is being cached for a mere 5 minutes, so this multiple row update scenario would be short lived but ideally, I'll be pushing back the time to live on the cache and/or making it something that's configurable. If you have to do mass updates, you're probably doing them with a cronjob and should just be flushing all of the cache in that scenario (as it would be nearly impossible to detect the affected keys and purge them all).
2012-10-23 23:30:04 -04:00

1328 lines
27 KiB
PHP

<?php
/**
* Model Parent Class for PICKLES
*
* PHP version 5
*
* Licensed under The MIT License
* Redistribution of these files must retain the above copyright notice.
*
* @author Josh Sherman <pickles@joshtronic.com>
* @copyright Copyright 2007-2012, Josh Sherman
* @license http://www.opensource.org/licenses/mit-license.html
* @package PICKLES
* @link https://github.com/joshtronic/pickles
*/
/**
* Model Class
*
* This is a parent class that all PICKLES data models should be extending. When
* using the class as designed, objects will function as active record pattern
* objects.
*/
class Model extends Object
{
// {{{ Properties
/**
* Model Name
*
* @access private
* @var string
*/
private $model = null;
/**
* Database Object
*
* @access protected
* @var object
*/
protected $db = null;
/**
* Columns
*
* Mapping of key columns for the table.
*
* @access protected
* @var array
*/
protected $columns = null;
/**
* Cache Object
*
* @access
* @var object
*/
protected $cache = null;
/**
* Whether or not to use cache
*
* @access protected
* @var boolean
*/
protected $use_cache = false;
/**
* SQL Array
*
* @access private
* @var array
*/
private $sql = array();
/**
* Input Parameters Array
*
* @access private
* @var array
*/
private $input_parameters = array();
/**
* Insert Priority
*
* Defaults to false (normal priority) but can be set to "low" or "high"
*
* @access protected
* @var string
*/
protected $priority = false;
/**
* Delayed Insert
*
* @access protected
* @var boolean
*/
protected $delayed = false;
/**
* Ignore Unique Index
*
* @access protected
* @var boolean
*/
protected $ignore = false;
/**
* Replace instead of Insert/Update?
*
* @access protected
* @var boolean
*/
protected $replace = false;
/**
* Field List
*
* @access protected
* @var mixed
*/
protected $fields = '*'; // SELECT
/**
* Table Name
*
* @access protected
* @var mixed
*/
protected $table = false; // FROM
/**
* Joins
*
* @access protected
* @var mixed
*/
protected $joins = false; // JOIN
/**
* [Index] Hints
*
* @access protected
* @var mixed
*/
protected $hints = false; // USE INDEX
/**
* Conditions
*
* @access protected
* @var mixed
*/
protected $conditions = false; // WHERE
/**
* Group
*
* @access protected
* @var mixed
*/
protected $group = false; // GROUP BY
/**
* Having
*
* @access protected
* @var mixed
*/
protected $having = false; // HAVING
/**
* Order
*
* @access protected
* @var mixed
*/
protected $order = false; // ORDER BY
/**
* Limit
*
* @access protected
* @var mixed
*/
protected $limit = false; // LIMIT
/**
* Offset
*
* @access protected
* @var mixed (string or array)
*/
protected $offset = false; // OFFSET
/**
* Query Results
*
* @access protected
* @var array
*/
protected $results = null;
/**
* Index
*
* @var integer
*/
private $index = null;
/**
* Record
*
* @access private
* @var array
*/
public $record = null;
/**
* Records
*
* @var array
*/
public $records = null;
/**
* Original Record
*
* @access private
* @var array
*/
private $original = null;
/**
* Iterate
*
* Used to hold the status during a walk()
*
* @access private
* @var boolean
*/
private $iterate = false;
/**
* Snapshot
*
* Snapshot of the object properties
*
* @access private
* @var array
*/
private $snapshot = array();
/**
* MySQL?
*
* Whether or not we're using MySQL
*
* @access private
* @var boolean
*/
private $mysql = false;
/**
* PostgreSQL?
*
* Whether or not we're using PostgreSQL
*
* @access private
* @var boolean
*/
private $postgresql = false;
// }}}
// {{{ Class Constructor
/**
* Constructor
*
* Creates a new (empty) object or populates the record set.
*
* @param mixed $type_or_parameters optional type of query or parameters
* @param array $parameters optional data to create a query from
*/
public function __construct($type_or_parameters = null, $parameters = null)
{
// Errors if a table is not set. You're welcome, Geoff.
if ($this->table == false)
{
throw new Exception('You must set the table variable');
}
// Runs the parent constructor so we have the config
parent::__construct();
// Gets an instance of the database and check which it is
$this->db = Database::getInstance();
$this->mysql = ($this->db->driver == 'pdo_mysql');
$this->postgresql = ($this->db->driver == 'pdo_pgsql');
// Sets up the cache object and grabs the class name to use in our cache keys
$this->cache = Cache::getInstance();
$this->model = get_class($this);
// Default column mapping
$columns = array(
'id' => 'id',
'created_at' => 'created_at',
'created_id' => 'created_id',
'updated_at' => 'updated_at',
'updated_id' => 'updated_id',
'deleted_at' => 'deleted_at',
'deleted_id' => 'deleted_id',
'is_deleted' => 'is_deleted',
);
// Grabs the config columns if no columns are set
if ($this->columns === null && isset($this->db->columns))
{
$this->columns = $this->db->columns;
}
// Sets all but the `id` column to false
if ($this->columns === false)
{
foreach ($columns as $column => $field)
{
if ($column != 'id')
{
$columns[$column] = false;
}
}
}
// Merges the model's columns with the defaults
elseif (is_array($this->columns))
{
foreach ($this->columns as $column => $field)
{
$columns[$column] = $field;
}
}
$this->columns = $columns;
// Takes a snapshot of the [non-object] object properties
foreach ($this as $variable => $value)
{
if (!in_array($variable, array('db', 'cache', 'config', 'snapshot')))
{
$this->snapshot[$variable] = $value;
}
}
return $this->execute($type_or_parameters, $parameters);
}
// }}}
// {{{ Database Execution Methods
/**
* Execute
*
* Potentially populates the record set from the passed arguments.
*
* @param mixed $type_or_parameters optional type of query or parameters
* @param array $parameters optional data to create a query from
*/
public function execute($type_or_parameters = null, $parameters = null)
{
// Resets internal properties
foreach ($this->snapshot as $variable => $value)
{
$this->$variable = $value;
}
// Builds out the query
if ($type_or_parameters != null)
{
// Loads the parameters into the object
if (is_array($type_or_parameters))
{
if (is_array($parameters))
{
throw new Exception('You cannot pass in 2 query parameter arrays');
}
if ($this->columns['is_deleted'])
{
$type_or_parameters['conditions'][$this->columns['is_deleted']] = '0';
}
$this->loadParameters($type_or_parameters);
}
elseif (is_array($parameters))
{
if ($this->columns['is_deleted'])
{
$parameters['conditions'][$this->columns['is_deleted']] = '0';
}
$this->loadParameters($parameters);
}
elseif (ctype_digit((string)$type_or_parameters))
{
$cache_key = $this->model . '-' . $type_or_parameters;
$parameters = array($this->columns['id'] => $type_or_parameters);
if ($this->columns['is_deleted'])
{
$parameters[$this->columns['is_deleted']] = '0';
}
$this->loadParameters($parameters);
}
elseif (ctype_digit((string)$parameters))
{
$cache_key = $this->model . '-' . $parameters;
$parameters = array($this->columns['id'] => $parameters);
if ($this->columns['is_deleted'])
{
$parameters[$this->columns['is_deleted']] = '0';
}
$this->loadParameters($parameters);
}
elseif ($this->columns['is_deleted'])
{
$this->loadParameters(array($this->columns['is_deleted'] => '0'));
}
// Starts with a basic SELECT ... FROM
$this->sql = array(
'SELECT ' . (is_array($this->fields) ? implode(', ', $this->fields) : $this->fields),
'FROM ' . $this->table,
);
switch ($type_or_parameters)
{
// Updates query to use COUNT syntax
case 'count':
$this->sql[0] = 'SELECT COUNT(*) AS count';
$this->generateQuery();
break;
// Adds the rest of the query
case 'all':
case 'list':
case 'indexed':
default:
$this->generateQuery();
break;
}
$query_database = true;
if (isset($cache_key))
{
$cached = $this->cache->get($cache_key);
}
if (isset($cached) && $cached)
{
$this->records = $cached;
}
else
{
$this->records = $this->db->fetch(
implode(' ', $this->sql),
(count($this->input_parameters) == 0 ? null : $this->input_parameters)
);
if (isset($cache_key))
{
$this->cache->set($cache_key, $this->records);
}
}
$index_records = in_array($type_or_parameters, array('list', 'indexed'));
// Flattens the data into a list
if ($index_records == true)
{
$list = array();
foreach ($this->records as $record)
{
// Users the first value as the key and the second as the value
if ($type_or_parameters == 'list')
{
$list[array_shift($record)] = array_shift($record);
}
// Uses the first value as the key
else
{
$list[current($record)] = $record;
}
}
$this->records = $list;
}
// Sets up the current record
if (isset($this->records[0]))
{
$this->record = $this->records[0];
}
else
{
if ($index_records == true)
{
$this->record[key($this->records)] = current($this->records);
}
else
{
$this->record = $this->records;
}
}
$this->index = 0;
$this->original = $this->records;
}
return true;
}
// }}}
// {{{ SQL Generation Methods
/**
* Generate Query
*
* Goes through all of the object variables that correspond with parts of
* the query and adds them to the master SQL array.
*
* @return boolean true
*/
private function generateQuery()
{
// Adds the JOIN syntax
if ($this->joins != false)
{
if (is_array($this->joins))
{
foreach ($this->joins as $join => $tables)
{
$join_pieces = array((stripos('JOIN ', $join) === false ? 'JOIN' : strtoupper($join)));
if (is_array($tables))
{
foreach ($tables as $table => $conditions)
{
$join_pieces[] = $table;
if (is_array($conditions))
{
$type = strtoupper(key($conditions));
$conditions = current($conditions);
$join_pieces[] = $type;
$join_pieces[] = $this->generateConditions($conditions, true);
}
else
{
$join_pieces = $conditions;
}
}
}
else
{
$join_pieces[] = $tables;
}
}
$this->sql[] = implode(' ', $join_pieces);
unset($join_pieces);
}
else
{
$this->sql[] = (stripos('JOIN ', $join) === false ? 'JOIN ' : '') . $this->joins;
}
}
// Adds the index hints
if ($this->hints != false)
{
if (is_array($this->hints))
{
foreach ($this->hints as $hint => $columns)
{
if (is_array($columns))
{
$this->sql[] = $hint . ' (' . implode(', ', $columns) . ')';
}
else
{
$format = (stripos($columns, 'USE ') === false);
$this->sql[] = ($format ? 'USE INDEX (' : '') . $columns . ($format ? ')' : '');
}
}
}
else
{
$format = (stripos($this->hints, 'USE ') === false);
$this->sql[] = ($format ? 'USE INDEX (' : '') . $this->hints . ($format ? ')' : '');
}
}
// Adds the WHERE conditionals
if ($this->conditions != false)
{
$this->sql[] = 'WHERE ' . (is_array($this->conditions) ? $this->generateConditions($this->conditions) : $this->conditions);
}
// Adds the GROUP BY syntax
if ($this->group != false)
{
$this->sql[] = 'GROUP BY ' . (is_array($this->group) ? implode(', ', $this->group) : $this->group);
}
// Adds the HAVING conditions
if ($this->having != false)
{
$this->sql[] = 'HAVING ' . (is_array($this->having) ? $this->generateConditions($this->having) : $this->having);
}
// Adds the ORDER BY syntax
if ($this->order != false)
{
$this->sql[] = 'ORDER BY ' . (is_array($this->order) ? implode(', ', $this->order) : $this->order);
}
// Adds the LIMIT syntax
if ($this->limit != false)
{
$this->sql[] = 'LIMIT ' . (is_array($this->limit) ? implode(', ', $this->limit) : $this->limit);
}
// Adds the OFFSET syntax
if ($this->offset != false)
{
$this->sql[] = 'OFFSET ' . $this->offset;
}
return true;
}
/**
* Generate Conditions
*
* Generates the conditional blocks of SQL from the passed array of
* conditions. Supports as much as I could remember to implement. This
* method is utilized by both the WHERE and HAVING clauses.
*
* @param array $conditions array of potentially nested conditions
* @param boolean $inject_values whether or not to use input parameters
* @param string $conditional syntax to use between conditions
* @return string $sql generated SQL for the conditions
*/
private function generateConditions($conditions, $inject_values = false, $conditional = 'AND')
{
$sql = '';
foreach ($conditions as $key => $value)
{
$key = trim($key);
if (strtoupper($key) == 'NOT')
{
$key = 'AND NOT';
}
// Checks if conditional to start recursion
if (preg_match('/^(AND|&&|OR|\|\||XOR)( NOT)?$/i', $key))
{
if (is_array($value))
{
// Determines if we need to include ( )
$nested = (count($value) > 1);
$conditional = $key;
$sql .= ' ' . ($sql == '' ? '' : $key) . ' ' . ($nested ? '(' : '');
$sql .= $this->generateConditions($value, $inject_values, $conditional);
$sql .= ($nested ? ')' : '');
}
else
{
$sql .= ' ' . ($sql == '' ? '' : $key) . ' ' . $value;
}
}
else
{
if ($sql != '')
{
if (preg_match('/^(AND|&&|OR|\|\||XOR)( NOT)?/i', $key))
{
$sql .= ' ';
}
else
{
$sql .= ' ' . $conditional . ' ';
}
}
// Checks for our keywords to control the flow
$operator = preg_match('/(<|<=|=|>=|>|!=|!|<>| LIKE)$/i', $key);
$between = preg_match('/ BETWEEN$/i', $key);
$is_is_not = preg_match('/( IS| IS NOT)$/i', $key);
// Checks for boolean and null
$is_true = ($value === true);
$is_false = ($value === false);
$is_null = ($value === null);
// Generates an IN statement
if (is_array($value) && $between == false)
{
$sql .= $key . ' IN (';
if ($inject_values == true)
{
$sql .= implode(', ', $value);
}
else
{
$sql .= implode(', ', array_fill(1, count($value), '?'));
$this->input_parameters = array_merge($this->input_parameters, $value);
}
$sql .= ')';
}
else
{
// If the key is numeric it wasn't set, so don't use it
if (is_numeric($key))
{
$sql .= $value;
}
else
{
// Omits the operator as the operator is there
if ($operator == true || $is_is_not == true)
{
if ($is_true || $is_false || $is_null)
{
// Scrubs the operator if someone doesn't use IS / IS NOT
if ($operator == true)
{
$key = preg_replace('/ ?(!=|!|<>)$/i', ' IS NOT', $key);
$key = preg_replace('/ ?(<|<=|=|>=| LIKE)$/i', ' IS', $key);
}
$sql .= $key . ' ';
if ($is_true)
{
$sql .= 'TRUE';
}
elseif ($is_false)
{
$sql .= 'FALSE';
}
else
{
$sql .= 'NULL';
}
}
else
{
$sql .= $key . ' ';
if ($inject_values == true)
{
$sql .= $value;
}
else
{
$sql .= '?';
$this->input_parameters[] = $value;
}
}
}
// Generates a BETWEEN statement
elseif ($between == true)
{
if (is_array($value))
{
// Checks the number of values, BETWEEN expects 2
if (count($value) != 2)
{
throw new Exception('Between expects 2 values');
}
else
{
$sql .= $key . ' ';
if ($inject_values == true)
{
$sql .= $value[0] . ' AND ' . $value[1];
}
else
{
$sql .= '? AND ?';
$this->input_parameters = array_merge($this->input_parameters, $value);
}
}
}
else
{
throw new Exception('Between usage expects values to be in an array');
}
}
else
{
$sql .= $key . ' ';
// Checks if we're working with NULL values
if ($is_true)
{
$sql .= 'IS TRUE';
}
elseif ($is_false)
{
$sql .= 'IS FALSE';
}
elseif ($is_null)
{
$sql .= 'IS NULL';
}
else
{
if ($inject_values == true)
{
$sql .= '= ' . $value;
}
else
{
$sql .= '= ?';
$this->input_parameters[] = $value;
}
}
}
}
}
}
}
return $sql;
}
// }}}
// {{{ Record Interaction Methods
/**
* Count Records
*
* Counts the records
*/
public function count()
{
return count($this->records);
}
/**
* Sort Records
*
* Sorts the records by the specified index in the specified order.
*
* @param string $index the index to be sorted on
* @param string $order the direction to order
* @return boolean true
* @todo Implement this method
*/
public function sort($index, $order = 'ASC')
{
return true;
}
/**
* Shuffle Records
*
* Sorts the records in a pseudo-random order.
*
* @return boolean true
* @todo Implement this method
*/
public function shuffle()
{
return true;
}
/**
* Next Record
*
* Increment the record array to the next member of the record set.
*
* @return boolean whether or not there was next element
*/
public function next()
{
$return = (boolean)($this->record = next($this->records));
if ($return == true)
{
$this->index++;
}
return $return;
}
/**
* Previous Record
*
* Decrement the record array to the next member of the record set.
*
* @return boolean whether or not there was previous element
*/
public function prev()
{
$return = (boolean)($this->record = prev($this->records));
if ($return == true)
{
$this->index--;
}
return $return;
}
/**
* Reset Record
*
* Set the pointer to the first element of the record set.
*
* @return boolean whether or not records is an array (and could be reset)
*/
public function reset()
{
$return = (boolean)($this->record = reset($this->records));
if ($return == true)
{
$this->index = 0;
}
return $return;
}
/**
* First Record
*
* Alias of reset(). "first" is more intuitive to me, but reset stays in
* line with the built in PHP functions. Not sure why I'd want to add some
* consistency to one of the most inconsistent languages.
*
* @return boolean whether or not records is an array (and could be reset)
*/
public function first()
{
return $this->reset();
}
/**
* End Record
*
* Set the pointer to the last element of the record set.
*
* @return boolean whether or not records is an array (and end() worked)
*/
public function end()
{
$return = (boolean)($this->record = end($this->records));
if ($return == true)
{
$this->index = $this->count() - 1;
}
return $return;
}
/**
* Last Record
*
* Alias of end(). "last" is more intuitive to me, but end stays in line
* with the built in PHP functions.
*
* @return boolean whether or not records is an array (and end() worked)
*/
public function last()
{
return $this->end();
}
/**
* Walk Records
*
* Returns the current record and advances to the next. Built to allow for
* simplified code when looping through a record set.
*
* @return mixed either an array of the current record or false
* @todo Does not currently support "indexed" or "list" return types
*/
public function walk()
{
// Checks if we should start iterating, solves off by one issues with next()
if ($this->iterate == false)
{
$this->iterate = true;
// Resets the records, saves calling reset() when walking multiple times
$this->reset();
}
else
{
$this->next();
}
return $this->record;
}
// }}}
// {{{ Record Manipulation Methods
/**
* Commit
*
* Inserts or updates a record in the database.
*
* @return boolean results of the query
*/
public function commit()
{
// Checks if the record is actually populated
if (count($this->record) > 0)
{
// Determines if it's an UPDATE or INSERT
$update = (isset($this->record[$this->columns['id']]) && trim($this->record[$this->columns['id']]) != '');
// Starts to build the query, optionally sets PRIORITY, DELAYED and IGNORE syntax
if ($this->replace === true && $this->mysql)
{
$sql = 'REPLACE';
if (strtoupper($this->priority) == 'LOW')
{
$sql .= ' LOW_PRIORITY';
}
elseif ($this->delayed == true)
{
$sql .= ' DELAYED';
}
$sql .= ' INTO ' . $this->table . ' SET ';
}
else
{
if ($update == true)
{
$sql = 'UPDATE';
}
else
{
$sql = 'INSERT';
// PRIORITY syntax takes priority over DELAYED
if ($this->mysql)
{
if ($this->priority !== false && in_array(strtoupper($this->priority), array('LOW', 'HIGH')))
{
$sql .= ' ' . strtoupper($this->priority) . '_PRIORITY';
}
elseif ($this->delayed == true)
{
$sql .= ' DELAYED';
}
if ($this->ignore == true)
{
$sql .= ' IGNORE';
}
}
$sql .= ' INTO';
}
$sql .= ' ' . $this->table . ($update ? ' SET ' : ' ');
}
$input_parameters = null;
// Limits the columns being updated
$record = ($update ? array_diff_assoc($this->record, isset($this->original[$this->index]) ? $this->original[$this->index] : array()) : $this->record);
// Makes sure there's something to INSERT or UPDATE
if (count($record) > 0)
{
$insert_fields = array();
// Loops through all the columns and assembles the query
foreach ($record as $column => $value)
{
if ($column != $this->columns['id'])
{
if ($update == true)
{
if ($input_parameters != null)
{
$sql .= ', ';
}
$sql .= $column . ' = ?';
}
else
{
$insert_fields[] = $column;
}
$input_parameters[] = (is_array($value) ? (JSON_AVAILABLE ? json_encode($value) : serialize($value)) : $value);
}
}
// If it's an UPDATE tack on the ID
if ($update == true)
{
if ($this->columns['updated_at'] != false)
{
if ($input_parameters != null)
{
$sql .= ', ';
}
$sql .= $this->columns['updated_at'] . ' = ?';
$input_parameters[] = Time::timestamp();
}
if ($this->columns['updated_id'] != false && isset($_SESSION['__pickles']['security']['user_id']))
{
if ($input_parameters != null)
{
$sql .= ', ';
}
$sql .= $this->columns['updated_id'] . ' = ?';
$input_parameters[] = $_SESSION['__pickles']['security']['user_id'];
}
$sql .= ' WHERE ' . $this->columns['id'] . ' = ?' . ($this->mysql ? ' LIMIT 1' : '') . ';';
$input_parameters[] = $this->record[$this->columns['id']];
}
else
{
if ($this->columns['created_at'] != false)
{
$insert_fields[] = $this->columns['created_at'];
$input_parameters[] = Time::timestamp();
}
if ($this->columns['created_id'] != false && isset($_SESSION['__pickles']['security']['user_id']))
{
$insert_fields[] = $this->columns['created_id'];
$input_parameters[] = $_SESSION['__pickles']['security']['user_id'];
}
$sql .= '(' . implode(', ', $insert_fields) . ') VALUES (' . implode(', ', array_fill(0, count($input_parameters), '?')) . ')';
// PDO::lastInsertId() doesn't work so we return the ID with the query
if ($this->postgresql)
{
$sql .= ' RETURNING ' . $this->columns['id'];
}
$sql .= ';';
}
// Executes the query
if ($this->postgresql && $update == false)
{
$results = $this->db->fetch($sql, $input_parameters);
return $results[0][$this->columns['id']];
}
else
{
$results = $this->db->execute($sql, $input_parameters);
// Clears the cache
if ($update)
{
$this->cache->delete($this->model . '-' . $this->record[$this->columns['id']]);
}
return $results;
}
}
}
return false;
}
/**
* Delete Record
*
* Deletes the current record from the database.
*
* @return boolean status of the query
*/
public function delete()
{
if (isset($this->record[$this->columns['id']]))
{
// Logical deletion
if ($this->columns['is_deleted'])
{
$sql = 'UPDATE ' . $this->table . ' SET ' . $this->columns['is_deleted'] . ' = ?';
$input_parameters = array('1');
if ($this->columns['deleted_at'])
{
$sql .= ', ' . $this->columns['deleted_at'] . ' = ?';
$input_parameters[] = Time::timestamp();
}
if ($this->columns['deleted_id'] && isset($_SESSION['__pickles']['security']['user_id']))
{
$sql .= ', ' . $this->columns['deleted_id'] . ' = ?';
$input_parameters[] = $_SESSION['__pickles']['security']['user_id'];
}
$sql .= ' WHERE ' . $this->columns['id'] . ' = ?';
}
// For reals deletion
else
{
$sql = 'DELETE FROM ' . $this->table . ' WHERE ' . $this->columns['id'] . ' = ?' . ($this->mysql ? ' LIMIT 1' : '') . ';';
}
$input_parameters[] = $this->record[$this->columns['id']];
$results = $this->db->execute($sql, $input_parameters);
// Clears the cache
$this->cache->delete($this->model . '-' . $this->record[$this->columns['id']]);
return $results;
}
else
{
return false;
}
}
// }}}
// {{{ Utility Methods
/**
* Load Parameters
*
* Loads the passed parameters back into the object.
*
* @access private
* @param array $parameters key / value list
* @param boolean whether or not the parameters were loaded
*/
private function loadParameters($parameters)
{
if (is_array($parameters))
{
$conditions = true;
// Adds the parameters to the object
foreach ($parameters as $key => $value)
{
// Clean up the variable just in case
$key = trim(strtolower($key));
// Assigns valid keys to the appropriate class property
if (in_array($key, array('fields', 'table', 'joins', 'hints', 'conditions', 'group', 'having', 'order', 'limit', 'offset')))
{
$this->$key = $value;
$conditions = false;
}
}
// If no valid properties were found, assume it's the conditionals
if ($conditions == true)
{
$this->conditions = $parameters;
}
return true;
}
return false;
}
/**
* Unescape String
*
* Assuming magic quotes is turned on, strips slashes from the string.
*
* @access protected
* @param string $value string to be unescaped
* @return string unescaped string
*/
protected function unescape($value)
{
if (get_magic_quotes_gpc())
{
$value = stripslashes($value);
}
return $value;
}
// }}}
}
?>