From adb6fd862a0a189d2fda1b28c40b6c909c7153c5 Mon Sep 17 00:00:00 2001 From: dimonneon Date: Wed, 8 Jul 2015 12:56:38 +0300 Subject: [PATCH 1/3] Change database connection on a per-model basis by declaring the instance variable --- README.md | 4 +- core/MY_Model.php | 179 +++++----------------------------------------- 2 files changed, 20 insertions(+), 163 deletions(-) diff --git a/README.md b/README.md index 38fc601..76845bc 100644 --- a/README.md +++ b/README.md @@ -315,14 +315,14 @@ Database Connection The class will automatically use the default database connection, and even load it for you if you haven't yet. -You can specify a database connection on a per-model basis by declaring the _$\_db\_group_ instance variable. This is equivalent to calling `$this->db->database($this->_db_group, TRUE)`. +You can specify a database connection on a per-model basis by declaring the _$\_db\_group_ instance variable. This is equivalent to calling `$this->db->database($this->_database, TRUE)`. See ["Connecting to your Database"](http://ellislab.com/codeigniter/user-guide/database/connecting.html) for more information. ```php class Post_model extends MY_Model { - public $_db_group = 'group_name'; + public $_database = 'group_name'; } ``` diff --git a/core/MY_Model.php b/core/MY_Model.php index 05add98..61f8396 100644 --- a/core/MY_Model.php +++ b/core/MY_Model.php @@ -6,33 +6,27 @@ * @link http://github.com/jamierumbelow/codeigniter-base-model * @copyright Copyright (c) 2012, Jamie Rumbelow */ - class MY_Model extends CI_Model { - /* -------------------------------------------------------------- * VARIABLES * ------------------------------------------------------------ */ - /** * This model's default database table. Automatically * guessed by pluralising the model name. */ protected $_table; - /** - * The database connection object. Will be set to the default - * connection. This allows individual models to use different DBs + * The database connection group object. Will be set to the default + * connection. This allows individual models to use different DB groups * without overwriting CI's global $this->db connection. */ public $_database; - /** * This model's default primary key or unique identifier. * Used by the get(), update() and delete() functions. */ protected $primary_key = 'id'; - /** * Support for soft deletes and this model's 'deleted' key */ @@ -40,7 +34,6 @@ class MY_Model extends CI_Model protected $soft_delete_key = 'deleted'; protected $_temporary_with_deleted = FALSE; protected $_temporary_only_deleted = FALSE; - /** * The various callbacks available to the model. Each are * simple lists of method names (methods will be run on $this). @@ -53,46 +46,37 @@ class MY_Model extends CI_Model protected $after_get = array(); protected $before_delete = array(); protected $after_delete = array(); - protected $callback_parameters = array(); - /** * Protected, non-modifiable attributes */ protected $protected_attributes = array(); - /** * Relationship arrays. Use flat strings for defaults or string * => array to customise the class name and primary key */ protected $belongs_to = array(); protected $has_many = array(); - protected $_with = array(); - /** * An array of validation rules. This needs to be the same format * as validation rules passed to the Form_validation library. */ protected $validate = array(); - /** * Optionally skip the validation. Used in conjunction with * skip_validation() to skip data validation for any future calls. */ protected $skip_validation = FALSE; - /** * By default we return our results as objects. If we need to override * this, we can, or, we could use the `as_array()` and `as_object()` scopes. */ protected $return_type = 'object'; protected $_temporary_return_type = NULL; - /* -------------------------------------------------------------- * GENERIC METHODS * ------------------------------------------------------------ */ - /** * Initialise the model, tie into the CodeIgniter superobject and * try our best to guess the table name. @@ -100,31 +84,27 @@ class MY_Model extends CI_Model public function __construct() { parent::__construct(); - $this->load->helper('inflector'); - $this->_fetch_table(); + if($this->_database){ + $this->db = $this->load->database($this->_database, TRUE); + } $this->_database = $this->db; - array_unshift($this->before_create, 'protect_attributes'); array_unshift($this->before_update, 'protect_attributes'); - $this->_temporary_return_type = $this->return_type; } - /* -------------------------------------------------------------- * CRUD INTERFACE * ------------------------------------------------------------ */ - /** * Fetch a single record based on the primary key. Returns an object. */ public function get($primary_value) { - return $this->get_by($this->primary_key, $primary_value); + return $this->get_by($this->primary_key, $primary_value); } - /** * Fetch a single record based on an arbitrary WHERE call. Can be * any valid value to $this->_database->where(). @@ -132,36 +112,27 @@ public function get($primary_value) public function get_by() { $where = func_get_args(); - if ($this->soft_delete && $this->_temporary_with_deleted !== TRUE) { $this->_database->where($this->soft_delete_key, (bool)$this->_temporary_only_deleted); } - - $this->_set_where($where); - + $this->_set_where($where); $this->trigger('before_get'); - $row = $this->_database->get($this->_table) ->{$this->_return_type()}(); $this->_temporary_return_type = $this->return_type; - $row = $this->trigger('after_get', $row); - $this->_with = array(); return $row; } - /** * Fetch an array of records based on an array of primary values. */ public function get_many($values) { $this->_database->where_in($this->primary_key, $values); - return $this->get_all(); } - /** * Fetch an array of records based on an arbitrary WHERE call. */ @@ -170,10 +141,8 @@ public function get_many_by() $where = func_get_args(); $this->_set_where($where); - return $this->get_all(); } - /** * Fetch all the records in the table. Can be used as a generic call * to $this->_database->get() with scoped methods. @@ -181,25 +150,20 @@ public function get_many_by() public function get_all() { $this->trigger('before_get'); - if ($this->soft_delete && $this->_temporary_with_deleted !== TRUE) { $this->_database->where($this->soft_delete_key, (bool)$this->_temporary_only_deleted); } - $result = $this->_database->get($this->_table) ->{$this->_return_type(1)}(); $this->_temporary_return_type = $this->return_type; - foreach ($result as $key => &$row) { $row = $this->trigger('after_get', $row, ($key == count($result) - 1)); } - $this->_with = array(); return $result; } - /** * Insert a new row into the table. $data should be an associative array * of data to be inserted. Returns newly created ID. @@ -210,16 +174,12 @@ public function insert($data, $skip_validation = FALSE) { $data = $this->validate($data); } - if ($data !== FALSE) { $data = $this->trigger('before_create', $data); - $this->_database->insert($this->_table, $data); $insert_id = $this->_database->insert_id(); - $this->trigger('after_create', $insert_id); - return $insert_id; } else @@ -227,42 +187,34 @@ public function insert($data, $skip_validation = FALSE) return FALSE; } } - /** * Insert multiple rows into the table. Returns an array of multiple IDs. */ public function insert_many($data, $skip_validation = FALSE) { $ids = array(); - foreach ($data as $key => $row) { $ids[] = $this->insert($row, $skip_validation, ($key == count($data) - 1)); } - return $ids; } - /** * Updated a record based on the primary value. */ public function update($primary_value, $data, $skip_validation = FALSE) { $data = $this->trigger('before_update', $data); - if ($skip_validation === FALSE) { $data = $this->validate($data); } - if ($data !== FALSE) { $result = $this->_database->where($this->primary_key, $primary_value) ->set($data) ->update($this->_table); - $this->trigger('after_update', array($data, $result)); - return $result; } else @@ -270,27 +222,22 @@ public function update($primary_value, $data, $skip_validation = FALSE) return FALSE; } } - /** * Update many records, based on an array of primary values. */ public function update_many($primary_values, $data, $skip_validation = FALSE) { $data = $this->trigger('before_update', $data); - if ($skip_validation === FALSE) { $data = $this->validate($data); } - if ($data !== FALSE) { $result = $this->_database->where_in($this->primary_key, $primary_values) ->set($data) ->update($this->_table); - $this->trigger('after_update', array($data, $result)); - return $result; } else @@ -298,7 +245,6 @@ public function update_many($primary_values, $data, $skip_validation = FALSE) return FALSE; } } - /** * Updated a record based on an arbitrary WHERE clause. */ @@ -306,16 +252,13 @@ public function update_by() { $args = func_get_args(); $data = array_pop($args); - $data = $this->trigger('before_update', $data); - if ($this->validate($data) !== FALSE) { $this->_set_where($args); $result = $this->_database->set($data) ->update($this->_table); $this->trigger('after_update', array($data, $result)); - return $result; } else @@ -323,7 +266,6 @@ public function update_by() return FALSE; } } - /** * Update all records */ @@ -333,19 +275,15 @@ public function update_all($data) $result = $this->_database->set($data) ->update($this->_table); $this->trigger('after_update', array($data, $result)); - return $result; } - /** * Delete a row from the table by the primary value */ public function delete($id) { $this->trigger('before_delete', $id); - $this->_database->where($this->primary_key, $id); - if ($this->soft_delete) { $result = $this->_database->update($this->_table, array( $this->soft_delete_key => TRUE )); @@ -354,24 +292,17 @@ public function delete($id) { $result = $this->_database->delete($this->_table); } - $this->trigger('after_delete', $result); - return $result; } - /** * Delete a row from the database table by an arbitrary WHERE clause */ public function delete_by() { $where = func_get_args(); - - $where = $this->trigger('before_delete', $where); - + $where = $this->trigger('before_delete', $where); $this->_set_where($where); - - if ($this->soft_delete) { $result = $this->_database->update($this->_table, array( $this->soft_delete_key => TRUE )); @@ -380,21 +311,16 @@ public function delete_by() { $result = $this->_database->delete($this->_table); } - $this->trigger('after_delete', $result); - return $result; } - /** * Delete many rows from the database table by multiple primary values */ public function delete_many($primary_values) { $primary_values = $this->trigger('before_delete', $primary_values); - $this->_database->where_in($this->primary_key, $primary_values); - if ($this->soft_delete) { $result = $this->_database->update($this->_table, array( $this->soft_delete_key => TRUE )); @@ -403,46 +329,35 @@ public function delete_many($primary_values) { $result = $this->_database->delete($this->_table); } - $this->trigger('after_delete', $result); - return $result; } - - /** * Truncates the table */ public function truncate() { $result = $this->_database->truncate($this->_table); - return $result; } - /* -------------------------------------------------------------- * RELATIONSHIPS * ------------------------------------------------------------ */ - public function with($relationship) { $this->_with[] = $relationship; - if (!in_array('relate', $this->after_get)) { $this->after_get[] = 'relate'; } - return $this; } - public function relate($row) { - if (empty($row)) + if (empty($row)) { - return $row; + return $row; } - foreach ($this->belongs_to as $key => $value) { if (is_string($value)) @@ -455,11 +370,9 @@ public function relate($row) $relationship = $key; $options = $value; } - if (in_array($relationship, $this->_with)) { $this->load->model($options['model'], $relationship . '_model'); - if (is_object($row)) { $row->{$relationship} = $this->{$relationship . '_model'}->get($row->{$options['primary_key']}); @@ -470,7 +383,6 @@ public function relate($row) } } } - foreach ($this->has_many as $key => $value) { if (is_string($value)) @@ -483,11 +395,9 @@ public function relate($row) $relationship = $key; $options = $value; } - if (in_array($relationship, $this->_with)) { $this->load->model($options['model'], $relationship . '_model'); - if (is_object($row)) { $row->{$relationship} = $this->{$relationship . '_model'}->get_many_by($options['primary_key'], $row->{$this->primary_key}); @@ -498,21 +408,17 @@ public function relate($row) } } } - return $row; } - /* -------------------------------------------------------------- * UTILITY METHODS * ------------------------------------------------------------ */ - /** * Retrieve and generate a form_dropdown friendly array */ function dropdown() { $args = func_get_args(); - if(count($args) == 2) { list($key, $value) = $args; @@ -522,30 +428,22 @@ function dropdown() $key = $this->primary_key; $value = $args[0]; } - $this->trigger('before_dropdown', array( $key, $value )); - if ($this->soft_delete && $this->_temporary_with_deleted !== TRUE) { $this->_database->where($this->soft_delete_key, FALSE); } - $result = $this->_database->select(array($key, $value)) ->get($this->_table) ->result(); - $options = array(); - foreach ($result as $row) { $options[$row->{$key}] = $row->{$value}; } - $options = $this->trigger('after_dropdown', $options); - return $options; } - /** * Fetch a count of rows based on an arbitrary WHERE call. */ @@ -555,13 +453,10 @@ public function count_by() { $this->_database->where($this->soft_delete_key, (bool)$this->_temporary_only_deleted); } - $where = func_get_args(); $this->_set_where($where); - return $this->_database->count_all_results($this->_table); } - /** * Fetch a total count of rows, disregarding any previous conditions */ @@ -571,10 +466,8 @@ public function count_all() { $this->_database->where($this->soft_delete_key, (bool)$this->_temporary_only_deleted); } - return $this->_database->count_all($this->_table); } - /** * Tell the class to skip the insert validation */ @@ -583,7 +476,6 @@ public function skip_validation() $this->skip_validation = TRUE; return $this; } - /** * Get the skip validation status */ @@ -591,7 +483,6 @@ public function get_skip_validation() { return $this->skip_validation; } - /** * Return the next auto increment of the table. Only tested on MySQL. */ @@ -602,7 +493,6 @@ public function get_next_id() ->where('TABLE_NAME', $this->_table) ->where('TABLE_SCHEMA', $this->_database->database)->get()->row()->AUTO_INCREMENT; } - /** * Getter for the table name */ @@ -610,11 +500,9 @@ public function table() { return $this->_table; } - /* -------------------------------------------------------------- * GLOBAL SCOPES * ------------------------------------------------------------ */ - /** * Return the next call as an array rather than an object */ @@ -623,7 +511,6 @@ public function as_array() $this->_temporary_return_type = 'array'; return $this; } - /** * Return the next call as an object rather than an array */ @@ -632,7 +519,6 @@ public function as_object() $this->_temporary_return_type = 'object'; return $this; } - /** * Don't care about soft deleted rows on the next call */ @@ -641,7 +527,6 @@ public function with_deleted() $this->_temporary_with_deleted = TRUE; return $this; } - /** * Only get deleted rows on the next call */ @@ -650,11 +535,9 @@ public function only_deleted() $this->_temporary_only_deleted = TRUE; return $this; } - /* -------------------------------------------------------------- * OBSERVERS * ------------------------------------------------------------ */ - /** * MySQL DATETIME created_at and updated_at */ @@ -668,10 +551,8 @@ public function created_at($row) { $row['created_at'] = date('Y-m-d H:i:s'); } - return $row; } - public function updated_at($row) { if (is_object($row)) @@ -682,10 +563,8 @@ public function updated_at($row) { $row['updated_at'] = date('Y-m-d H:i:s'); } - return $row; } - /** * Serialises data for you automatically, allowing you to pass * through objects and let it handle the serialisation in the background @@ -696,10 +575,8 @@ public function serialize($row) { $row[$column] = serialize($row[$column]); } - return $row; } - public function unserialize($row) { foreach ($this->callback_parameters as $column) @@ -713,10 +590,8 @@ public function unserialize($row) $row->$column = unserialize($row->$column); } } - return $row; } - /** * Protect attributes by removing them from $row array */ @@ -733,14 +608,11 @@ public function protect_attributes($row) unset($row[$attr]); } } - return $row; } - /* -------------------------------------------------------------- * QUERY BUILDER DIRECT ACCESS METHODS * ------------------------------------------------------------ */ - /** * A wrapper to $this->_database->order_by() */ @@ -759,7 +631,6 @@ public function order_by($criteria, $order = 'ASC') } return $this; } - /** * A wrapper to $this->_database->limit() */ @@ -768,11 +639,9 @@ public function limit($limit, $offset = 0) $this->_database->limit($limit, $offset); return $this; } - /* -------------------------------------------------------------- * INTERNAL METHODS * ------------------------------------------------------------ */ - /** * Trigger an event and call its observers. Pass through the event name * (which looks for an instance variable $this->event_name), an array of @@ -787,18 +656,14 @@ public function trigger($event, $data = FALSE, $last = TRUE) if (strpos($method, '(')) { preg_match('/([a-zA-Z0-9\_\-]+)(\(([a-zA-Z0-9\_\-\., ]+)\))?/', $method, $matches); - $method = $matches[1]; $this->callback_parameters = explode(',', $matches[3]); } - $data = call_user_func_array(array($this, $method), array($data, $last)); } } - return $data; } - /** * Run validation on the passed data */ @@ -808,20 +673,16 @@ public function validate($data) { return $data; } - if(!empty($this->validate)) { foreach($data as $key => $val) { $_POST[$key] = $val; } - $this->load->library('form_validation'); - if(is_array($this->validate)) { $this->form_validation->set_rules($this->validate); - if ($this->form_validation->run() === TRUE) { return $data; @@ -848,7 +709,6 @@ public function validate($data) return $data; } } - /** * Guess the table name by pluralising the model name */ @@ -859,7 +719,6 @@ private function _fetch_table() $this->_table = plural(preg_replace('/(_m|_model)?$/', '', strtolower(get_class($this)))); } } - /** * Guess the primary key for current table */ @@ -870,7 +729,6 @@ private function _fetch_primary_key() $this->primary_key = $this->_database->query("SHOW KEYS FROM `".$this->_table."` WHERE Key_name = 'PRIMARY'")->row()->Column_name; } } - /** * Set WHERE parameters, cleverly */ @@ -901,8 +759,8 @@ protected function _set_where($params) { $this->_database->where($params[0]); } - else if(count($params) == 2) - { + else if(count($params) == 2) + { if (is_array($params[1])) { $this->_database->where_in($params[0], $params[1]); @@ -911,11 +769,11 @@ protected function _set_where($params) { $this->_database->where($params[0], $params[1]); } - } - else if(count($params) == 3) - { - $this->_database->where($params[0], $params[1], $params[2]); - } + } + else if(count($params) == 3) + { + $this->_database->where($params[0], $params[1], $params[2]); + } else { if (is_array($params[1])) @@ -928,7 +786,6 @@ protected function _set_where($params) } } } - /** * Return the method name for the current return type */ @@ -937,4 +794,4 @@ protected function _return_type($multi = FALSE) $method = ($multi) ? 'result' : 'row'; return $this->_temporary_return_type == 'array' ? $method . '_array' : $method; } -} +} \ No newline at end of file From 8759bb9e00f04c1cb880460275a35cacff3688e5 Mon Sep 17 00:00:00 2001 From: dimonneon Date: Wed, 8 Jul 2015 13:05:15 +0300 Subject: [PATCH 2/3] Specify a database connection on a per-model basis by declaring the instance variable --- README.md | 4 ++-- core/MY_Model.php | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 38fc601..f2b9a19 100644 --- a/README.md +++ b/README.md @@ -315,14 +315,14 @@ Database Connection The class will automatically use the default database connection, and even load it for you if you haven't yet. -You can specify a database connection on a per-model basis by declaring the _$\_db\_group_ instance variable. This is equivalent to calling `$this->db->database($this->_db_group, TRUE)`. +You can specify a database connection on a per-model basis by declaring the _$\_database_ instance variable. This is equivalent to calling `$this->db->database($this->_database, TRUE)`. See ["Connecting to your Database"](http://ellislab.com/codeigniter/user-guide/database/connecting.html) for more information. ```php class Post_model extends MY_Model { - public $_db_group = 'group_name'; + public $_database = 'group_name'; } ``` diff --git a/core/MY_Model.php b/core/MY_Model.php index 05add98..671d4fa 100644 --- a/core/MY_Model.php +++ b/core/MY_Model.php @@ -21,8 +21,8 @@ class MY_Model extends CI_Model protected $_table; /** - * The database connection object. Will be set to the default - * connection. This allows individual models to use different DBs + * The database connection object. Will be set to the default group + * connection. This allows individual models to use different DB groups * without overwriting CI's global $this->db connection. */ public $_database; @@ -105,6 +105,9 @@ public function __construct() $this->_fetch_table(); + if($this->_database){ + $this->db = $this->load->database($this->_database, TRUE); + } $this->_database = $this->db; array_unshift($this->before_create, 'protect_attributes'); From 01978150e9fc386e8775153ee81d0cf657c421c1 Mon Sep 17 00:00:00 2001 From: dimonneon Date: Fri, 24 Jul 2015 00:11:54 +0300 Subject: [PATCH 3/3] Add wrapper to ->_database->group_by() method --- README.md | 4 +- core/MY_Model.php | 200 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 184 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 76845bc..38fc601 100644 --- a/README.md +++ b/README.md @@ -315,14 +315,14 @@ Database Connection The class will automatically use the default database connection, and even load it for you if you haven't yet. -You can specify a database connection on a per-model basis by declaring the _$\_db\_group_ instance variable. This is equivalent to calling `$this->db->database($this->_database, TRUE)`. +You can specify a database connection on a per-model basis by declaring the _$\_db\_group_ instance variable. This is equivalent to calling `$this->db->database($this->_db_group, TRUE)`. See ["Connecting to your Database"](http://ellislab.com/codeigniter/user-guide/database/connecting.html) for more information. ```php class Post_model extends MY_Model { - public $_database = 'group_name'; + public $_db_group = 'group_name'; } ``` diff --git a/core/MY_Model.php b/core/MY_Model.php index 61f8396..b7bd13c 100644 --- a/core/MY_Model.php +++ b/core/MY_Model.php @@ -6,27 +6,33 @@ * @link http://github.com/jamierumbelow/codeigniter-base-model * @copyright Copyright (c) 2012, Jamie Rumbelow */ + class MY_Model extends CI_Model { + /* -------------------------------------------------------------- * VARIABLES * ------------------------------------------------------------ */ + /** * This model's default database table. Automatically * guessed by pluralising the model name. */ protected $_table; + /** - * The database connection group object. Will be set to the default - * connection. This allows individual models to use different DB groups + * The database connection object. Will be set to the default + * connection. This allows individual models to use different DBs * without overwriting CI's global $this->db connection. */ public $_database; + /** * This model's default primary key or unique identifier. * Used by the get(), update() and delete() functions. */ protected $primary_key = 'id'; + /** * Support for soft deletes and this model's 'deleted' key */ @@ -34,6 +40,7 @@ class MY_Model extends CI_Model protected $soft_delete_key = 'deleted'; protected $_temporary_with_deleted = FALSE; protected $_temporary_only_deleted = FALSE; + /** * The various callbacks available to the model. Each are * simple lists of method names (methods will be run on $this). @@ -46,37 +53,46 @@ class MY_Model extends CI_Model protected $after_get = array(); protected $before_delete = array(); protected $after_delete = array(); + protected $callback_parameters = array(); + /** * Protected, non-modifiable attributes */ protected $protected_attributes = array(); + /** * Relationship arrays. Use flat strings for defaults or string * => array to customise the class name and primary key */ protected $belongs_to = array(); protected $has_many = array(); + protected $_with = array(); + /** * An array of validation rules. This needs to be the same format * as validation rules passed to the Form_validation library. */ protected $validate = array(); + /** * Optionally skip the validation. Used in conjunction with * skip_validation() to skip data validation for any future calls. */ protected $skip_validation = FALSE; + /** * By default we return our results as objects. If we need to override * this, we can, or, we could use the `as_array()` and `as_object()` scopes. */ protected $return_type = 'object'; protected $_temporary_return_type = NULL; + /* -------------------------------------------------------------- * GENERIC METHODS * ------------------------------------------------------------ */ + /** * Initialise the model, tie into the CodeIgniter superobject and * try our best to guess the table name. @@ -84,27 +100,31 @@ class MY_Model extends CI_Model public function __construct() { parent::__construct(); + $this->load->helper('inflector'); + $this->_fetch_table(); - if($this->_database){ - $this->db = $this->load->database($this->_database, TRUE); - } $this->_database = $this->db; + array_unshift($this->before_create, 'protect_attributes'); array_unshift($this->before_update, 'protect_attributes'); + $this->_temporary_return_type = $this->return_type; } + /* -------------------------------------------------------------- * CRUD INTERFACE * ------------------------------------------------------------ */ + /** * Fetch a single record based on the primary key. Returns an object. */ public function get($primary_value) { - return $this->get_by($this->primary_key, $primary_value); + return $this->get_by($this->primary_key, $primary_value); } + /** * Fetch a single record based on an arbitrary WHERE call. Can be * any valid value to $this->_database->where(). @@ -112,27 +132,36 @@ public function get($primary_value) public function get_by() { $where = func_get_args(); + if ($this->soft_delete && $this->_temporary_with_deleted !== TRUE) { $this->_database->where($this->soft_delete_key, (bool)$this->_temporary_only_deleted); } - $this->_set_where($where); + + $this->_set_where($where); + $this->trigger('before_get'); + $row = $this->_database->get($this->_table) ->{$this->_return_type()}(); $this->_temporary_return_type = $this->return_type; + $row = $this->trigger('after_get', $row); + $this->_with = array(); return $row; } + /** * Fetch an array of records based on an array of primary values. */ public function get_many($values) { $this->_database->where_in($this->primary_key, $values); + return $this->get_all(); } + /** * Fetch an array of records based on an arbitrary WHERE call. */ @@ -141,8 +170,10 @@ public function get_many_by() $where = func_get_args(); $this->_set_where($where); + return $this->get_all(); } + /** * Fetch all the records in the table. Can be used as a generic call * to $this->_database->get() with scoped methods. @@ -150,20 +181,25 @@ public function get_many_by() public function get_all() { $this->trigger('before_get'); + if ($this->soft_delete && $this->_temporary_with_deleted !== TRUE) { $this->_database->where($this->soft_delete_key, (bool)$this->_temporary_only_deleted); } + $result = $this->_database->get($this->_table) ->{$this->_return_type(1)}(); $this->_temporary_return_type = $this->return_type; + foreach ($result as $key => &$row) { $row = $this->trigger('after_get', $row, ($key == count($result) - 1)); } + $this->_with = array(); return $result; } + /** * Insert a new row into the table. $data should be an associative array * of data to be inserted. Returns newly created ID. @@ -174,12 +210,16 @@ public function insert($data, $skip_validation = FALSE) { $data = $this->validate($data); } + if ($data !== FALSE) { $data = $this->trigger('before_create', $data); + $this->_database->insert($this->_table, $data); $insert_id = $this->_database->insert_id(); + $this->trigger('after_create', $insert_id); + return $insert_id; } else @@ -187,34 +227,42 @@ public function insert($data, $skip_validation = FALSE) return FALSE; } } + /** * Insert multiple rows into the table. Returns an array of multiple IDs. */ public function insert_many($data, $skip_validation = FALSE) { $ids = array(); + foreach ($data as $key => $row) { $ids[] = $this->insert($row, $skip_validation, ($key == count($data) - 1)); } + return $ids; } + /** * Updated a record based on the primary value. */ public function update($primary_value, $data, $skip_validation = FALSE) { $data = $this->trigger('before_update', $data); + if ($skip_validation === FALSE) { $data = $this->validate($data); } + if ($data !== FALSE) { $result = $this->_database->where($this->primary_key, $primary_value) ->set($data) ->update($this->_table); + $this->trigger('after_update', array($data, $result)); + return $result; } else @@ -222,22 +270,27 @@ public function update($primary_value, $data, $skip_validation = FALSE) return FALSE; } } + /** * Update many records, based on an array of primary values. */ public function update_many($primary_values, $data, $skip_validation = FALSE) { $data = $this->trigger('before_update', $data); + if ($skip_validation === FALSE) { $data = $this->validate($data); } + if ($data !== FALSE) { $result = $this->_database->where_in($this->primary_key, $primary_values) ->set($data) ->update($this->_table); + $this->trigger('after_update', array($data, $result)); + return $result; } else @@ -245,6 +298,7 @@ public function update_many($primary_values, $data, $skip_validation = FALSE) return FALSE; } } + /** * Updated a record based on an arbitrary WHERE clause. */ @@ -252,13 +306,16 @@ public function update_by() { $args = func_get_args(); $data = array_pop($args); + $data = $this->trigger('before_update', $data); + if ($this->validate($data) !== FALSE) { $this->_set_where($args); $result = $this->_database->set($data) ->update($this->_table); $this->trigger('after_update', array($data, $result)); + return $result; } else @@ -266,6 +323,7 @@ public function update_by() return FALSE; } } + /** * Update all records */ @@ -275,15 +333,19 @@ public function update_all($data) $result = $this->_database->set($data) ->update($this->_table); $this->trigger('after_update', array($data, $result)); + return $result; } + /** * Delete a row from the table by the primary value */ public function delete($id) { $this->trigger('before_delete', $id); + $this->_database->where($this->primary_key, $id); + if ($this->soft_delete) { $result = $this->_database->update($this->_table, array( $this->soft_delete_key => TRUE )); @@ -292,17 +354,24 @@ public function delete($id) { $result = $this->_database->delete($this->_table); } + $this->trigger('after_delete', $result); + return $result; } + /** * Delete a row from the database table by an arbitrary WHERE clause */ public function delete_by() { $where = func_get_args(); - $where = $this->trigger('before_delete', $where); + + $where = $this->trigger('before_delete', $where); + $this->_set_where($where); + + if ($this->soft_delete) { $result = $this->_database->update($this->_table, array( $this->soft_delete_key => TRUE )); @@ -311,16 +380,21 @@ public function delete_by() { $result = $this->_database->delete($this->_table); } + $this->trigger('after_delete', $result); + return $result; } + /** * Delete many rows from the database table by multiple primary values */ public function delete_many($primary_values) { $primary_values = $this->trigger('before_delete', $primary_values); + $this->_database->where_in($this->primary_key, $primary_values); + if ($this->soft_delete) { $result = $this->_database->update($this->_table, array( $this->soft_delete_key => TRUE )); @@ -329,35 +403,46 @@ public function delete_many($primary_values) { $result = $this->_database->delete($this->_table); } + $this->trigger('after_delete', $result); + return $result; } + + /** * Truncates the table */ public function truncate() { $result = $this->_database->truncate($this->_table); + return $result; } + /* -------------------------------------------------------------- * RELATIONSHIPS * ------------------------------------------------------------ */ + public function with($relationship) { $this->_with[] = $relationship; + if (!in_array('relate', $this->after_get)) { $this->after_get[] = 'relate'; } + return $this; } + public function relate($row) { - if (empty($row)) + if (empty($row)) { - return $row; + return $row; } + foreach ($this->belongs_to as $key => $value) { if (is_string($value)) @@ -370,9 +455,11 @@ public function relate($row) $relationship = $key; $options = $value; } + if (in_array($relationship, $this->_with)) { $this->load->model($options['model'], $relationship . '_model'); + if (is_object($row)) { $row->{$relationship} = $this->{$relationship . '_model'}->get($row->{$options['primary_key']}); @@ -383,6 +470,7 @@ public function relate($row) } } } + foreach ($this->has_many as $key => $value) { if (is_string($value)) @@ -395,9 +483,11 @@ public function relate($row) $relationship = $key; $options = $value; } + if (in_array($relationship, $this->_with)) { $this->load->model($options['model'], $relationship . '_model'); + if (is_object($row)) { $row->{$relationship} = $this->{$relationship . '_model'}->get_many_by($options['primary_key'], $row->{$this->primary_key}); @@ -408,17 +498,21 @@ public function relate($row) } } } + return $row; } + /* -------------------------------------------------------------- * UTILITY METHODS * ------------------------------------------------------------ */ + /** * Retrieve and generate a form_dropdown friendly array */ function dropdown() { $args = func_get_args(); + if(count($args) == 2) { list($key, $value) = $args; @@ -428,22 +522,30 @@ function dropdown() $key = $this->primary_key; $value = $args[0]; } + $this->trigger('before_dropdown', array( $key, $value )); + if ($this->soft_delete && $this->_temporary_with_deleted !== TRUE) { $this->_database->where($this->soft_delete_key, FALSE); } + $result = $this->_database->select(array($key, $value)) ->get($this->_table) ->result(); + $options = array(); + foreach ($result as $row) { $options[$row->{$key}] = $row->{$value}; } + $options = $this->trigger('after_dropdown', $options); + return $options; } + /** * Fetch a count of rows based on an arbitrary WHERE call. */ @@ -453,10 +555,13 @@ public function count_by() { $this->_database->where($this->soft_delete_key, (bool)$this->_temporary_only_deleted); } + $where = func_get_args(); $this->_set_where($where); + return $this->_database->count_all_results($this->_table); } + /** * Fetch a total count of rows, disregarding any previous conditions */ @@ -466,8 +571,10 @@ public function count_all() { $this->_database->where($this->soft_delete_key, (bool)$this->_temporary_only_deleted); } + return $this->_database->count_all($this->_table); } + /** * Tell the class to skip the insert validation */ @@ -476,6 +583,7 @@ public function skip_validation() $this->skip_validation = TRUE; return $this; } + /** * Get the skip validation status */ @@ -483,6 +591,7 @@ public function get_skip_validation() { return $this->skip_validation; } + /** * Return the next auto increment of the table. Only tested on MySQL. */ @@ -493,6 +602,7 @@ public function get_next_id() ->where('TABLE_NAME', $this->_table) ->where('TABLE_SCHEMA', $this->_database->database)->get()->row()->AUTO_INCREMENT; } + /** * Getter for the table name */ @@ -500,9 +610,11 @@ public function table() { return $this->_table; } + /* -------------------------------------------------------------- * GLOBAL SCOPES * ------------------------------------------------------------ */ + /** * Return the next call as an array rather than an object */ @@ -511,6 +623,7 @@ public function as_array() $this->_temporary_return_type = 'array'; return $this; } + /** * Return the next call as an object rather than an array */ @@ -519,6 +632,7 @@ public function as_object() $this->_temporary_return_type = 'object'; return $this; } + /** * Don't care about soft deleted rows on the next call */ @@ -527,6 +641,7 @@ public function with_deleted() $this->_temporary_with_deleted = TRUE; return $this; } + /** * Only get deleted rows on the next call */ @@ -535,9 +650,11 @@ public function only_deleted() $this->_temporary_only_deleted = TRUE; return $this; } + /* -------------------------------------------------------------- * OBSERVERS * ------------------------------------------------------------ */ + /** * MySQL DATETIME created_at and updated_at */ @@ -551,8 +668,10 @@ public function created_at($row) { $row['created_at'] = date('Y-m-d H:i:s'); } + return $row; } + public function updated_at($row) { if (is_object($row)) @@ -563,8 +682,10 @@ public function updated_at($row) { $row['updated_at'] = date('Y-m-d H:i:s'); } + return $row; } + /** * Serialises data for you automatically, allowing you to pass * through objects and let it handle the serialisation in the background @@ -575,8 +696,10 @@ public function serialize($row) { $row[$column] = serialize($row[$column]); } + return $row; } + public function unserialize($row) { foreach ($this->callback_parameters as $column) @@ -590,8 +713,10 @@ public function unserialize($row) $row->$column = unserialize($row->$column); } } + return $row; } + /** * Protect attributes by removing them from $row array */ @@ -608,11 +733,14 @@ public function protect_attributes($row) unset($row[$attr]); } } + return $row; } + /* -------------------------------------------------------------- * QUERY BUILDER DIRECT ACCESS METHODS * ------------------------------------------------------------ */ + /** * A wrapper to $this->_database->order_by() */ @@ -631,6 +759,28 @@ public function order_by($criteria, $order = 'ASC') } return $this; } + + /* -------------------------------------------------------------- + * QUERY BUILDER DIRECT ACCESS METHODS + * ------------------------------------------------------------ */ + /** + * A wrapper to $this->_database->group_by() + */ + public function group_by($criteria) + { + if ( is_array($criteria) ) + { + foreach ($criteria as $key => $value) + { + $this->_database->group_by($value); + } + } + else + { + $this->_database->group_by($criteria); + } + return $this; + } /** * A wrapper to $this->_database->limit() */ @@ -639,9 +789,11 @@ public function limit($limit, $offset = 0) $this->_database->limit($limit, $offset); return $this; } + /* -------------------------------------------------------------- * INTERNAL METHODS * ------------------------------------------------------------ */ + /** * Trigger an event and call its observers. Pass through the event name * (which looks for an instance variable $this->event_name), an array of @@ -656,14 +808,18 @@ public function trigger($event, $data = FALSE, $last = TRUE) if (strpos($method, '(')) { preg_match('/([a-zA-Z0-9\_\-]+)(\(([a-zA-Z0-9\_\-\., ]+)\))?/', $method, $matches); + $method = $matches[1]; $this->callback_parameters = explode(',', $matches[3]); } + $data = call_user_func_array(array($this, $method), array($data, $last)); } } + return $data; } + /** * Run validation on the passed data */ @@ -673,16 +829,20 @@ public function validate($data) { return $data; } + if(!empty($this->validate)) { foreach($data as $key => $val) { $_POST[$key] = $val; } + $this->load->library('form_validation'); + if(is_array($this->validate)) { $this->form_validation->set_rules($this->validate); + if ($this->form_validation->run() === TRUE) { return $data; @@ -709,6 +869,7 @@ public function validate($data) return $data; } } + /** * Guess the table name by pluralising the model name */ @@ -719,6 +880,7 @@ private function _fetch_table() $this->_table = plural(preg_replace('/(_m|_model)?$/', '', strtolower(get_class($this)))); } } + /** * Guess the primary key for current table */ @@ -729,6 +891,7 @@ private function _fetch_primary_key() $this->primary_key = $this->_database->query("SHOW KEYS FROM `".$this->_table."` WHERE Key_name = 'PRIMARY'")->row()->Column_name; } } + /** * Set WHERE parameters, cleverly */ @@ -759,8 +922,8 @@ protected function _set_where($params) { $this->_database->where($params[0]); } - else if(count($params) == 2) - { + else if(count($params) == 2) + { if (is_array($params[1])) { $this->_database->where_in($params[0], $params[1]); @@ -769,11 +932,11 @@ protected function _set_where($params) { $this->_database->where($params[0], $params[1]); } - } - else if(count($params) == 3) - { - $this->_database->where($params[0], $params[1], $params[2]); - } + } + else if(count($params) == 3) + { + $this->_database->where($params[0], $params[1], $params[2]); + } else { if (is_array($params[1])) @@ -786,6 +949,7 @@ protected function _set_where($params) } } } + /** * Return the method name for the current return type */ @@ -794,4 +958,4 @@ protected function _return_type($multi = FALSE) $method = ($multi) ? 'result' : 'row'; return $this->_temporary_return_type == 'array' ? $method . '_array' : $method; } -} \ No newline at end of file +}