diff --git a/application/hooks/global.php b/application/hooks/global.php index c0af827..ba5dce4 100644 --- a/application/hooks/global.php +++ b/application/hooks/global.php @@ -1,7 +1,6 @@ - + * Copyright (c) 2011 Karsten Heiken, Eike Foken * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,7 +34,10 @@ function check_login() { $public_controllers = array('auth', 'xmlrpc'); $CI = & get_instance(); - if (!$CI->input->is_ajax_request() && !$CI->access->loggedIn() && !in_array($CI->router->class, $public_controllers)) { + if (!$CI->input->is_ajax_request() && !$CI->access->isLoggedIn() && !in_array($CI->router->class, $public_controllers)) { redirect('auth/login'); } -} \ No newline at end of file +} + +/* End of file global.php */ +/* Location: ./application/hooks/global.php */ diff --git a/application/language/de_DE/auth_lang.php b/application/language/de_DE/auth_lang.php deleted file mode 100644 index 092a886..0000000 --- a/application/language/de_DE/auth_lang.php +++ /dev/null @@ -1,20 +0,0 @@ - */ class Access { /** * Contains the CI instance. + * + * @var object */ - protected $ci; + private $CI; /** - * Contains occured messages (using the language file). + * Contains cached stuff. * - * @var string + * @var array */ - protected $messages = array(); - - /** - * Contains occured errors (using the language file). - * - * @var string - */ - protected $errors = array(); + private $cache = array(); /** * Constructor. */ public function __construct() { - $this->ci =& get_instance(); - $this->ci->load->config('auth', true); - $this->ci->load->library('email'); - $this->ci->lang->load('auth'); - $this->ci->load->model('user'); - $this->ci->load->model('group'); - $this->ci->load->helper('cookie'); + $this->CI =& get_instance(); + $this->CI->load->config('auth', true); + $this->CI->load->library('email'); + $this->CI->load->model('user'); + $this->CI->load->model('group'); + $this->CI->load->helper('cookie'); // auto-login the user if they are remembered - if (!$this->loggedIn() && get_cookie('username') && get_cookie('remember_code')) { - $this->ci->access = $this; - $this->ci->user->loginRememberedUser(); + if (!$this->isloggedIn() && get_cookie('username') && get_cookie('remember_code')) { + $this->CI->access = $this; + $this->CI->user->loginRememberedUser(); } + + log_message('debug', "Access Class Initialized"); } /** @@ -54,12 +72,12 @@ class Access { * @return boolean */ public function changePassword($username, $old, $new) { - if ($this->ci->user->changePassword($username, $old, $new)) { - $this->ci->messages->add(_('Password successfully changed'), 'success'); + if ($this->CI->user->changePassword($username, $old, $new)) { + $this->CI->messages->add(_('Password successfully changed'), 'success'); return true; } - $this->ci->messages->add(_('Unable to change password'), 'error'); + $this->CI->messages->add(_('Unable to change password'), 'error'); return false; } @@ -70,34 +88,34 @@ class Access { * @return void */ public function forgottenPassword($email) { - if ($this->ci->user->forgottenPassword($email)) { + if ($this->CI->user->forgottenPassword($email)) { // get user information - $user = $this->ci->user->getUserByEmail($email); + $user = $this->CI->user->getUserByEmail($email); $data = array( 'username' => $user['username'], 'forgotten_password_code' => $user['forgotten_password_code'], ); - $message = $this->ci->load->view('auth/email/forgot_password', $data, true); - $this->ci->email->clear(); - $config['mailtype'] = $this->ci->config->item('email_type', 'auth'); - $this->ci->email->initialize($config); - $this->ci->email->set_newline("\r\n"); - $this->ci->email->from($this->ci->config->item('admin_email', 'auth'), 'Scattport'); - $this->ci->email->to($user['email']); - $this->ci->email->subject('ScattPort - Forgotten Password Verification'); - $this->ci->email->message($message); + $message = $this->CI->load->view('auth/email/forgot_password', $data, true); + $this->CI->email->clear(); + $config['mailtype'] = $this->CI->config->item('email_type', 'auth'); + $this->CI->email->initialize($config); + $this->CI->email->set_newline("\r\n"); + $this->CI->email->from($this->CI->config->item('admin_email', 'auth'), 'Scattport'); + $this->CI->email->to($user['email']); + $this->CI->email->subject('ScattPort - Forgotten Password Verification'); + $this->CI->email->message($message); - if ($this->ci->email->send()) { - $this->ci->messages->add(_('Password reset email sent'), 'success'); + if ($this->CI->email->send()) { + $this->CI->messages->add(_('Password reset email sent'), 'success'); return true; } else { - $this->ci->messages->add(_('Unable to send password reset email'), 'error'); + $this->CI->messages->add(_('Unable to send password reset email'), 'error'); return false; } } else { - $this->ci->messages->add(_('This email address is not registered'), 'error'); + $this->CI->messages->add(_('This email address is not registered'), 'error'); return false; } } @@ -109,14 +127,14 @@ class Access { * @return void */ public function forgottenPasswordComplete($code) { - $profile = $this->ci->user->profile($code, true); // pass the code to profile + $profile = $this->CI->user->profile($code, true); // pass the code to profile if (!is_object($profile)) { - $this->ci->messages->add(_('Unable to change password'), 'error'); + $this->CI->messages->add(_('Unable to change password'), 'error'); return false; } - $new_password = $this->ci->user->forgottenPasswordComplete($code, $profile->salt); + $new_password = $this->CI->user->forgottenPasswordComplete($code, $profile->salt); if ($new_password) { $data = array( @@ -124,27 +142,27 @@ class Access { 'new_password' => $new_password ); - $message = $this->ci->load->view('auth/email/forgot_password_complete', $data, true); + $message = $this->CI->load->view('auth/email/forgot_password_complete', $data, true); - $this->ci->email->clear(); - $config['mailtype'] = $this->ci->config->item('email_type', 'auth'); - $this->ci->email->initialize($config); - $this->ci->email->set_newline("\r\n"); - $this->ci->email->from($this->ci->config->item('admin_email', 'auth'), $this->ci->config->item('site_title', 'auth')); - $this->ci->email->to($profile->email); - $this->ci->email->subject('ScattPort - New Password'); - $this->ci->email->message($message); + $this->CI->email->clear(); + $config['mailtype'] = $this->CI->config->item('email_type', 'auth'); + $this->CI->email->initialize($config); + $this->CI->email->set_newline("\r\n"); + $this->CI->email->from($this->CI->config->item('admin_email', 'auth'), $this->CI->config->item('site_title', 'auth')); + $this->CI->email->to($profile->email); + $this->CI->email->subject('ScattPort - New Password'); + $this->CI->email->message($message); - if ($this->ci->email->send()) { - $this->ci->messages->add(_('Password successfully changed'), 'success'); + if ($this->CI->email->send()) { + $this->CI->messages->add(_('Password successfully changed'), 'success'); return true; } else { - $this->ci->messages->add(_('Unable to change password'), 'error'); + $this->CI->messages->add(_('Unable to change password'), 'error'); return false; } } - $this->ci->messages->add(_('Unable to change password'), 'error'); + $this->CI->messages->add(_('Unable to change password'), 'error'); return false; } @@ -157,10 +175,10 @@ class Access { * @return boolean */ public function login($username, $password, $remember = false) { - if ($this->ci->user->login($username, $password, $remember)) { + if ($this->CI->user->login($username, $password, $remember)) { return true; } else { - $this->ci->messages->add(_('Incorrect username or password'), 'error'); + $this->CI->messages->add(_('Incorrect username or password'), 'error'); return false; } } @@ -171,9 +189,9 @@ class Access { * @return boolean */ public function logout() { - $this->ci->session->unset_userdata('username'); - $this->ci->session->unset_userdata('group'); - $this->ci->session->unset_userdata('user_id'); + $this->CI->session->unset_userdata('username'); + $this->CI->session->unset_userdata('group'); + $this->CI->session->unset_userdata('user_id'); // delete the remember cookies if they exist if (get_cookie('username')) { @@ -182,20 +200,29 @@ class Access { delete_cookie('remember_code'); } - $this->ci->session->sess_destroy(); - $this->ci->session->sess_create(); + $this->CI->session->sess_destroy(); + $this->CI->session->sess_create(); - $this->ci->messages->add(_('Logged out successfully'), 'success'); + $this->CI->messages->add(_('Logged out successfully'), 'success'); return true; } + /** + * Kept for backwards compatibility. + * + * @see Access::isLoggedIn() + */ + public function loggedIn() { + return $this->isLoggedIn(); + } + /** * Checks if the user is logged in. * * @return boolean */ - public function loggedIn() { - return (boolean) $this->ci->session->userdata('username'); + public function isLoggedIn() { + return (boolean) $this->CI->session->userdata('username'); } /** @@ -205,18 +232,18 @@ class Access { */ public function isAdmin() { $adminGroup = 'admins'; - $userGroup = $this->ci->session->userdata('group'); + $userGroup = $this->CI->session->userdata('group'); return $userGroup == $adminGroup; } /** - * Checks if the current user is assigned to the specified group. + * Checks if the current user is assigned to the speCIfied group. * * @param string $checkGroup * @return boolean */ public function isGroup($checkGroup) { - $userGroup = $this->ci->session->userdata('group'); + $userGroup = $this->CI->session->userdata('group'); if (is_array($checkGroup)) { return in_array($userGroup, $checkGroup); @@ -230,7 +257,7 @@ class Access { * @return object */ public function getCurrentUser() { - return $this->ci->user->getUserByID($this->ci->session->userdata('user_id')); + return $this->CI->user->getUserByID($this->CI->session->userdata('user_id')); } /** @@ -239,7 +266,10 @@ class Access { * @return array */ public function profile() { - return $this->ci->user->profile($this->ci->session->userdata('username')); + if (!isset($this->cache['profile']->username)) { + $this->cache['profile'] = $this->CI->user->profile($this->CI->session->userdata('username')); + } + return $this->cache['profile']; } } diff --git a/application/libraries/Assets.php b/application/libraries/Assets.php index d38b64f..37f29f6 100644 --- a/application/libraries/Assets.php +++ b/application/libraries/Assets.php @@ -1,7 +1,30 @@ */ class Assets { @@ -12,6 +35,11 @@ class Assets { private $css = array(); private $javascript = array(); + /** + * Contains the CI instance. + * + * @var object + */ private $CI; /** @@ -44,6 +72,7 @@ class Assets { * @param string $type * @param string $filename * @param mixed $attributes + * @return string */ public function load($type, $filename, $attributes = '') { // validate type parameter diff --git a/application/libraries/datamapper.php b/application/libraries/Datamapper.php similarity index 95% rename from application/libraries/datamapper.php rename to application/libraries/Datamapper.php index 9c66201..3c54134 100644 --- a/application/libraries/datamapper.php +++ b/application/libraries/Datamapper.php @@ -1,3124 +1,3124 @@ -_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 */ \ No newline at end of file +_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 */ diff --git a/application/libraries/Job.php b/application/libraries/Job.php deleted file mode 100644 index 35f9be6..0000000 --- a/application/libraries/Job.php +++ /dev/null @@ -1,48 +0,0 @@ - - */ -class Job { - - private $CI; - - /** - * Constructor. - */ - public function __construct() { - $this->CI =& get_instance(); - - // load models - $this->CI->load->model('program'); - $this->CI->load->model('experiment'); - - log_message('debug', "Job Class Initialized"); - } - - /** - * - * @param string $experimentId - * @return boolean Returns TRUE on success. - */ - public function createConfigs($experimentId) { - $experiment = $this->CI->experiment->getById($experimentId); - $path = FCPATH . 'uploads/' . $experiment['project_id'] . '/' . $experiment['id'] . '/'; - - $program = $this->CI->program->getById($experiment['program_id']); - - $handler = fopen($path . 'default.calc', "w"); - - $parameters = $this->CI->experiment->getParameters($experimentId); - foreach ($parameters as $param) { - $line = str_replace("{type}", $param['type'], $program['input_line']); - $line = str_replace("{param}", $param['name'], $line); - $line = str_replace("{value}", $param['value'], $line); - fwrite($handler, $line); - } - fclose($handler); - - return true; - } -} \ No newline at end of file diff --git a/application/libraries/Jsmin.php b/application/libraries/Jsmin.php index c8dd9e6..6d88caf 100644 --- a/application/libraries/Jsmin.php +++ b/application/libraries/Jsmin.php @@ -1,4 +1,5 @@ - * @copyright 2002 Douglas Crockford (jsmin.c) * @copyright 2008 Ryan Grove (PHP port) diff --git a/application/libraries/Lang_detect.php b/application/libraries/Lang_detect.php index b1c6843..e518190 100644 --- a/application/libraries/Lang_detect.php +++ b/application/libraries/Lang_detect.php @@ -1,11 +1,53 @@ - + */ class Lang_detect { + /** + * Contains the CI instance. + * + * @var object + */ private $CI; + /** + * Contains all supported languages. + * + * @var array + */ private $supportedLanguages = array(); + /** + * Contains the detected language. + * + * @var string + */ private $language = ''; /** diff --git a/application/libraries/MY_Form_validation.php b/application/libraries/MY_Form_validation.php index a3ffcd9..cc2711b 100644 --- a/application/libraries/MY_Form_validation.php +++ b/application/libraries/MY_Form_validation.php @@ -1,4 +1,25 @@ - */ class MY_Form_validation extends CI_Form_validation { diff --git a/application/libraries/MY_Session.php b/application/libraries/MY_Session.php index 90fd5d6..23ccc0e 100644 --- a/application/libraries/MY_Session.php +++ b/application/libraries/MY_Session.php @@ -1,8 +1,30 @@ - + * Copyright (c) 2006 Vijay Mahrra & Sheikh Ahmed * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * + * @package ScattPort * @author Vijay Mahrra & Sheikh Ahmed * @author Eike Foken * @link http://www.designbyfail.com/ @@ -15,8 +16,19 @@ */ class Messages { - var $_ci; - var $_types = array('success', 'error', 'notice'); + /** + * Contains the CI instance. + * + * @var object + */ + private $CI; + + /** + * Contains the available message types. + * + * @var array + */ + private $types = array('success', 'error', 'notice'); /** * Constructor. @@ -24,10 +36,10 @@ class Messages { * @param array $params */ public function __construct($params = array()) { - $this->_ci =& get_instance(); - $this->_ci->load->library('session'); + $this->CI =& get_instance(); + $this->CI->load->library('session'); // check if theres already messages, if not, initialise the messages array in the session - $messages = $this->_ci->session->userdata('messages'); + $messages = $this->CI->session->userdata('messages'); if (empty($messages)) { $this->clear(); } @@ -38,22 +50,22 @@ class Messages { */ public function clear() { $messages = array(); - foreach ($this->_types as $type) { + foreach ($this->types as $type) { $messages[$type] = array(); } - $this->_ci->session->set_userdata('messages', $messages); + $this->CI->session->set_userdata('messages', $messages); } /** * Adds a message (default type is 'notice'). */ public function add($message, $type = 'notice') { - $messages = $this->_ci->session->userdata('messages'); + $messages = $this->CI->session->userdata('messages'); // handle PEAR errors gracefully if (is_a($message, 'PEAR_Error')) { $message = $message->getMessage(); $type = 'error'; - } else if (!in_array($type, $this->_types)) { + } else if (!in_array($type, $this->types)) { // set the type to message if the user specified a type that's unknown $type = 'notice'; } @@ -61,7 +73,7 @@ class Messages { if (!in_array($message, $messages[$type]) && is_string($message)) { $messages[$type][] = $message; } - $messages = $this->_ci->session->set_userdata('messages', $messages); + $messages = $this->CI->session->set_userdata('messages', $messages); } /** @@ -71,13 +83,13 @@ class Messages { * @return boolean|integer */ public function sum($type = null) { - $messages = $this->_ci->session->userdata('messages'); + $messages = $this->CI->session->userdata('messages'); if (!empty($type)) { $i = count($messages[$type]); return $i; } $i = 0; - foreach ($this->_types as $type) { + foreach ($this->types as $type) { $i += count($messages[$type]); } return $i > 0 ? $i : false; @@ -90,7 +102,7 @@ class Messages { * @return mixed */ public function get($type = null) { - $messages = $this->_ci->session->userdata('messages'); + $messages = $this->CI->session->userdata('messages'); if (!empty($type)) { if (count($messages[$type]) == 0) { return false; @@ -99,7 +111,7 @@ class Messages { } // return false if there actually are no messages in the session $i = 0; - foreach ($this->_types as $type) { + foreach ($this->types as $type) { $i += count($messages[$type]); } if ($i == 0) { @@ -108,7 +120,7 @@ class Messages { // order return by order of type array above // i.e. success, error, warning and then informational messages last - foreach ($this->_types as $type) { + foreach ($this->types as $type) { $return[$type] = $messages[$type]; } $this->clear(); diff --git a/application/libraries/Program_runner.php b/application/libraries/Program_runner.php index d534971..383c1b9 100644 --- a/application/libraries/Program_runner.php +++ b/application/libraries/Program_runner.php @@ -1,7 +1,38 @@ - + */ class Program_runner { + /** + * Constains the CI instance. + * + * @var object + */ private $CI; /** @@ -44,3 +75,6 @@ class Program_runner { } } + +/* End of file Program_runner.php */ +/* Location: ./application/libraries/Program_runner.php */ diff --git a/application/models/user.php b/application/models/user.php index 3a34443..c719851 100644 --- a/application/models/user.php +++ b/application/models/user.php @@ -233,10 +233,7 @@ class User extends CI_Model { */ public function profile($username = '', $isCode = false) { if (empty($username)) { - @$username = $this->session->userdata('username'); - if (empty($username)) { - return false; - } + return false; } $this->db->select('users.*, groups.name AS `group`, groups.description AS `group_description`'); diff --git a/application/views/header.php b/application/views/header.php index fc8e3ca..e08c3a8 100644 --- a/application/views/header.php +++ b/application/views/header.php @@ -54,7 +54,7 @@ ?> - +