├── config └── autoload.php ├── core └── MY_Loader.php ├── libraries └── events.php ├── readme.md ├── spark.info └── tests └── eventsTest.php /config/autoload.php: -------------------------------------------------------------------------------- 1 | _ci_events_paths = array(APPPATH); 13 | log_message('debug', "MY_Loader Class Initialized"); 14 | } 15 | 16 | /** Load a events module * */ 17 | public function event($event = '', $params = NULL, $object_name = NULL) 18 | { 19 | if (is_array($event)) 20 | { 21 | foreach ($event as $class) 22 | { 23 | $this->library($class, $params); 24 | } 25 | 26 | return; 27 | } 28 | 29 | if ($event == '' OR isset($this->_base_classes[$event])) 30 | { 31 | return FALSE; 32 | } 33 | 34 | if ( ! is_null($params) && ! is_array($params)) 35 | { 36 | $params = NULL; 37 | } 38 | 39 | $this->_ci_events_class($event, $params, $object_name); 40 | } 41 | 42 | /** Load an array of events * */ 43 | public function events($event = '', $params = NULL, $object_name = NULL) 44 | { 45 | if (is_array($event)) 46 | { 47 | foreach ($event as $class) 48 | { 49 | $this->library($class, $params); 50 | } 51 | } 52 | return; 53 | } 54 | 55 | /** 56 | * Load Events 57 | * 58 | * This function loads the requested class. 59 | * 60 | * @param string the item that is being loaded 61 | * @param mixed any additional parameters 62 | * @param string an optional object name 63 | * @return void 64 | */ 65 | protected function _ci_events_class($class, $params = NULL, $object_name = NULL) { 66 | // Get the class name, and while we're at it trim any slashes. 67 | // The directory path can be included as part of the class name, 68 | // but we don't want a leading slash 69 | $class = str_replace('.php', '', trim($class, '/')); 70 | 71 | // Was the path included with the class name? 72 | // We look for a slash to determine this 73 | $subdir = ''; 74 | if (($last_slash = strrpos($class, '/')) !== FALSE) { 75 | // Extract the path 76 | $subdir = substr($class, 0, $last_slash + 1); 77 | 78 | // Get the filename from the path 79 | $class = substr($class, $last_slash + 1); 80 | } 81 | 82 | // We'll test for both lowercase and capitalized versions of the file name 83 | foreach (array(ucfirst($class), strtolower($class)) as $class) { 84 | $subclass = APPPATH . 'events/' . $subdir . config_item('subclass_prefix') . $class . '.php'; 85 | 86 | // Is this a class extension request? 87 | if (file_exists($subclass)) { 88 | $baseclass = BASEPATH . 'events/' . ucfirst($class) . '.php'; 89 | 90 | if (!file_exists($baseclass)) { 91 | log_message('error', "Unable to load the requested class: " . $class); 92 | show_error("Unable to load the requested class: " . $class); 93 | } 94 | 95 | // Safety: Was the class already loaded by a previous call? 96 | if (in_array($subclass, $this->_ci_library_paths)) { 97 | // Before we deem this to be a duplicate request, let's see 98 | // if a custom object name is being supplied. If so, we'll 99 | // return a new instance of the object 100 | if (!is_null($object_name)) { 101 | $CI = & get_instance(); 102 | if (!isset($CI->$object_name)) { 103 | return $this->_ci_init_library($class, config_item('subclass_prefix'), $params, $object_name); 104 | } 105 | } 106 | 107 | $is_duplicate = TRUE; 108 | log_message('debug', $class . " class already loaded. Second attempt ignored."); 109 | return; 110 | } 111 | 112 | include_once($baseclass); 113 | include_once($subclass); 114 | $this->_ci_library_paths[] = $subclass; 115 | 116 | return $this->_ci_init_library($class, config_item('subclass_prefix'), $params, $object_name); 117 | } 118 | 119 | // Lets search for the requested library file and load it. 120 | $is_duplicate = FALSE; 121 | foreach ($this->_ci_events_paths as $path) { 122 | $filepath = $path . 'events/' . $subdir . $class . '.php'; 123 | 124 | // Does the file exist? No? Bummer... 125 | if (!file_exists($filepath)) { 126 | continue; 127 | } 128 | 129 | // Safety: Was the class already loaded by a previous call? 130 | if (in_array($filepath, $this->_ci_library_paths)) { 131 | // Before we deem this to be a duplicate request, let's see 132 | // if a custom object name is being supplied. If so, we'll 133 | // return a new instance of the object 134 | if (!is_null($object_name)) { 135 | $CI = & get_instance(); 136 | if (!isset($CI->$object_name)) { 137 | return $this->_ci_init_library($class, '', $params, $object_name); 138 | } 139 | } 140 | 141 | $is_duplicate = TRUE; 142 | log_message('debug', $class . " class already loaded. Second attempt ignored."); 143 | return; 144 | } 145 | 146 | include_once($filepath); 147 | $this->_ci_library_paths[] = $filepath; 148 | return $this->_ci_init_library($class, '', $params, $object_name); 149 | } 150 | } // END FOREACH 151 | // One last attempt. Maybe the library is in a subdirectory, but it wasn't specified? 152 | if ($subdir == '') { 153 | $path = strtolower($class) . '/' . $class; 154 | return $this->_ci_load_class($path, $params); 155 | } 156 | 157 | // If we got this far we were unable to find the requested class. 158 | // We do not issue errors if the load call failed due to a duplicate request 159 | if ($is_duplicate == FALSE) { 160 | log_message('error', "Unable to load the requested class: " . $class); 161 | show_error("Unable to load the requested class: " . $class); 162 | } 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /libraries/events.php: -------------------------------------------------------------------------------- 1 | 11 | * @author Dan Horrigan 12 | * @license Apache License v2.0 13 | * @copyright 2010 Dan Horrigan 14 | * 15 | * Licensed under the Apache License, Version 2.0 (the "License"); 16 | * you may not use this file except in compliance with the License. 17 | * You may obtain a copy of the License at 18 | * 19 | * http://www.apache.org/licenses/LICENSE-2.0 20 | * 21 | * Unless required by applicable law or agreed to in writing, software 22 | * distributed under the License is distributed on an "AS IS" BASIS, 23 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | * See the License for the specific language governing permissions and 25 | * limitations under the License. 26 | */ 27 | 28 | /** 29 | * Events Library 30 | */ 31 | class Events { 32 | 33 | /** 34 | * @var array An array of listeners 35 | */ 36 | protected static $_listeners = array(); 37 | 38 | // ------------------------------------------------------------------------ 39 | 40 | /** 41 | * Register 42 | * 43 | * Registers a Callback for a given event 44 | * 45 | * @access public 46 | * @param string The name of the event 47 | * @param array The callback for the Event 48 | * @return void 49 | */ 50 | public static function register($event, array $callback) 51 | { 52 | $key = get_class($callback[0]).'::'.$callback[1]; 53 | self::$_listeners[$event][$key] = $callback; 54 | self::log_message('debug', 'Events::register() - Registered "'.$key.' with event "'.$event.'"'); 55 | } 56 | 57 | // ------------------------------------------------------------------------ 58 | 59 | /** 60 | * Trigger 61 | * 62 | * Triggers an event and returns the results. The results can be returned 63 | * in the following formats: 64 | * 65 | * 'array' 66 | * 'json' 67 | * 'serialized' 68 | * 'string' 69 | * 70 | * @access public 71 | * @param string The name of the event 72 | * @param mixed Any data that is to be passed to the listener 73 | * @param string The return type 74 | * @return mixed The return of the listeners, in the return type 75 | */ 76 | public static function trigger($event, $data = '', $return_type = 'string') 77 | { 78 | self::log_message('debug', 'Events::trigger() - Triggering event "'.$event.'"'); 79 | 80 | $calls = array(); 81 | 82 | if (self::has_listeners($event)) 83 | { 84 | foreach (self::$_listeners[$event] as $listener) 85 | { 86 | if (is_callable($listener)) 87 | { 88 | $calls[] = call_user_func($listener, $data); 89 | } 90 | } 91 | } 92 | 93 | return self::_format_return($calls, $return_type); 94 | } 95 | 96 | // ------------------------------------------------------------------------ 97 | 98 | /** 99 | * Format Return 100 | * 101 | * Formats the return in the given type 102 | * 103 | * @access protected 104 | * @param array The array of returns 105 | * @param string The return type 106 | * @return mixed The formatted return 107 | */ 108 | protected static function _format_return(array $calls, $return_type) 109 | { 110 | self::log_message('debug', 'Events::_format_return() - Formating calls in type "'.$return_type.'"'); 111 | 112 | switch ($return_type) 113 | { 114 | case 'json': 115 | return json_encode($calls); 116 | break; 117 | case 'serialized': 118 | return serialize($calls); 119 | break; 120 | case 'string': 121 | $str = ''; 122 | foreach ($calls as $call) 123 | { 124 | $str .= $call; 125 | } 126 | return $str; 127 | break; 128 | default: 129 | return $calls; 130 | break; 131 | } 132 | 133 | return FALSE; 134 | } 135 | 136 | // ------------------------------------------------------------------------ 137 | 138 | /** 139 | * Has Listeners 140 | * 141 | * Checks if the event has listeners 142 | * 143 | * @access public 144 | * @param string The name of the event 145 | * @return bool Whether the event has listeners 146 | */ 147 | public static function has_listeners($event) 148 | { 149 | self::log_message('debug', 'Events::has_listeners() - Checking if event "'.$event.'" has listeners.'); 150 | 151 | if (isset(self::$_listeners[$event]) AND count(self::$_listeners[$event]) > 0) 152 | { 153 | return TRUE; 154 | } 155 | return FALSE; 156 | } 157 | 158 | // ------------------------------------------------------------------------ 159 | 160 | /** 161 | * Log Message 162 | * 163 | * Pulled out for unit testing 164 | * 165 | * @param string $type 166 | * @param string $message 167 | * @return void 168 | */ 169 | public static function log_message($type = 'debug', $message = '') 170 | { 171 | if (function_exists('log_message')) 172 | { 173 | log_message($type, $message); 174 | } 175 | } 176 | } 177 | 178 | /* End of file events.php */ -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # CodeIgniter Events Library 2 | 3 | Build extendible applications with an events system. 4 | 5 | Version 1.0.0 6 | 7 | * Author: [Eric Barnes](http://ericlbarnes.com/ "Eric Barnes") 8 | * Author: [Dan Horrigan](http://dhorrigan.com/ "Dan Horrigan") 9 | 10 | ##### Additions (Core Extention) 11 | 12 | * Author: [Nathan Macnamara](https://github.com/nathanmac "Nathan Macnamara") 13 | 14 | 15 | ## Public Methods 16 | 17 | ### register 18 | 19 | Registers a Callback for a given event 20 | 21 | * $event *string* 22 | * $callback *array* 23 | * Example: `Events::register('test_string', array('Class_name', 'string_return'));` 24 | 25 | ### trigger 26 | 27 | Triggers an event and returns the results. 28 | 29 | * $event *string* - The name of the event 30 | * $data *mixed* - Any data that is to be passed to the listener 31 | * $return_type *string* - Either 'array', 'json', 'serialized', or 'string' 32 | * Example: `Events::trigger('test_string', 'test', 'string');` 33 | 34 | ### has_listeners 35 | 36 | Checks if the event has any listeners 37 | 38 | * $event *string* - The name of the event 39 | * return *bool* 40 | 41 | ## Usage Overview 42 | 43 | All Events functions are static. 44 | 45 | You can add a listener to an event with the register() function: 46 | 47 |
Events::register('event_name_here', array('class_name_or_object_ref', 'method_name'));
48 | 49 | The second parameter of register() is an array that is callable via [call_user_func()](http://us2.php.net/manual/en/function.call-user-func.php "call_user_func"). 50 | 51 | You trigger an Event by calling the trigger() function: 52 | 53 |
$event_return = Events::trigger('event_name_here', $data, 'string');
54 | 55 | The 3rd parameter is the type of data you wish trigger() to return. Your options are as follows: 56 | 57 | * 'array' 58 | * 'json' 59 | * 'serialized' 60 | * 'string' (the default) 61 | 62 | ## Example Usage 63 | 64 | Because events need to be registered before being used it is a good idea to have a system 65 | in place to load any of these before you trigger any events. 66 | 67 | Here is an example loading the event handler to register the event. 68 | 69 |
 70 | // Example Welcome Controller
 71 | 
 72 | class Welcome extends CI_Controller {
 73 | 
 74 | 	public function __construct()
 75 | 	{
 76 | 		parent::__construct();
 77 | 		// Load Library
 78 | 		$this->load->library('events');
 79 | 
 80 | 		$this->load->event('test');
 81 | 	}
 82 | 
 83 | 	public function index()
 84 | 	{
 85 | 		var_dump(Events::trigger('test_string', 'test', 'string'));
 86 | 	}
 87 | }
 88 | 
 89 | // Example events/test.php
 90 | 
 91 | class Test {
 92 | 
 93 | 	public function __construct()
 94 | 	{
 95 | 		Events::register('test_string', array($this, 'string_return'));
 96 | 	}
 97 | 
 98 | 	public function string_return()
 99 | 	{
100 | 		return 'I returned a string. Cakes and Pies!';
101 | 	}
102 | }
103 | 
104 | -------------------------------------------------------------------------------- /spark.info: -------------------------------------------------------------------------------- 1 | name: Events 2 | version: 1.0.0 3 | compatibility: 2.0.0 4 | tags: ["events", "extension"] -------------------------------------------------------------------------------- /tests/eventsTest.php: -------------------------------------------------------------------------------- 1 | assertFalse(Events::has_listeners('non_existant')); 29 | $this->assertTrue(Events::has_listeners('unit_test')); 30 | } 31 | 32 | public function test_single_callback() 33 | { 34 | Events::register('single', array($this, 'callback')); 35 | $this->assertEquals(Events::trigger('single', 'test'), 'test'); 36 | } 37 | 38 | public function test_multiple_callback() 39 | { 40 | $this->assertEquals(Events::trigger('unit_test', 'test'), 'testtest2'); 41 | $this->assertEquals(Events::trigger('unit_test', 'test2'), 'testtest2'); 42 | } 43 | 44 | public function test_array_callback() 45 | { 46 | Events::register('test_array_callback', array($this, 'callback')); 47 | $arr = array('foo' => 'bar'); 48 | $this->assertEquals(Events::trigger('test_array_callback', $arr), $this->callback($arr)); 49 | } 50 | 51 | } --------------------------------------------------------------------------------