diff --git a/README.md b/README.md index 38fc601..f976f67 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,15 @@ Observers can also take parameters in their name, much like CodeIgniter's Form V return $row; } +**By using the scope skip_observers() triggering of all the attached/registered observers can be disabled. For example:** + +```php +// A user logs in. We want to store a timestamp of this moment, +// but we don't the registered built-in observer 'updated_at' to be triggered, +// i.e. we don't want the field 'updated_at' to change its value. +$this->users->skip_observers()->update($id, array('last_login_at' => date('Y-m-d H:i:s'))); +``` + Validation ---------- diff --git a/core/MY_Model.php b/core/MY_Model.php index 05add98..a13d88e 100644 --- a/core/MY_Model.php +++ b/core/MY_Model.php @@ -56,6 +56,11 @@ class MY_Model extends CI_Model protected $callback_parameters = array(); + /** + * Support for skip_observers() scope. + */ + protected $_temporary_skip_observers = FALSE; + /** * Protected, non-modifiable attributes */ @@ -110,7 +115,7 @@ public function __construct() array_unshift($this->before_create, 'protect_attributes'); array_unshift($this->before_update, 'protect_attributes'); - $this->_temporary_return_type = $this->return_type; + $this->_reset_state(); } /* -------------------------------------------------------------- @@ -122,7 +127,7 @@ public function __construct() */ public function get($primary_value) { - return $this->get_by($this->primary_key, $primary_value); + return $this->get_by($this->primary_key, $primary_value); } /** @@ -138,7 +143,7 @@ public function get_by() $this->_database->where($this->soft_delete_key, (bool)$this->_temporary_only_deleted); } - $this->_set_where($where); + $this->_set_where($where); $this->trigger('before_get'); @@ -148,7 +153,8 @@ public function get_by() $row = $this->trigger('after_get', $row); - $this->_with = array(); + $this->_reset_state(); + return $row; } @@ -196,7 +202,8 @@ public function get_all() $row = $this->trigger('after_get', $row, ($key == count($result) - 1)); } - $this->_with = array(); + $this->_reset_state(); + return $result; } @@ -220,12 +227,14 @@ public function insert($data, $skip_validation = FALSE) $this->trigger('after_create', $insert_id); + $this->_reset_state(); + return $insert_id; } - else - { - return FALSE; - } + + $this->_reset_state(); + + return FALSE; } /** @@ -233,10 +242,14 @@ public function insert($data, $skip_validation = FALSE) */ public function insert_many($data, $skip_validation = FALSE) { + $skip_observers = $this->_temporary_skip_observers; + $ids = array(); foreach ($data as $key => $row) { + $this->_temporary_skip_observers = $skip_observers; + $ids[] = $this->insert($row, $skip_validation, ($key == count($data) - 1)); } @@ -263,12 +276,14 @@ public function update($primary_value, $data, $skip_validation = FALSE) $this->trigger('after_update', array($data, $result)); + $this->_reset_state(); + return $result; } - else - { - return FALSE; - } + + $this->_reset_state(); + + return FALSE; } /** @@ -291,12 +306,14 @@ public function update_many($primary_values, $data, $skip_validation = FALSE) $this->trigger('after_update', array($data, $result)); + $this->_reset_state(); + return $result; } - else - { - return FALSE; - } + + $this->_reset_state(); + + return FALSE; } /** @@ -316,12 +333,14 @@ public function update_by() ->update($this->_table); $this->trigger('after_update', array($data, $result)); + $this->_reset_state(); + return $result; } - else - { - return FALSE; - } + + $this->_reset_state(); + + return FALSE; } /** @@ -334,6 +353,8 @@ public function update_all($data) ->update($this->_table); $this->trigger('after_update', array($data, $result)); + $this->_reset_state(); + return $result; } @@ -357,6 +378,8 @@ public function delete($id) $this->trigger('after_delete', $result); + $this->_reset_state(); + return $result; } @@ -367,11 +390,10 @@ 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 )); @@ -383,6 +405,8 @@ public function delete_by() $this->trigger('after_delete', $result); + $this->_reset_state(); + return $result; } @@ -406,6 +430,8 @@ public function delete_many($primary_values) $this->trigger('after_delete', $result); + $this->_reset_state(); + return $result; } @@ -417,6 +443,8 @@ public function truncate() { $result = $this->_database->truncate($this->_table); + $this->_reset_state(); + return $result; } @@ -436,11 +464,14 @@ public function with($relationship) return $this; } + // This observer is to be suppressed by skip_observers() scope too. + // This might change if there is a good/valid use-case, but let us not + // complicate code for now. public function relate($row) { - if (empty($row)) + if (empty($row)) { - return $row; + return $row; } foreach ($this->belongs_to as $key => $value) @@ -543,6 +574,8 @@ function dropdown() $options = $this->trigger('after_dropdown', $options); + $this->_reset_state(); + return $options; } @@ -559,7 +592,11 @@ public function count_by() $where = func_get_args(); $this->_set_where($where); - return $this->_database->count_all_results($this->_table); + $result = $this->_database->count_all_results($this->_table); + + $this->_reset_state(); + + return $result; } /** @@ -572,7 +609,11 @@ public function count_all() $this->_database->where($this->soft_delete_key, (bool)$this->_temporary_only_deleted); } - return $this->_database->count_all($this->_table); + $result = $this->_database->count_all($this->_table); + + $this->_reset_state(); + + return $result; } /** @@ -651,6 +692,15 @@ public function only_deleted() return $this; } + /** + * Disables triggering of all the attached/registered observers. + */ + public function skip_observers() + { + $this->_temporary_skip_observers = TRUE; + return $this; + } + /* -------------------------------------------------------------- * OBSERVERS * ------------------------------------------------------------ */ @@ -780,7 +830,7 @@ public function limit($limit, $offset = 0) */ public function trigger($event, $data = FALSE, $last = TRUE) { - if (isset($this->$event) && is_array($this->$event)) + if (!$this->_temporary_skip_observers && isset($this->$event) && is_array($this->$event)) { foreach ($this->$event as $method) { @@ -804,12 +854,12 @@ public function trigger($event, $data = FALSE, $last = TRUE) */ public function validate($data) { - if($this->skip_validation) + if ($this->skip_validation) { return $data; } - if(!empty($this->validate)) + if (!empty($this->validate)) { foreach($data as $key => $val) { @@ -818,7 +868,7 @@ public function validate($data) $this->load->library('form_validation'); - if(is_array($this->validate)) + if (is_array($this->validate)) { $this->form_validation->set_rules($this->validate); @@ -901,8 +951,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 +961,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])) @@ -937,4 +987,17 @@ protected function _return_type($multi = FALSE) $method = ($multi) ? 'result' : 'row'; return $this->_temporary_return_type == 'array' ? $method . '_array' : $method; } + + /** + * Resets all internal state flags and temporary scope data. + */ + protected function _reset_state() + { + $this->_with = array(); + $this->_temporary_return_type = $this->return_type; + $this->_temporary_with_deleted = FALSE; + $this->_temporary_only_deleted = FALSE; + $this->_temporary_skip_observers = FALSE; + } + }