/event.php

https://github.com/m3nt0r/eventful-spinoff-cakephp · PHP · 199 lines · 81 code · 19 blank · 99 comment · 12 complexity · 2cb40127396b7effe8a9a0e25e8db65b MD5 · raw file

  1. <?php
  2. /**
  3. * Event Component for CakePHP
  4. *
  5. * Plugin Spinoff - single component approach.
  6. *
  7. * @author Kjell Bublitz <kjell@growinthings.de>
  8. * @copyright 2008-2009 (c) Kjell Bublitz
  9. * @link http://cakealot.com
  10. * @package eventful-component
  11. * @subpackage components
  12. * @version $Id$
  13. */
  14. App::import('Core', 'String');
  15. /**
  16. * EventComponent
  17. *
  18. *
  19. * @package eventful-component
  20. * @subpackage components
  21. */
  22. class EventComponent extends Object {
  23. /**
  24. * Controller Instance
  25. *
  26. * @var object
  27. */
  28. private $Controller = null;
  29. /**
  30. * Startup
  31. *
  32. * @param unknown_type $controller
  33. */
  34. public function initialize(&$controller) {
  35. $this->Controller = $controller;
  36. }
  37. /**
  38. * Trigger Event
  39. *
  40. * @param string|array $events Use dot notation if you want.
  41. * @param array $data (optional) Any data to pass along
  42. * @param array $config (optional)
  43. * @return array
  44. *
  45. * @todo Do something clever with $config ...
  46. */
  47. public function triggerEvent($eventName, $data = array(), $config = array()) {
  48. if (is_array($eventName)) {
  49. $eventNames = Set::filter($eventName);
  50. foreach ($eventNames as $eventName) {
  51. extract($this->_parseEventName($eventName), EXTR_OVERWRITE);
  52. $return[$scope][$event] = $this->_dispatchEvent($scope, $event, $data);
  53. }
  54. } else {
  55. extract($this->_parseEventName($eventName), EXTR_OVERWRITE);
  56. $return[$scope][$event] = $this->_dispatchEvent($scope, $event, $data);
  57. }
  58. return $return;
  59. }
  60. /**
  61. * Dispatch event
  62. *
  63. * @param string $scope
  64. * @param string $eventName
  65. * @param array $data (optional)
  66. * @return
  67. */
  68. private function _dispatchEvent($scope, $eventName, $data = array()) {
  69. $eventHandlerMethod = $this->_handlerMethodName($eventName);
  70. $validHandlersClasses = $this->_scanControllers($scope, $eventHandlerMethod);
  71. $return = array();
  72. foreach($validHandlersClasses as $class) {
  73. $controller = $this->Controller;
  74. if ($class != get_class($controller)) {
  75. $controller = new $class;
  76. }
  77. $event = new Event($eventName, $data);
  78. // call method on controller, pass event object and triggering controller object
  79. $return[$class] = call_user_method_array($eventHandlerMethod, $controller, array($event, &$this->Controller));
  80. }
  81. return $return;
  82. }
  83. var $validHandlers = array();
  84. /**
  85. * Check all controller classes in scope for the eventHandlerMethod
  86. *
  87. * @param unknown_type $scope
  88. * @param unknown_type $eventHandlerMethod
  89. * @return array List of controller class names
  90. *
  91. * @todo plugin support
  92. * @todo deprecate or replace require_once
  93. */
  94. private function _scanControllers($scope, $eventHandlerMethod) {
  95. $validHandlerClasses = array();
  96. $controllers = Configure::listObjects('controller');
  97. foreach ($controllers as $controller) {
  98. if (($scope == $controller || low($scope) == 'global')) { // must be in scope, or global
  99. $controllerClass = $controller.'Controller';
  100. if (!class_exists($controllerClass)) { // app import doesn't work..
  101. require_once(CONTROLLERS.Inflector::underscore($controllerClass).'.php');
  102. }
  103. if (is_callable(array($controllerClass, $eventHandlerMethod))) {
  104. $validHandlerClasses[] = $controllerClass;
  105. }
  106. }
  107. }
  108. return $validHandlerClasses;
  109. }
  110. /**
  111. * eventName to methodName
  112. *
  113. * @param string $eventName
  114. * @return string
  115. */
  116. private function _handlerMethodName($eventName) {
  117. return '_on'.Inflector::camelize($eventName);
  118. }
  119. /**
  120. * Parse eventName and extract scope. Default scope is "Global"
  121. *
  122. * @param string $eventName
  123. * @return array (scope, event)
  124. */
  125. private function _parseEventName($eventName) {
  126. $eventTokens = String::tokenize($eventName, '.');
  127. $scope = 'Global';
  128. $event = $eventTokens[0];
  129. if (count($eventTokens) > 1) {
  130. list($scope, $event) = $eventTokens;
  131. }
  132. return compact('scope', 'event');
  133. }
  134. }
  135. /**
  136. * Event Object
  137. *
  138. * @package eventful-component
  139. */
  140. class Event {
  141. /**
  142. * Contains assigned values
  143. *
  144. * @var array
  145. */
  146. protected $values = array();
  147. /**
  148. * Constructor with EventName and EventData (optional)
  149. *
  150. * Event Data is automaticly assigned as properties by array key
  151. *
  152. * @param string $eventName Name of the Event
  153. * @param array $data optional array with k/v data
  154. */
  155. public function __construct($eventName, $data = array()) {
  156. $this->name = $eventName;
  157. if (!empty($data)) {
  158. foreach ($data as $name => $value) {
  159. $this->{$name} = $value;
  160. } // push data values to props
  161. }
  162. }
  163. /**
  164. * Write to object
  165. *
  166. * @param string $name Key
  167. * @param mixed $value Value
  168. */
  169. public function __set($name, $value) {
  170. $this->values[$name] = $value;
  171. }
  172. /**
  173. * Read from object
  174. *
  175. * @param string $name Key
  176. */
  177. public function __get($name) {
  178. return $this->values[$name];
  179. }
  180. }