From 3d58618fac5a8af908210d586e90640218819088 Mon Sep 17 00:00:00 2001 From: Ivan Tcholakov Date: Wed, 30 Jul 2014 06:05:29 +0300 Subject: [PATCH 1/3] Refactoring before skip_observers() feature implementation. See https://github.com/jamierumbelow/codeigniter-base-model/issues/113 --- core/MY_Model.php | 115 +++++++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 37 deletions(-) diff --git a/core/MY_Model.php b/core/MY_Model.php index 05add98..48ff805 100644 --- a/core/MY_Model.php +++ b/core/MY_Model.php @@ -110,7 +110,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 +122,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 +138,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 +148,8 @@ public function get_by() $row = $this->trigger('after_get', $row); - $this->_with = array(); + $this->_reset_state(); + return $row; } @@ -196,7 +197,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 +222,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; } /** @@ -263,12 +267,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 +297,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 +324,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 +344,8 @@ public function update_all($data) ->update($this->_table); $this->trigger('after_update', array($data, $result)); + $this->_reset_state(); + return $result; } @@ -357,6 +369,8 @@ public function delete($id) $this->trigger('after_delete', $result); + $this->_reset_state(); + return $result; } @@ -367,11 +381,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 +396,8 @@ public function delete_by() $this->trigger('after_delete', $result); + $this->_reset_state(); + return $result; } @@ -406,6 +421,8 @@ public function delete_many($primary_values) $this->trigger('after_delete', $result); + $this->_reset_state(); + return $result; } @@ -417,6 +434,8 @@ public function truncate() { $result = $this->_database->truncate($this->_table); + $this->_reset_state(); + return $result; } @@ -438,9 +457,9 @@ public function with($relationship) public function relate($row) { - if (empty($row)) + if (empty($row)) { - return $row; + return $row; } foreach ($this->belongs_to as $key => $value) @@ -543,6 +562,8 @@ function dropdown() $options = $this->trigger('after_dropdown', $options); + $this->_reset_state(); + return $options; } @@ -559,7 +580,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 +597,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; } /** @@ -804,12 +833,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 +847,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 +930,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 +940,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 +966,16 @@ 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; + } + } From 25dd66a14aa895b6efe65977da41098ffe64f0da Mon Sep 17 00:00:00 2001 From: Ivan Tcholakov Date: Wed, 30 Jul 2014 06:40:12 +0300 Subject: [PATCH 2/3] skip_observers() feature implementation. See https://github.com/jamierumbelow/codeigniter-base-model/issues/113 --- README.md | 9 +++++++++ core/MY_Model.php | 24 +++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 38fc601..abcc11c 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 48ff805..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 */ @@ -237,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)); } @@ -455,6 +464,9 @@ 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)) @@ -680,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 * ------------------------------------------------------------ */ @@ -809,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) { @@ -976,6 +997,7 @@ protected function _reset_state() $this->_temporary_return_type = $this->return_type; $this->_temporary_with_deleted = FALSE; $this->_temporary_only_deleted = FALSE; + $this->_temporary_skip_observers = FALSE; } } From 1de1eae6de4947d53e6f42f099c4e5c83a43495f Mon Sep 17 00:00:00 2001 From: Ivan Tcholakov Date: Wed, 30 Jul 2014 07:23:18 +0300 Subject: [PATCH 3/3] A minor correction within README.md. See https://github.com/jamierumbelow/codeigniter-base-model/issues/113 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index abcc11c..f976f67 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ 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: +**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,