PageRenderTime 32ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/A/Event/Manager.php

http://skeleton.googlecode.com/
PHP | 237 lines | 139 code | 20 blank | 78 comment | 25 complexity | 09af17130f4f16a085618b8fb5e0a822 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * Manager.php
  4. *
  5. * @license http://www.opensource.org/licenses/bsd-license.php BSD
  6. * @link http://skeletonframework.com/
  7. * @author Jonah Dahlquist <jonah@nucleussystems.com>, Christopher Thompson <christopherxthompson@gmail.com>
  8. */
  9. /**
  10. * Event Manager
  11. *
  12. * Handles creating, storing, and firing of events.
  13. *
  14. * @package A_Event
  15. */
  16. class A_Event_Manager
  17. {
  18. const ERROR_NO_EVENT = 'No event specified. ';
  19. const ERROR_NO_METHOD = 'Listener has no onEvent() method . ';
  20. const ERROR_WRONG_TYPE = 'The only types callback, closure and object with onEvent() method supported. ';
  21. protected $_events = array();
  22. protected $_cancel = false; // Listeners can return this value to stop chain
  23. protected $_exception = ''; // A_Exception
  24. protected $_errorMsg = '';
  25. protected $_path = './events';
  26. public function __construct($exception='')
  27. {
  28. $this->setException($exception);
  29. }
  30. /**
  31. * Set the exception class to use. If $class is set to true, the default
  32. * is used.
  33. *
  34. * @param string $class
  35. */
  36. public function setException($class)
  37. {
  38. if ($class === true) {
  39. $this->_exception = 'Exception';
  40. } else {
  41. $this->_exception = $class;
  42. }
  43. return $this;
  44. }
  45. /**
  46. * Set return value that stops the Listener chain
  47. * is used.
  48. *
  49. * @param string $class
  50. */
  51. public function setCancel($cancel)
  52. {
  53. $this->_cancel = $cancel;
  54. return $this;
  55. }
  56. /**
  57. * Add event listener. After being called, that eventName can be triggered
  58. * with fireEvent.
  59. *
  60. * @param mixed $events
  61. * @param mixed $eventListener
  62. */
  63. public function addEventListener($events, $eventListener = null)
  64. {
  65. if (!$eventListener) {
  66. $eventListener = $events;
  67. $events = null;
  68. }
  69. // if no events passed then check if we can get them from the listener
  70. if (!$events && method_exists($eventListener, 'getEvents')) {
  71. $events = $eventListener->getEvents();
  72. }
  73. if ($events) {
  74. // if single event name passed then convert to array for foreach below
  75. if (is_string($events)) {
  76. $events = array($events);
  77. }
  78. foreach ($events as $event) {
  79. $event = strval($event);
  80. if (!isset($this->_events[$event])) {
  81. $this->_events[$event] = array();
  82. }
  83. $this->_events[$event][] = $eventListener;
  84. }
  85. } else {
  86. $this->_errorHandler(0, self::ERROR_NO_EVENT);
  87. }
  88. return $this;
  89. }
  90. /**
  91. * Removes all listeners for the given event
  92. *
  93. * @param string $eventName
  94. */
  95. public function killEvent($eventName)
  96. {
  97. unset($this->_events[$eventName]);
  98. return $this;
  99. }
  100. /**
  101. * Removes event listener. If no more listeners are left on that event,
  102. * the event itself is removed.
  103. *
  104. * @param A_Event_Listener $eventListener
  105. */
  106. public function removeEventListener(A_Event_Listener $eventListener)
  107. {
  108. foreach ($this->_events as $ek => $event) {
  109. foreach ($event as $lk => $listener) {
  110. if ($listener == $eventListener) {
  111. unset($this->_events[$ek][$lk]);
  112. }
  113. }
  114. }
  115. return $this;
  116. }
  117. /**
  118. * Fires the event of the given name. The object (optional) is passed to
  119. * the event handler.
  120. *
  121. * @param string $eventName
  122. * @param mixed $eventData any data you want to pass to listeners
  123. */
  124. public function fireEvent($eventName, $eventData = null)
  125. {
  126. $result = array();
  127. if (isset($this->_events[$eventName])) {
  128. $i = 0;
  129. foreach ($this->_events[$eventName] as $listener) {
  130. if (is_callable($listener)) {
  131. // callback/anonymous function
  132. $r = call_user_func($listener, $eventName, $eventData);
  133. } elseif (is_object($listener)) {
  134. // event listener interface
  135. if (method_exists($listener, 'onEvent')) { // standard A_Event_Listener
  136. $r = $listener->onEvent($eventName, $eventData);
  137. } else {
  138. $this->_errorHandler(0, self::ERROR_NO_METHOD);
  139. $r = null;
  140. }
  141. } else {
  142. if ($this->loadClass($listener)) {
  143. $listener = new $listener();
  144. if (method_exists($listener, 'onEvent')) {
  145. $r = $listener->onEvent($eventName, $eventData);
  146. } else {
  147. $this->_errorHandler(0, self::ERROR_NO_METHOD);
  148. $r = null;
  149. }
  150. } else {
  151. $this->_errorHandler(0, self::ERROR_WRONG_TYPE);
  152. $r = null;
  153. }
  154. }
  155. // only use result for non-null return values
  156. if ($r !== null) {
  157. if ($r === $this->_cancel) {
  158. break;
  159. } else {
  160. $result[$i] = $r;
  161. }
  162. }
  163. ++$i;
  164. }
  165. } else {
  166. $this->_errorHandler(0, self::ERROR_NO_EVENT);
  167. }
  168. return $result;
  169. }
  170. /**
  171. * Gets any errors accumulated
  172. *
  173. * @return string
  174. */
  175. public function getErrorMsg() {
  176. return $this->_errorMsg;
  177. }
  178. /**
  179. * Set path to look in for handler classes
  180. *
  181. * @param string $path Directory to search in
  182. */
  183. public function setPath($path)
  184. {
  185. $this->_path = $path;
  186. }
  187. /**
  188. * Creates and throws an exception of the defined type
  189. *
  190. * @param int $errno
  191. * @param string $errorMsg
  192. */
  193. private function _errorHandler($errno, $errorMsg) {
  194. $this->_errorMsg .= $errorMsg;
  195. if ($this->_exception) {
  196. throw A_Exception::getInstance($this->_exception, $errorMsg);
  197. }
  198. }
  199. /**
  200. * Loads a class from the path
  201. *
  202. * @param string $class
  203. * @return bool Success or failure
  204. */
  205. protected function loadClass($class) {
  206. $file = rtrim($this->_path, '/\\') . '/'. str_replace(array('_','\\','-'), array('/','/','_'), ltrim($class, '\\')) . '.php';
  207. if (class_exists($class)) {
  208. return true;
  209. } elseif (file_exists($file)) {
  210. require_once($file);
  211. return true;
  212. } else {
  213. return false;
  214. }
  215. }
  216. }