Files
scattport-web/application/libraries/Datamapper.php
2011-09-13 20:08:25 +02:00

3125 lines
69 KiB
PHP

<?php defined('BASEPATH') || exit('No direct script access allowed');
/**
* Data Mapper Class
*
* Transforms database tables into objects.
*
* @licence MIT Licence
* @category Models
* @author Simon Stenhouse
* @link http://stensi.com
* @version 1.6.0
*/
// --------------------------------------------------------------------------
/**
* Autoload
*
* Autoloads object classes that are used with DataMapper.
*/
spl_autoload_register('DataMapper::autoload');
// --------------------------------------------------------------------------
/**
* Data Mapper Class
*/
class DataMapper {
static $config = array();
static $common = array();
var $error;
var $stored;
var $prefix = '';
var $join_prefix = '';
var $table = '';
var $model = '';
var $error_prefix = '';
var $error_suffix = '';
var $created_field = '';
var $updated_field = '';
var $auto_transaction = FALSE;
var $auto_populate_has_many = FALSE;
var $auto_populate_has_one = FALSE;
var $valid = FALSE;
var $validated = FALSE;
var $local_time = FALSE;
var $unix_timestamp = FALSE;
var $fields = array();
var $all = array();
var $parent = array();
var $validation = array();
var $has_many = array();
var $has_one = array();
var $query_related = array();
/**
* Constructor
*
* Initialize DataMapper.
*/
function DataMapper()
{
$this->_assign_libraries();
$this->_load_languages();
$this->_load_helpers();
// Determine model name
if (empty($this->model))
{
$this->model = singular(get_class($this));
}
// Load stored config settings by reference
foreach (array_keys(DataMapper::$config) as $key)
{
// Only if they're not already set
if (empty($this->{$key}))
{
$this->{$key} =& DataMapper::$config[$key];
}
}
// Load model settings if not in common storage
if ( ! array_key_exists($this->model, DataMapper::$common))
{
// If model is 'datamapper' then this is the initial autoload by CodeIgniter
if ($this->model == 'datamapper')
{
// Load config settings
$this->config->load('datamapper', TRUE, TRUE);
// Get and store config settings
DataMapper::$config = $this->config->item('datamapper');
return;
}
// Determine table name
if (empty($this->table))
{
$this->table = plural(get_class($this));
}
// Add prefix to table
$this->table = $this->prefix . $this->table;
// Convert validation into associative array by field name
$associative_validation = array();
foreach ($this->validation as $validation)
{
// Populate associative validation array
$associative_validation[$validation['field']] = $validation;
}
$this->validation = $associative_validation;
// Get and store the table's field names and meta data
$fields = $this->db->field_data($this->table);
// Store only the field names and ensure validation list includes all fields
foreach ($fields as $field)
{
// Populate fields array
$this->fields[] = $field->name;
// Add validation if current field has none
if ( ! array_key_exists($field->name, $this->validation))
{
$this->validation[$field->name] = array('field' => $field->name, 'label' => '', 'rules' => array());
}
}
// Store common model settings
DataMapper::$common[$this->model]['table'] = $this->table;
DataMapper::$common[$this->model]['fields'] = $this->fields;
DataMapper::$common[$this->model]['validation'] = $this->validation;
}
// Load stored common model settings by reference
foreach (array_keys(DataMapper::$common[$this->model]) as $key)
{
$this->{$key} =& DataMapper::$common[$this->model][$key];
}
// Clear object properties to set at default values
$this->clear();
}
// --------------------------------------------------------------------
/**
* Autoload
*
* Autoloads object classes that are used with DataMapper.
*
* Note:
* It is important that they are autoloaded as loading them manually with
* CodeIgniter's loader class will cause DataMapper's __get and __set functions
* to not function.
*
* @access public
* @param string
* @return void
*/
static function autoload($class)
{
// Don't attempt to autoload CI_ or MY_ prefixed classes
if (in_array(substr($class, 0, 3), array('CI_', 'MY_')))
{
return;
}
// Prepare class
$class = strtolower($class);
// Prepare path
$path = APPPATH . 'models';
// Prepare file
$file = $path . '/' . $class . '.php';
// Check if file exists, require_once if it does
if (file_exists($file))
{
require_once($file);
}
else
{
// Do a recursive search of the path for the class
DataMapper::recursive_require_once($class, $path);
}
}
// --------------------------------------------------------------------
/**
* Recursive Require Once
*
* Recursively searches the path for the class, require_once if found.
*
* @access public
* @param string
* @param string
* @return void
*/
static function recursive_require_once($class, $path)
{
if ($handle = opendir($path))
{
while (FALSE !== ($dir = readdir($handle)))
{
// If dir does not contain a dot
if (strpos($dir, '.') === FALSE)
{
// Prepare recursive path
$recursive_path = $path . '/' . $dir;
// Prepare file
$file = $recursive_path . '/' . $class . '.php';
// Check if file exists, require_once if it does
if (file_exists($file))
{
require_once($file);
break;
}
else if (is_dir($recursive_path))
{
// Do a recursive search of the path for the class
DataMapper::recursive_require_once($class, $recursive_path);
}
}
}
closedir($handle);
}
}
// --------------------------------------------------------------------
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Magic methods *
* *
* The following are methods to override the default PHP behaviour. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// --------------------------------------------------------------------
/**
* Set
*
* Sets the value of the named property.
*
* @access overload
* @param string
* @param string
* @return void
*/
function __set($name, $value)
{
$this->{$name} = $value;
}
// --------------------------------------------------------------------
/**
* Get
*
* Returns the value of the named property.
* If named property is a related item, instantiate it first.
*
* @access overload
* @param string
* @return object
*/
function __get($name)
{
// Return value of the named property
if (isset($this->{$name}))
{
return $this->{$name};
}
$has_many = in_array($name, $this->has_many);
$has_one = in_array($name, $this->has_one);
// If named property is a "has many" or "has one" related item
if ($has_many OR $has_one)
{
// Instantiate it before accessing
$model = ucfirst($name);
$this->{$name} = new $model();
// Store parent data
$this->{$name}->parent = array('model' => $this->model, 'id' => $this->id);
// Check if Auto Populate for "has many" or "has one" is on
if (($has_many && $this->auto_populate_has_many) OR ($has_one && $this->auto_populate_has_one))
{
$this->{$name}->get();
}
return $this->{$name};
}
return NULL;
}
// --------------------------------------------------------------------
/**
* Call
*
* Calls the watched method.
*
* @access overload
* @param string
* @param string
* @return void
*/
function __call($method, $arguments)
{
// List of watched method names
$watched_methods = array('get_by_related_', 'get_by_related', 'get_by_', '_related_', '_related');
foreach ($watched_methods as $watched_method)
{
// See if called method is a watched method
if (strpos($method, $watched_method) !== FALSE)
{
$pieces = explode($watched_method, $method);
if ( ! empty($pieces[0]) && ! empty($pieces[1]))
{
// Watched method is in the middle
return $this->{'_' . trim($watched_method, '_')}($pieces[0], array_merge(array($pieces[1]), $arguments));
}
else
{
// Watched method is a prefix or suffix
return $this->{'_' . trim($watched_method, '_')}(str_replace($watched_method, '', $method), $arguments);
}
}
}
}
// --------------------------------------------------------------------
/**
* Clone
*
* Allows for a less shallow clone than the default PHP clone.
*
* @access overload
* @return void
*/
function __clone()
{
foreach ($this as $key => $value)
{
if (is_object($value))
{
$this->{$key} = clone($value);
}
}
}
// --------------------------------------------------------------------
/**
* To String
*
* Converts the current object into a string.
*
* @access overload
* @return void
*/
function __toString()
{
return ucfirst($this->model);
}
// --------------------------------------------------------------------
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Main methods *
* *
* The following are methods that form the main *
* functionality of DataMapper. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// --------------------------------------------------------------------
/**
* Get
*
* Get objects.
*
* @access public
* @param integer
* @param integer
* @return object
*/
function get($limit = NULL, $offset = NULL)
{
// Check if this is a related object and if so, perform a related get
if ( ! empty($this->parent))
{
// Set limit and offset
$this->limit($limit, $offset);
// If this is a "has many" related item
if (in_array($this->parent['model'], $this->has_many))
{
$this->_get_relation($this->parent['model'], $this->parent['id']);
}
// If this is a "has one" related item
if (in_array($this->parent['model'], $this->has_one))
{
$this->_get_relation($this->parent['model'], $this->parent['id']);
}
// For method chaining
return $this;
}
// Check if object has been validated
if ($this->validated)
{
// Reset validated
$this->validated = FALSE;
// Use this objects properties
$data = $this->_to_array(TRUE);
if ( ! empty($data))
{
// Clear this object to make way for new data
$this->clear();
// Get by objects properties
$query = $this->db->get_where($this->table, $data, $limit, $offset);
if ($query->num_rows() > 0)
{
// Populate all with records as objects
$this->all = $this->_to_object($query->result(), $this->model);
// Populate this object with values from first record
foreach ($query->row() as $key => $value)
{
$this->{$key} = $value;
}
}
}
}
else
{
// Clear this object to make way for new data
$this->clear();
// Get by built up query
$query = $this->db->get($this->table, $limit, $offset);
if ($query->num_rows() > 0)
{
// Populate all with records as objects
$this->all = $this->_to_object($query->result(), $this->model);
// Populate this object with values from first record
foreach ($query->row() as $key => $value)
{
$this->{$key} = $value;
}
}
}
$this->_refresh_stored_values();
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Save
*
* Saves the current record.
* If object is supplied, saves relations between this object and the supplied object(s).
*
* @access public
* @param mixed
* @return bool
*/
function save($object = '')
{
// Temporarily store the success/failure
$result = array();
// Validate this objects properties
$this->validate($object);
// If validation passed
if ($this->valid)
{
// Get current timestamp
$timestamp = ($this->local_time) ? date('Y-m-d H:i:s') : gmdate('Y-m-d H:i:s');
// Check if unix timestamp
$timestamp = ($this->unix_timestamp) ? strtotime($timestamp) : $timestamp;
// Check if object has a 'created' field
if (in_array($this->created_field, $this->fields))
{
// If created datetime is empty, set it
if (empty($this->{$this->created_field}))
{
$this->{$this->created_field} = $timestamp;
}
}
// Check if object has an 'updated' field
if (in_array($this->updated_field, $this->fields))
{
// Update updated datetime
$this->{$this->updated_field} = $timestamp;
}
// Convert this object to array
$data = $this->_to_array();
if ( ! empty($data))
{
if ( ! empty($data['id']))
{
// Prepare data to send only changed fields
foreach ($data as $field => $value)
{
// Unset field from data if it hasn't been changed
if ($this->{$field} === $this->stored->{$field})
{
unset($data[$field]);
}
}
// Check if only the 'updated' field has changed, and if so, revert it
if (count($data) == 1 && isset($data[$this->updated_field]))
{
// Revert updated
$this->{$this->updated_field} = $this->stored->{$this->updated_field};
// Unset it
unset($data[$this->updated_field]);
}
// Only go ahead with save if there is still data
if ( ! empty($data))
{
// Begin auto transaction
$this->_auto_trans_begin();
// Update existing record
$this->db->where('id', $this->id);
$this->db->update($this->table, $data);
// Complete auto transaction
$this->_auto_trans_complete('save (update)');
}
// Reset validated
$this->validated = FALSE;
$result[] = TRUE;
}
else
{
// Prepare data to send only populated fields
foreach ($data as $field => $value)
{
// Unset field from data
if ( ! isset($value))
{
unset($data[$field]);
}
}
// Begin auto transaction
$this->_auto_trans_begin();
// Create new record
$this->db->insert($this->table, $data);
// Complete auto transaction
$this->_auto_trans_complete('save (insert)');
// Assign new ID
$this->id = $this->db->insert_id();
// Reset validated
$this->validated = FALSE;
$result[] = TRUE;
}
}
$this->_refresh_stored_values();
// Check if a relationship is being saved
if ( ! empty($object))
{
// Check if it is an array of relationships
if (is_array($object))
{
// Begin auto transaction
$this->_auto_trans_begin();
foreach ($object as $obj)
{
if (is_array($obj))
{
foreach ($obj as $o)
{
$result[] = $this->_save_relation($o);
}
}
else
{
$result[] = $this->_save_relation($obj);
}
}
// Complete auto transaction
$this->_auto_trans_complete('save (relationship)');
}
else
{
// Begin auto transaction
$this->_auto_trans_begin();
// Temporarily store the success/failure
$result[] = $this->_save_relation($object);
// Complete auto transaction
$this->_auto_trans_complete('save (relationship)');
}
}
}
// If no failure was recorded, return TRUE
return ( ! empty($result) && ! in_array(FALSE, $result));
}
// --------------------------------------------------------------------
/**
* Delete
*
* Deletes the current record.
* If object is supplied, deletes relations between this object and the supplied object(s).
*
* @access public
* @param mixed
* @return bool
*/
function delete($object = '')
{
if (empty($object))
{
if ( ! empty($this->id))
{
// Begin auto transaction
$this->_auto_trans_begin();
// Delete this object
$this->db->where('id', $this->id);
$this->db->delete($this->table);
// Delete all "has many" relations for this object
foreach ($this->has_many as $model)
{
// Prepare model
$model = ucfirst($model);
$object = new $model();
// Determine relationship table name
$relationship_table = $this->_get_relationship_table($object->prefix, $object->table, $object->model);
$data = array($this->model . '_id' => $this->id);
// Delete relation
$this->db->delete($relationship_table, $data);
}
// Delete all "has one" relations for this object
foreach ($this->has_one as $model)
{
// Prepare model
$model = ucfirst($model);
$object = new $model();
// Determine relationship table name
$relationship_table = $this->_get_relationship_table($object->prefix, $object->table, $object->model);
$data = array($this->model . '_id' => $this->id);
// Delete relation
$this->db->delete($relationship_table, $data);
}
// Complete auto transaction
$this->_auto_trans_complete('delete');
// Clear this object
$this->clear();
return TRUE;
}
}
else if (is_array($object))
{
// Begin auto transaction
$this->_auto_trans_begin();
// Temporarily store the success/failure
$result = array();
foreach ($object as $obj)
{
if (is_array($obj))
{
foreach ($obj as $o)
{
$result[] = $this->_delete_relation($o);
}
}
else
{
$result[] = $this->_delete_relation($obj);
}
}
// Complete auto transaction
$this->_auto_trans_complete('delete (relationship)');
// If no failure was recorded, return TRUE
if ( ! in_array(FALSE, $result))
{
return TRUE;
}
}
else
{
// Begin auto transaction
$this->_auto_trans_begin();
// Temporarily store the success/failure
$result = $this->_delete_relation($object);
// Complete auto transaction
$this->_auto_trans_complete('delete (relationship)');
return $result;
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Delete All
*
* Deletes all records in this objects all list.
*
* @access public
* @return bool
*/
function delete_all()
{
if ( ! empty($this->all))
{
foreach ($this->all as $item)
{
if ( ! empty($item->id))
{
$item->delete();
}
}
$this->clear();
return TRUE;
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Refresh All
*
* Removes any empty objects in this objects all list.
* Only needs to be used if you are looping through the all list
* a second time and you have deleted a record the first time through.
*
* @access public
* @return bool
*/
function refresh_all()
{
if ( ! empty($this->all))
{
$all = array();
foreach ($this->all as $item)
{
if ( ! empty($item->id))
{
$all[] = $item;
}
}
$this->all = $all;
return TRUE;
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Validate
*
* Validates the value of each property against the assigned validation rules.
*
* @access public
* @param mixed
* @return object
*/
function validate($object = '')
{
// Return if validation has already been run
if ($this->validated)
{
// For method chaining
return $this;
}
// Set validated as having been run
$this->validated = TRUE;
// Clear errors
$this->error = new stdClass();
$this->error->all = array();
$this->error->string = '';
foreach ($this->fields as $field)
{
$this->error->{$field} = '';
}
// Loop through each property to be validated
foreach ($this->validation as $validation)
{
// Get validation settings
$field = $validation['field'];
$label = ( ! empty($validation['label'])) ? $validation['label'] : $field;
$rules = $validation['rules'];
// Will validate differently if this is for a related item
$related = (in_array($field, $this->has_many) OR in_array($field, $this->has_one));
// Check if property has changed since validate last ran
if ($related OR ! isset($this->stored->{$field}) OR $this->{$field} !== $this->stored->{$field})
{
// Only validate if field is related or required or has a value
if ( ! $related && ! in_array('required', $rules))
{
if ( ! isset($this->{$field}) OR $this->{$field} === '')
{
continue;
}
}
// Loop through each rule to validate this property against
foreach ($rules as $rule => $param)
{
// Check for parameter
if (is_numeric($rule))
{
$rule = $param;
$param = '';
}
// Clear result
$result = '';
// Check rule exists
if ($related)
{
// Prepare rule to use different language file lines
$rule = 'related_' . $rule;
if (method_exists($this->model, '_' . $rule))
{
// Run related rule from DataMapper or the class extending DataMapper
$result = $this->{'_' . $rule}($object, $field, $param);
}
}
else if (method_exists($this->model, '_' . $rule))
{
// Run rule from DataMapper or the class extending DataMapper
$result = $this->{'_' . $rule}($field, $param);
}
else if (method_exists($this->form_validation, $rule))
{
// Run rule from CI Form Validation
$result = $this->form_validation->{$rule}($this->{$field}, $param);
}
else if (function_exists($rule))
{
// Run rule from PHP
$this->{$field} = $rule($this->{$field});
}
// Add an error message if the rule returned FALSE
if ($result === FALSE)
{
// Get corresponding error from language file
if (FALSE === ($line = $this->lang->line($rule)))
{
$line = 'Unable to access an error message corresponding to your field name.';
}
// Check if param is an array
if (is_array($param))
{
// Convert into a string so it can be used in the error message
$param = implode(', ', $param);
// Replace last ", " with " or "
if (FALSE !== ($pos = strrpos($param, ', ')))
{
$param = substr_replace($param, ' or ', $pos, 2);
}
}
// Check if param is a validation field
if (array_key_exists($param, $this->validation))
{
// Change it to the label value
$param = $this->validation[$param]['label'];
}
// Add error message
$this->error_message($field, sprintf($line, $label, $param));
}
}
}
}
// Set whether validation passed
$this->valid = empty($this->error->all);
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Clear
*
* Clears the current object.
*
* @access public
* @return void
*/
function clear()
{
// Clear the all list
$this->all = array();
// Clear errors
$this->error = new stdClass();
$this->error->all = array();
$this->error->string = '';
// Clear this objects properties and set blank error messages in case they are accessed
foreach ($this->fields as $field)
{
$this->{$field} = NULL;
$this->error->{$field} = '';
}
// Clear this objects "has many" related objects
foreach ($this->has_many as $related)
{
unset($this->{$related});
}
// Clear this objects "has one" related objects
foreach ($this->has_one as $related)
{
unset($this->{$related});
}
// Clear the query related list
$this->query_related = array();
// Clear and refresh stored values
$this->stored = new stdClass();
$this->_refresh_stored_values();
}
// --------------------------------------------------------------------
/**
* Count
*
* Returns the total count of the objects records.
* If on a related object, returns the total count of related objects records.
*
* @access public
* @return integer
*/
function count()
{
// Check if related object
if ( ! empty($this->parent))
{
// Prepare model
$model = ucfirst($this->parent['model']);
$object = new $model();
// Determine relationship table name
$relationship_table = $this->_get_relationship_table($object->prefix, $object->table, $object->model);
$this->db->where($this->parent['model'] . '_id', $this->parent['id']);
$this->db->from($relationship_table);
// Return count
return $this->db->count_all_results();
}
else
{
$this->db->from($this->table);
// Return count
return $this->db->count_all_results();
}
}
// --------------------------------------------------------------------
/**
* Exists
*
* Returns TRUE if the current object has a database record.
*
* @access public
* @return bool
*/
function exists()
{
return ( ! empty($this->id));
}
// --------------------------------------------------------------------
/**
* Query
*
* Runs the specified query and populates the current object with the results.
*
* Warning: Use at your own risk. This will only be as reliable as your query.
*
* @access public
* @access string
* @access array
* @return void
*/
function query($sql, $binds = FALSE)
{
// Get by objects properties
$query = $this->db->query($sql, $binds);
if ($query->num_rows() > 0)
{
// Populate all with records as objects
$this->all = $this->_to_object($query->result(), $this->model);
// Populate this object with values from first record
foreach ($query->row() as $key => $value)
{
$this->{$key} = $value;
}
}
$this->_refresh_stored_values();
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Error Message
*
* Adds an error message to this objects error object.
*
* @access public
* @access string
* @access string
* @return void
*/
function error_message($field, $error)
{
if ( ! empty($field) && ! empty($error))
{
// Set field specific error
$this->error->{$field} = $this->error_prefix . $error . $this->error_suffix;
// Add field error to errors all list
$this->error->all[] = $this->error->{$field};
// Append field error to error message string
$this->error->string .= $this->error->{$field};
}
}
// --------------------------------------------------------------------
/**
* Get Clone
*
* Returns a clone of the current object.
*
* @access public
* @return object
*/
function get_clone()
{
return clone($this);
}
// --------------------------------------------------------------------
/**
* Get Copy
*
* Returns an unsaved copy of the current object.
*
* @access public
* @return object
*/
function get_copy()
{
$copy = clone($this);
$copy->id = NULL;
return $copy;
}
// --------------------------------------------------------------------
/**
* Get By
*
* Gets objects by specified field name and value.
*
* @access private
* @param string
* @param string
* @return object
*/
function _get_by($field, $value = array())
{
if (isset($value[0]))
{
$this->where($field, $value[0]);
}
return $this->get();
}
// --------------------------------------------------------------------
/**
* Get By Related
*
* Gets objects by specified related object and optionally by field name and value.
*
* @access private
* @param string
* @param mixed
* @return object
*/
function _get_by_related($model, $arguments = array())
{
if ( ! empty($model))
{
// Add model to start of arguments
$arguments = array_merge(array($model), $arguments);
}
$this->_related('where', $arguments);
return $this->get();
}
// --------------------------------------------------------------------
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Active Record methods *
* *
* The following are methods used to provide Active Record *
* functionality for data retrieval. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// --------------------------------------------------------------------
/**
* Select
*
* Sets the SELECT portion of the query.
*
* @access public
* @param string
* @param bool
* @return object
*/
function select($select = '*', $escape = NULL)
{
// Check if this is a related object
if ( ! empty($this->parent))
{
$this->db->select($this->table . '.' . $select, $escape);
}
else
{
$this->db->select($select, $escape);
}
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Select Max
*
* Sets the SELECT MAX(field) portion of a query.
*
* @access public
* @param string
* @param string
* @return object
*/
function select_max($select = '', $alias = '')
{
// Check if this is a related object
if ( ! empty($this->parent))
{
$alias = ($alias != '') ? $alias : $select;
$this->db->select_max($this->table . '.' . $select, $alias);
}
else
{
$this->db->select_max($select, $alias);
}
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Select Min
*
* Sets the SELECT MIN(field) portion of a query.
*
* @access public
* @param string
* @param string
* @return object
*/
function select_min($select = '', $alias = '')
{
// Check if this is a related object
if ( ! empty($this->parent))
{
$alias = ($alias != '') ? $alias : $select;
$this->db->select_min($this->table . '.' . $select, $alias);
}
else
{
$this->db->select_min($select, $alias);
}
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Select Avg
*
* Sets the SELECT AVG(field) portion of a query.
*
* @access public
* @param string
* @param string
* @return object
*/
function select_avg($select = '', $alias = '')
{
// Check if this is a related object
if ( ! empty($this->parent))
{
$alias = ($alias != '') ? $alias : $select;
$this->db->select_avg($this->table . '.' . $select, $alias);
}
else
{
$this->db->select_avg($select, $alias);
}
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Select Sum
*
* Sets the SELECT SUM(field) portion of a query.
*
* @access public
* @param string
* @param string
* @return object
*/
function select_sum($select = '', $alias = '')
{
// Check if this is a related object
if ( ! empty($this->parent))
{
$alias = ($alias != '') ? $alias : $select;
$this->db->select_sum($this->table . '.' . $select, $alias);
}
else
{
$this->db->select_sum($select, $alias);
}
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Distinct
*
* Sets the flag to add DISTINCT to the query.
*
* @access public
* @param bool
* @return object
*/
function distinct($value = TRUE)
{
$this->db->distinct($value);
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Get Where
*
* Get items matching the where clause.
*
* @access public
* @param mixed
* @param string
* @param string
* @return bool
*/
function get_where($where = array(), $limit = NULL, $offset = NULL)
{
$this->where($where);
return $this->get($limit, $offset);
}
// --------------------------------------------------------------------
/**
* Where
*
* Sets the WHERE portion of the query.
* Separates multiple calls with AND.
*
* Called by get_where()
*
* @access public
* @param mixed
* @param mixed
* @return object
*/
function where($key, $value = NULL, $escape = TRUE)
{
return $this->_where($key, $value, 'AND ', $escape);
}
// --------------------------------------------------------------------
/**
* Or Where
*
* Sets the WHERE portion of the query.
* Separates multiple calls with OR.
*
* @access public
* @param mixed
* @param mixed
* @return object
*/
function or_where($key, $value = NULL, $escape = TRUE)
{
return $this->_where($key, $value, 'OR ', $escape);
}
// --------------------------------------------------------------------
/**
* Where
*
* Called by where() or or_where().
*
* @access private
* @param mixed
* @param mixed
* @param string
* @param bool
* @return object
*/
function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
{
if ( ! is_array($key))
{
$key = array($key => $value);
}
// Check if this is a related object
if ( ! empty($this->parent))
{
foreach ($key as $k => $v)
{
$key[$this->table . '.' . $k] = $v;
unset($key[$k]);
}
}
$this->db->_where($key, $value, $type, $escape);
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Where In
*
* Sets the WHERE field IN ('item', 'item') SQL query joined with
* AND if appropriate.
*
* @access public
* @param string
* @param array
* @return object
*/
function where_in($key = NULL, $values = NULL)
{
return $this->_where_in($key, $values);
}
// --------------------------------------------------------------------
/**
* Or Where In
*
* Sets the WHERE field IN ('item', 'item') SQL query joined with
* OR if appropriate.
*
* @access public
* @param string
* @param array
* @return object
*/
function or_where_in($key = NULL, $values = NULL)
{
return $this->_where_in($key, $values, FALSE, 'OR ');
}
// --------------------------------------------------------------------
/**
* Where Not In
*
* Sets the WHERE field NOT IN ('item', 'item') SQL query joined with
* AND if appropriate.
*
* @access public
* @param string
* @param array
* @return object
*/
function where_not_in($key = NULL, $values = NULL)
{
return $this->_where_in($key, $values, TRUE);
}
// --------------------------------------------------------------------
/**
* Or Where Not In
*
* Sets the WHERE field NOT IN ('item', 'item') SQL query joined wuth
* OR if appropriate.
*
* @access public
* @param string
* @param array
* @return object
*/
function or_where_not_in($key = NULL, $values = NULL)
{
return $this->_where_in($key, $values, TRUE, 'OR ');
}
// --------------------------------------------------------------------
/**
* Where In
*
* Called by where_in(), or_where_in(), where_not_in(), or or_where_not_in().
*
* @access private
* @param string
* @param array
* @param bool
* @param string
* @return object
*/
function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ')
{
// Check if this is a related object
if ( ! empty($this->parent))
{
$this->db->_where_in($this->table . '.' . $key, $values, $not, $type);
}
else
{
$this->db->_where_in($key, $values, $not, $type);
}
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Like
*
* Sets the %LIKE% portion of the query.
* Separates multiple calls with AND.
*
* @access public
* @param mixed
* @param mixed
* @param string
* @return object
*/
function like($field, $match = '', $side = 'both')
{
return $this->_like($field, $match, 'AND ', $side);
}
// --------------------------------------------------------------------
/**
* Not Like
*
* Sets the NOT LIKE portion of the query.
* Separates multiple calls with AND.
*
* @access public
* @param mixed
* @param mixed
* @param string
* @return object
*/
function not_like($field, $match = '', $side = 'both')
{
return $this->_like($field, $match, 'AND ', $side, 'NOT');
}
// --------------------------------------------------------------------
/**
* Or Like
*
* Sets the %LIKE% portion of the query.
* Separates multiple calls with OR.
*
* @access public
* @param mixed
* @param mixed
* @param string
* @return object
*/
function or_like($field, $match = '', $side = 'both')
{
return $this->_like($field, $match, 'OR ', $side);
}
// --------------------------------------------------------------------
/**
* Or Not Like
*
* Sets the NOT LIKE portion of the query.
* Separates multiple calls with OR.
*
* @access public
* @param mixed
* @param mixed
* @param string
* @return object
*/
function or_not_like($field, $match = '', $side = 'both')
{
return $this->_like($field, $match, 'OR ', $side, 'NOT');
}
// --------------------------------------------------------------------
/**
* Like
*
* Sets the %LIKE% portion of the query.
* Separates multiple calls with AND.
*
* @access private
* @param mixed
* @param mixed
* @param string
* @param string
* @param string
* @return object
*/
function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '')
{
if ( ! is_array($field))
{
$field = array($field => $match);
}
// Check if this is a related object
if ( ! empty($this->parent))
{
foreach ($field as $k => $v)
{
$field[$this->table . '.' . $k] = $v;
unset($field[$k]);
}
}
$this->db->_like($field, $match, $type, $side, $not);
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Group By
*
* Sets the GROUP BY portion of the query.
*
* @access public
* @param string
* @return object
*/
function group_by($by)
{
// Check if this is a related object
if ( ! empty($this->parent))
{
$this->db->group_by($this->table . '.' . $by);
}
else
{
$this->db->group_by($by);
}
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Having
*
* Sets the HAVING portion of the query.
* Separates multiple calls with AND.
*
* @access public
* @param string
* @param string
* @param bool
* @return object
*/
function having($key, $value = '', $escape = TRUE)
{
return $this->_having($key, $value, 'AND ', $escape);
}
// --------------------------------------------------------------------
/**
* Or Having
*
* Sets the OR HAVING portion of the query.
* Separates multiple calls with OR.
*
* @access public
* @param string
* @param string
* @param bool
* @return object
*/
function or_having($key, $value = '', $escape = TRUE)
{
return $this->_having($key, $value, 'OR ', $escape);
}
// --------------------------------------------------------------------
/**
* Having
*
* Sets the HAVING portion of the query.
* Separates multiple calls with AND.
*
* @access private
* @param string
* @param string
* @param string
* @param bool
* @return object
*/
function _having($key, $value = '', $type = 'AND ', $escape = TRUE)
{
// Check if this is a related object
if ( ! empty($this->parent))
{
$this->db->_having($this->table . '.' . $key, $value, $type, $escape);
}
else
{
$this->db->_having($key, $value, $type, $escape);
}
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Order By
*
* Sets the ORDER BY portion of the query.
*
* @access public
* @param string
* @param string
* @return object
*/
function order_by($orderby, $direction = '')
{
// Check if this is a related object
if ( ! empty($this->parent))
{
$this->db->order_by($this->table . '.' . $orderby, $direction);
}
else
{
$this->db->order_by($orderby, $direction);
}
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Limit
*
* Sets the LIMIT portion of the query.
*
* @access public
* @param integer
* @param integer
* @return object
*/
function limit($value, $offset = '')
{
$this->db->limit($value, $offset);
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Offset
*
* Sets the OFFSET portion of the query.
*
* @access public
* @param integer
* @return object
*/
function offset($offset)
{
$this->db->offset($offset);
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Start Cache
*
* Starts AR caching.
*
* @access public
* @return void
*/
function start_cache()
{
$this->db->start_cache();
}
// --------------------------------------------------------------------
/**
* Stop Cache
*
* Stops AR caching.
*
* @access public
* @return void
*/
function stop_cache()
{
$this->db->stop_cache();
}
// --------------------------------------------------------------------
/**
* Flush Cache
*
* Empties the AR cache.
*
* @access public
* @return void
*/
function flush_cache()
{
$this->db->flush_cache();
}
// --------------------------------------------------------------------
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Transaction methods *
* *
* The following are methods used for transaction handling. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// --------------------------------------------------------------------
/**
* Trans Off
*
* This permits transactions to be disabled at run-time.
*
* @access public
* @return void
*/
function trans_off()
{
$this->db->trans_enabled = FALSE;
}
// --------------------------------------------------------------------
/**
* Trans Strict
*
* When strict mode is enabled, if you are running multiple groups of
* transactions, if one group fails all groups will be rolled back.
* If strict mode is disabled, each group is treated autonomously, meaning
* a failure of one group will not affect any others.
*
* @access public
* @param bool
* @return void
*/
function trans_strict($mode = TRUE)
{
$this->db->trans_strict($mode);
}
// --------------------------------------------------------------------
/**
* Trans Start
*
* Start a transaction.
*
* @access public
* @param bool
* @return void
*/
function trans_start($test_mode = FALSE)
{
$this->db->trans_start($test_mode);
}
// --------------------------------------------------------------------
/**
* Trans Complete
*
* Complete a transaction.
*
* @access public
* @return bool
*/
function trans_complete()
{
return $this->db->trans_complete();
}
// --------------------------------------------------------------------
/**
* Trans Begin
*
* Begin a transaction.
*
* @access public
* @param bool
* @return bool
*/
function trans_begin($test_mode = FALSE)
{
return $this->db->trans_begin($test_mode);
}
// --------------------------------------------------------------------
/**
* Trans Status
*
* Lets you retrieve the transaction flag to determine if it has failed.
*
* @access public
* @return bool
*/
function trans_status()
{
return $this->_trans_status;
}
// --------------------------------------------------------------------
/**
* Trans Commit
*
* Commit a transaction.
*
* @access public
* @return bool
*/
function trans_commit()
{
return $this->db->trans_commit();
}
// --------------------------------------------------------------------
/**
* Trans Rollback
*
* Rollback a transaction.
*
* @access public
* @return bool
*/
function trans_rollback()
{
return $this->db->trans_rollback();
}
// --------------------------------------------------------------------
/**
* Auto Trans Begin
*
* Begin an auto transaction if enabled.
*
* @access public
* @param bool
* @return bool
*/
function _auto_trans_begin()
{
// Begin auto transaction
if ($this->auto_transaction)
{
$this->trans_begin();
}
}
// --------------------------------------------------------------------
/**
* Auto Trans Complete
*
* Complete an auto transaction if enabled.
*
* @access public
* @param string
* @return bool
*/
function _auto_trans_complete($label = 'complete')
{
// Complete auto transaction
if ($this->auto_transaction)
{
// Check if successful
if (!$this->trans_complete())
{
$rule = 'transaction';
// Get corresponding error from language file
if (FALSE === ($line = $this->lang->line($rule)))
{
$line = 'Unable to access the ' . $rule .' error message.';
}
// Add transaction error message
$this->error_message($rule, sprintf($line, $label));
// Set validation as failed
$this->valid = FALSE;
}
}
}
// --------------------------------------------------------------------
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Related methods *
* *
* The following are methods used for managing related records. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// --------------------------------------------------------------------
/**
* Related
*
* Sets the specified related query.
*
* @access private
* @param string
* @param mixed
* @return object
*/
function _related($query, $arguments = array())
{
if ( ! empty($query) && ! empty($arguments))
{
$object = $field = $value = $option = NULL;
// Prepare model
if (is_object($arguments[0]))
{
$object = $arguments[0];
// Prepare field and value
$field = (isset($arguments[1])) ? $arguments[1] : 'id';
$value = (isset($arguments[2])) ? $arguments[2] : $object->id;
}
else
{
$model = ucfirst($arguments[0]);
$object = new $model();
// Prepare field and value
$field = (isset($arguments[1])) ? $arguments[1] : 'id';
$value = (isset($arguments[2])) ? $arguments[2] : NULL;
}
// Ignore if field and value is invalid
if ($field == 'id' && empty($value) OR $field != 'id' && $this->table == $object->table)
{
// For method chaining
return $this;
}
// Determine relationship table name
$relationship_table = $this->_get_relationship_table($object->prefix, $object->table, $object->model);
// Retrieve related records
if (empty($this->db->ar_select))
{
$this->db->select($this->table . '.*');
}
// Check if self referencing
if ($this->table == $object->table)
{
// Add join if not already included
if ( ! in_array($object->model, $this->query_related))
{
$this->db->join($relationship_table, $object->table . '.id = ' . $relationship_table . '.' . $this->model . '_id', 'left');
$this->query_related[] = $object->model;
}
// Add query clause
$this->db->{$query}($relationship_table . '.' . $object->model . '_id', $value);
}
else
{
// Add join if not already included
if ( ! in_array($object->model, $this->query_related))
{
$this->db->join($relationship_table, $this->table . '.id = ' . $relationship_table . '.' . $this->model . '_id', 'left');
$this->query_related[] = $object->model;
}
// Add join if not already included
if ( ! in_array($object->table, $this->query_related))
{
$this->db->join($object->table, $object->table . '.id = ' . $relationship_table . '.' . $object->model . '_id', 'left');
$this->query_related[] = $object->table;
}
// Add query clause
$this->db->{$query}($object->table . '.' . $field, $value);
}
}
// For method chaining
return $this;
}
// --------------------------------------------------------------------
/**
* Get Relation
*
* Finds all related records of this objects current record.
*
* @access private
* @param string
* @param integer
* @return void
*/
function _get_relation($model, $id)
{
// No related items
if (empty($model) OR empty($id))
{
// Reset query
$this->db->_reset_select();
return;
}
// Prepare model
$model = ucfirst($model);
$object = new $model();
// Determine relationship table name
$relationship_table = $this->_get_relationship_table($object->prefix, $object->table, $object->model);
// Retrieve related records
if (empty($this->db->ar_select))
{
$this->db->select($this->table . '.*');
}
// Check if self referencing
if ($this->table == $object->table)
{
$this->db->from($this->table);
$this->db->join($relationship_table, $object->table . '.id = ' . $relationship_table . '.' . $this->model . '_id', 'left');
$this->db->where($relationship_table . '.' . $object->model . '_id = ' . $id);
}
else
{
$this->db->from($this->table);
$this->db->join($relationship_table, $this->table . '.id = ' . $relationship_table . '.' . $this->model . '_id', 'left');
$this->db->join($object->table, $object->table . '.id = ' . $relationship_table . '.' . $object->model . '_id', 'left');
$this->db->where($object->table . '.id = ' . $id);
}
$query = $this->db->get();
// Clear this object to make way for new data
$this->clear();
if ($query->num_rows() > 0)
{
// Populate all with records as objects
$this->all = $this->_to_object($query->result(), $this->model);
// Populate this object with values from first record
foreach ($query->row() as $key => $value)
{
$this->{$key} = $value;
}
}
$this->_refresh_stored_values();
}
// --------------------------------------------------------------------
/**
* Save Relation
*
* Saves the relation between this and the other object.
*
* @access private
* @param object
* @return bool
*/
function _save_relation($object)
{
if ( ! empty($object->model) && ! empty($this->id) && ! empty($object->id))
{
// Determine relationship table name
$relationship_table = $this->_get_relationship_table($object->prefix, $object->table, $object->model);
$data = array($this->model . '_id' => $this->id, $object->model . '_id' => $object->id);
// Check if relation already exists
$query = $this->db->get_where($relationship_table, $data, NULL, NULL);
if ($query->num_rows() == 0)
{
// If this object has a "has many" relationship with the other object
if (in_array($object->model, $this->has_many))
{
// If the other object has a "has one" relationship with this object
if (in_array($this->model, $object->has_one))
{
// And it has an existing relation
$query = $this->db->get_where($relationship_table, array($object->model . '_id' => $object->id), 1, 0);
if ($query->num_rows() > 0)
{
// Find and update the other objects existing relation to relate with this object
$this->db->where($object->model . '_id', $object->id);
$this->db->update($relationship_table, $data);
}
else
{
// Add the relation since one doesn't exist
$this->db->insert($relationship_table, $data);
}
return TRUE;
}
else if (in_array($this->model, $object->has_many))
{
// We can add the relation since this specific relation doesn't exist, and a "has many" to "has many" relationship exists between the objects
$this->db->insert($relationship_table, $data);
return TRUE;
}
}
// If this object has a "has one" relationship with the other object
else if (in_array($object->model, $this->has_one))
{
// And it has an existing relation
$query = $this->db->get_where($relationship_table, array($this->model . '_id' => $this->id), 1, 0);
if ($query->num_rows() > 0)
{
// Find and update the other objects existing relation to relate with this object
$this->db->where($this->model . '_id', $this->id);
$this->db->update($relationship_table, $data);
}
else
{
// Add the relation since one doesn't exist
$this->db->insert($relationship_table, $data);
}
return TRUE;
}
}
else
{
// Relationship already exists
return TRUE;
}
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Delete Relation
*
* Deletes the relation between this and the other object.
*
* @access private
* @param object
* @return bool
*/
function _delete_relation($object)
{
if ( ! empty($object->model) && ! empty($this->id) && ! empty($object->id))
{
// Determine relationship table name
$relationship_table = $this->_get_relationship_table($object->prefix, $object->table, $object->model);
$data = array($this->model . '_id' => $this->id, $object->model . '_id' => $object->id);
// Delete relation
$this->db->delete($relationship_table, $data);
// Clear related object so it is refreshed on next access
$this->{$object->model} = NULL;
return TRUE;
}
return FALSE;
}
// --------------------------------------------------------------------
/**
* Get Relationship Table
*
* Determines the relationship table.
*
* @access private
* @param string
* @param string
* @param string
* @return string
*/
function _get_relationship_table($prefix, $table, $model)
{
$relationship_table = '';
// Check if self referencing
if ($this->table == $table)
{
$relationship_table = (plural($this->model) < plural($model)) ? plural($this->model) . '_' . plural($model) : plural($model) . '_' . plural($this->model);
}
else
{
$relationship_table = ($this->table < $table) ? $this->table . '_' . $table : $table . '_' . $this->table;
}
// Remove all occurances of the prefix from the relationship table
$relationship_table = str_replace($prefix, '', str_replace($this->prefix, '', $relationship_table));
// So we can prefix the beginning, using the join prefix instead, if it is set
$relationship_table = (empty($this->join_prefix)) ? $this->prefix . $relationship_table : $this->join_prefix . $relationship_table;
return $relationship_table;
}
// --------------------------------------------------------------------
/**
* Count Related
*
* Returns the number of related items in the database and in the related object.
*
* @access private
* @param string
* @param mixed
* @return integer
*/
function _count_related($model, $object = '')
{
$count = 0;
if ( ! empty($object))
{
if (is_array($object))
{
foreach ($object as $obj)
{
if (is_array($obj))
{
foreach ($obj as $o)
{
if ($o->model == $model)
{
$count++;
}
}
}
else
{
if ($obj->model == $model)
{
$count++;
}
}
}
}
else
{
if ($object->model == $model)
{
$count++;
}
}
}
if ( ! empty($model) && ! empty($this->id))
{
// Prepare model
$model = ucfirst($model);
$object = new $model();
// Store parent data
$object->parent = array('model' => $this->model, 'id' => $this->id);
$count += $object->count();
}
return $count;
}
// --------------------------------------------------------------------
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Related Validation methods *
* *
* The following are methods used to validate the *
* relationships of this object. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// --------------------------------------------------------------------
/**
* Related Required (pre-process)
*
* Checks if the related object has the required related item
* or if the required relation already exists.
*
* @access private
* @param mixed
* @param string
* @return bool
*/
function _related_required($object, $model)
{
return ($this->_count_related($model, $object) == 0) ? FALSE : TRUE;
}
// --------------------------------------------------------------------
/**
* Related Min Size (pre-process)
*
* Checks if the value of a property is at most the minimum size.
*
* @access private
* @param mixed
* @param string
* @param integer
* @return bool
*/
function _related_min_size($object, $model, $size = 0)
{
return ($this->_count_related($model, $object) < $size) ? FALSE : TRUE;
}
// --------------------------------------------------------------------
/**
* Related Max Size (pre-process)
*
* Checks if the value of a property is at most the maximum size.
*
* @access private
* @param mixed
* @param string
* @param integer
* @return bool
*/
function _related_max_size($object, $model, $size = 0)
{
return ($this->_count_related($model, $object) > $size) ? FALSE : TRUE;
}
// --------------------------------------------------------------------
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Validation methods *
* *
* The following are methods used to validate the *
* values of this objects properties. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// --------------------------------------------------------------------
/**
* Alpha Dash Dot (pre-process)
*
* Alpha-numeric with underscores, dashes and full stops.
*
* @access private
* @param string
* @return bool
*/
function _alpha_dash_dot($field)
{
return ( ! preg_match('/^([\.-a-z0-9_-])+$/i', $this->{$field})) ? FALSE : TRUE;
}
// --------------------------------------------------------------------
/**
* Alpha Slash Dot (pre-process)
*
* Alpha-numeric with underscores, dashes, forward slashes and full stops.
*
* @access private
* @param string
* @return bool
*/
function _alpha_slash_dot($field)
{
return ( ! preg_match('/^([\.\/-a-z0-9_-])+$/i', $this->{$field})) ? FALSE : TRUE;
}
// --------------------------------------------------------------------
/**
* Matches (pre-process)
*
* Match one field to another.
* This replaces the version in CI_Form_validation.
*
* @access private
* @param string
* @param string
* @return bool
*/
function _matches($field, $other_field)
{
return ($this->{$field} !== $this->{$other_field}) ? FALSE : TRUE;
}
// --------------------------------------------------------------------
/**
* Min Date (pre-process)
*
* Checks if the value of a property is at least the minimum date.
*
* @access private
* @param string
* @param string
* @return bool
*/
function _min_date($field, $date)
{
return (strtotime($this->{$field}) < strtotime($date)) ? FALSE : TRUE;
}
// --------------------------------------------------------------------
/**
* Max Date (pre-process)
*
* Checks if the value of a property is at most the maximum date.
*
* @access private
* @param string
* @param string
* @return bool
*/
function _max_date($field, $date)
{
return (strtotime($this->{$field}) > strtotime($date)) ? FALSE : TRUE;
}
// --------------------------------------------------------------------
/**
* Min Size (pre-process)
*
* Checks if the value of a property is at least the minimum size.
*
* @access private
* @param string
* @param integer
* @return bool
*/
function _min_size($field, $size)
{
return ($this->{$field} < $size) ? FALSE : TRUE;
}
// --------------------------------------------------------------------
/**
* Max Size (pre-process)
*
* Checks if the value of a property is at most the maximum size.
*
* @access private
* @param string
* @param integer
* @return bool
*/
function _max_size($field, $size)
{
return ($this->{$field} > $size) ? FALSE : TRUE;
}
// --------------------------------------------------------------------
/**
* Unique (pre-process)
*
* Checks if the value of a property is unique.
* If the property belongs to this object, we can ignore it.
*
* @access private
* @param string
* @return bool
*/
function _unique($field)
{
if ( ! empty($this->{$field}))
{
$query = $this->db->get_where($this->table, array($field => $this->{$field}), 1, 0);
if ($query->num_rows() > 0)
{
$row = $query->row();
// If unique value does not belong to this object
if ($this->id != $row->id)
{
// Then it is not unique
return FALSE;
}
}
}
// No matches found so is unique
return TRUE;
}
// --------------------------------------------------------------------
/**
* Unique Pair (pre-process)
*
* Checks if the value of a property, paired with another, is unique.
* If the properties belongs to this object, we can ignore it.
*
* @access private
* @param string
* @param string
* @return bool
*/
function _unique_pair($field, $other_field = '')
{
if ( ! empty($this->{$field}) && ! empty($this->{$other_field}))
{
$query = $this->db->get_where($this->table, array($field => $this->{$field}, $other_field => $this->{$other_field}), 1, 0);
if ($query->num_rows() > 0)
{
$row = $query->row();
// If unique pair value does not belong to this object
if ($this->id != $row->id)
{
// Then it is not a unique pair
return FALSE;
}
}
}
// No matches found so is unique
return TRUE;
}
// --------------------------------------------------------------------
/**
* Valid Date (pre-process)
*
* Checks whether the field value is a valid DateTime.
*
* @access private
* @param string
* @return bool
*/
function _valid_date($field)
{
// Ignore if empty
if (empty($this->{$field}))
{
return TRUE;
}
$date = date_parse($this->{$field});
return checkdate($date['month'], $date['day'],$date['year']);
}
// --------------------------------------------------------------------
/**
* Valid Date Group (pre-process)
*
* Checks whether the field value, grouped with other field values, is a valid DateTime.
*
* @access private
* @param string
* @param array
* @return bool
*/
function _valid_date_group($field, $fields = array())
{
// Ignore if empty
if (empty($this->{$field}))
{
return TRUE;
}
$date = date_parse($this->{$fields['year']} . '-' . $this->{$fields['month']} . '-' . $this->{$fields['day']});
return checkdate($date['month'], $date['day'],$date['year']);
}
// --------------------------------------------------------------------
/**
* Valid Match (pre-process)
*
* Checks whether the field value matches one of the specified array values.
*
* @access private
* @param string
* @param array
* @return bool
*/
function _valid_match($field, $param = array())
{
return in_array($this->{$field}, $param);
}
// --------------------------------------------------------------------
/**
* Encode PHP Tags (prep)
*
* Convert PHP tags to entities.
* This replaces the version in CI_Form_validation.
*
* @access private
* @param string
* @return void
*/
function _encode_php_tags($field)
{
$this->{$field} = encode_php_tags($this->{$field});
}
// --------------------------------------------------------------------
/**
* Prep for Form (prep)
*
* Converts special characters to allow HTML to be safely shown in a form.
* This replaces the version in CI_Form_validation.
*
* @access private
* @param string
* @return void
*/
function _prep_for_form($field)
{
$this->{$field} = $this->form_validation->prep_for_form($this->{$field});
}
// --------------------------------------------------------------------
/**
* Prep URL (prep)
*
* Adds "http://" to URLs if missing.
* This replaces the version in CI_Form_validation.
*
* @access private
* @param string
* @return void
*/
function _prep_url($field)
{
$this->{$field} = $this->form_validation->prep_url($this->{$field});
}
// --------------------------------------------------------------------
/**
* Strip Image Tags (prep)
*
* Strips the HTML from image tags leaving the raw URL.
* This replaces the version in CI_Form_validation.
*
* @access private
* @param string
* @return void
*/
function _strip_image_tags($field)
{
$this->{$field} = strip_image_tags($this->{$field});
}
// --------------------------------------------------------------------
/**
* XSS Clean (prep)
*
* Runs the data through the XSS filtering function, described in the Input Class page.
* This replaces the version in CI_Form_validation.
*
* @access private
* @param string
* @param bool
* @return void
*/
function _xss_clean($field, $is_image = FALSE)
{
$this->{$field} = xss_clean($this->{$field}, $is_image);
}
// --------------------------------------------------------------------
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Common methods *
* *
* The following are common methods used by other methods. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// --------------------------------------------------------------------
/**
* To Array
*
* Converts this objects current record into an array for database queries.
* If validate is TRUE (getting by objects properties) empty objects are ignored.
*
* @access private
* @param bool
* @return array
*/
function _to_array($validate = FALSE)
{
$data = array();
foreach ($this->fields as $field)
{
if (empty($this->{$field}) && $validate)
{
continue;
}
$data[$field] = $this->{$field};
}
return $data;
}
// --------------------------------------------------------------------
/**
* To Object
*
* Converts the query result into an array of objects.
*
* @access private
* @param array
* @param string
* @return array
*/
function _to_object($result, $model)
{
$items = array();
foreach ($result as $row)
{
$item = new $model();
foreach ($this->fields as $field)
{
if (isset($row->{$field}))
{
$item->{$field} = $row->{$field};
}
else
{
$item->{$field} = NULL;
}
}
$item->_refresh_stored_values();
$items[$item->id] = $item;
}
return $items;
}
// --------------------------------------------------------------------
/**
* Refresh Stored Values
*
* Refreshes the stored values with the current values.
*
* @access private
* @return void
*/
function _refresh_stored_values()
{
// Update stored values
foreach ($this->fields as $field)
{
$this->stored->{$field} = $this->{$field};
}
// Check if there is a "matches" validation rule
foreach ($this->validation as $validation)
{
// If there is, match the field value with the other field value
if (array_key_exists('matches', $validation['rules']))
{
$this->{$validation['field']} = $this->stored->{$validation['field']} = $this->{$validation['rules']['matches']};
}
}
}
// --------------------------------------------------------------------
/**
* Assign Libraries
*
* Assigns required CodeIgniter libraries to DataMapper.
*
* @access private
* @return void
*/
function _assign_libraries()
{
if ($CI =& get_instance())
{
// Load CodeIgniters form validation if not already loaded
if ( ! isset($CI->form_validation))
{
$CI->load->library('form_validation');
}
$this->form_validation = $CI->form_validation;
$this->lang = $CI->lang;
$this->load = $CI->load;
$this->db = $CI->db;
$this->config = $CI->config;
}
}
// --------------------------------------------------------------------
/**
* Load Languages
*
* Loads required language files.
*
* @access private
* @return void
*/
function _load_languages()
{
// Load the form validation language file
$this->lang->load('form_validation');
// Load the DataMapper language file
$this->lang->load('datamapper');
}
// --------------------------------------------------------------------
/**
* Load Helpers
*
* Loads required CodeIgniter helpers.
*
* @access private
* @return void
*/
function _load_helpers()
{
// Load inflector helper for singular and plural functions
$this->load->helper('inflector');
// Load security helper for prepping functions
$this->load->helper('security');
}
}
/* End of file datamapper.php */
/* Location: ./application/models/datamapper.php */