PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/library/core/class.pluggable.php

https://github.com/Emaratilicious/Garden
PHP | 212 lines | 63 code | 26 blank | 123 comment | 26 complexity | c616c84547ce52289e7886bf3de2ca0a MD5 | raw file
  1. <?php if (!defined('APPLICATION')) exit();
  2. /*
  3. Copyright 2008, 2009 Vanilla Forums Inc.
  4. This file is part of Garden.
  5. Garden is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
  6. Garden is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  7. You should have received a copy of the GNU General Public License along with Garden. If not, see <http://www.gnu.org/licenses/>.
  8. Contact Vanilla Forums Inc. at support [at] vanillaforums [dot] com
  9. */
  10. /**
  11. * The Pluggable class is extended by other classes to enable the plugins
  12. * and the custom event model in plugins. Any class that extends this class
  13. * has the ability to throw custom events at any time, which can then be
  14. * handled by plugins.
  15. *
  16. * @author Mark O'Sullivan
  17. * @copyright 2009 Mark O'Sullivan
  18. * @license http://www.opensource.org/licenses/gpl-2.0.php GPL
  19. * @package Garden
  20. * @version @@GARDEN-VERSION@@
  21. * @namespace Garden.Core
  22. */
  23. /**
  24. * The Pluggable class is extended by other classes to enable the plugins
  25. * and the custom event model in plugins. Any class that extends this class
  26. * has the ability to throw custom events at any time, which can then be
  27. * handled by plugins.
  28. *
  29. * @package Garden
  30. */
  31. abstract class Gdn_Pluggable extends Gdn_SliceProvider {
  32. /**
  33. * The name of the class that has been instantiated. Typically this will be
  34. * a class that has extended this class.
  35. *
  36. * @var string
  37. */
  38. protected $ClassName;
  39. /**
  40. * Any arguments that should be passed into a plugin's event handler.
  41. * Typically these are variables that were defined before the event fired
  42. * and were local to the method being executed. It is an associative array
  43. * of Argument_Name => Argument_Value pairs. The EventArguments can be
  44. * accessed (and changed) in the plugin since the plugin has full
  45. * access to the object throwing the event (see FireEvent() below).
  46. *
  47. * @var array
  48. */
  49. public $EventArguments;
  50. /**
  51. * When any events are handled by plugins, the return values from those
  52. * method are saved in $this->Returns array as $EventHandlerName =>
  53. * array($PluginName => $ReturnValue) pairs.
  54. * Note: Method overrides and direct method call return values are NOT saved
  55. * in this array; they are returned as normal.
  56. * Example: To get the return value a plugin called "TestPlugin" that
  57. * attaches to an "ExampleController->Render()" method using the magic
  58. * "Before" event, you would reference it like so:
  59. * $ReturnVal = $Sender->Returns['ExampleController_BeforeRender_Handler']['TestPlugin'];
  60. *
  61. * @var array
  62. */
  63. public $Returns = array();
  64. /**
  65. * An enumerator indicating what type of handler the method being called is.
  66. * Options are:
  67. * HANDLER_TYPE_NORMAL: Standard call to a method on the object.
  68. * HANDLER_TYPE_OVERRIDE: Call to a method override.
  69. * HANDLER_TYPE_NEW: Call to a new object method.
  70. * The default value is HANDLER_TYPE_NORMAL;
  71. *
  72. * @var enumerator
  73. */
  74. public $HandlerType;
  75. /**
  76. * The public constructor of the class. If any extender of this class
  77. * overrides this one, parent::__construct(); should be called to ensure
  78. * interoperability.
  79. *
  80. */
  81. public function __construct() {
  82. $this->ClassName = get_class($this);
  83. $this->EventArguments = array();
  84. $this->Returns = array();
  85. $this->HandlerType = HANDLER_TYPE_NORMAL;
  86. }
  87. /**
  88. * @param unknown_type $PluginName
  89. * @param unknown_type $HandlerName
  90. * @return
  91. * @todo add doc
  92. */
  93. public function GetReturn($PluginName, $HandlerName) {
  94. return $this->Returns[strtolower($HandlerName)][strtolower($PluginName)];
  95. }
  96. /**
  97. * Fires an event to be dealt with by plugins. Plugins can create
  98. * custom methods to handle the event simply by naming their handler method
  99. * appropriately. The convention is:
  100. * public function SenderClassName_EventName_Handler($Sender) {}
  101. *
  102. * @param string $EventName The name of the event being fired.
  103. */
  104. public function FireEvent($EventName) {
  105. if (!$this->ClassName) {
  106. $RealClassName = get_class($this);
  107. throw new Exception("Event fired from pluggable class '{$RealClassName}', but Gdn_Pluggable::__construct() was never called.");
  108. }
  109. // Look to the PluginManager to see if there are related event handlers and call them
  110. return Gdn::PluginManager()->CallEventHandlers($this, $this->ClassName, $EventName);
  111. }
  112. /**
  113. * Used to extend any method
  114. *
  115. * There are two types of extended method calls:
  116. * 1. Declared: The method was declared with the lowercase "x" prefix and called without it.
  117. * ie. Declaration: public function xMethodName() {}
  118. * Call: $Object->MethodName();
  119. *
  120. * 2. Called: The method was declared without the lowercase "x" prefix and called with it.
  121. * ie. Declaration: public function MethodName() {}
  122. * Call: $Object->xMethodName();
  123. *
  124. * Note: Plugins will always refer to the method name without the "x"
  125. * regardless of the type. So, $ReferenceMethodName is declared below without
  126. * the "x".
  127. *
  128. *
  129. * @param string $MethodName
  130. * @param array $Arguments
  131. * @return mixed
  132. *
  133. */
  134. public function __call($MethodName, $Arguments) {
  135. // Define a return variable.
  136. $Return = FALSE;
  137. // Was this method declared, or called?
  138. if (substr($MethodName, 0, 1) == 'x') {
  139. // Declared
  140. $ActualMethodName = substr($MethodName, 1); // Remove the x prefix
  141. $ReferenceMethodName = $ActualMethodName; // No x prefix
  142. } else {
  143. // Called
  144. $ActualMethodName = 'x' . $MethodName; // Add the x prefix
  145. $ReferenceMethodName = $MethodName; // No x prefix
  146. }
  147. // Make sure that $ActualMethodName exists before continuing:
  148. if (!method_exists($this, $ActualMethodName)) {
  149. // Make sure that a plugin is not handling the call
  150. if (!Gdn::PluginManager()->HasNewMethod($this->ClassName, $ReferenceMethodName))
  151. trigger_error(ErrorMessage('The "' . $this->ClassName . '" object does not have a "' . $ActualMethodName . '" method.', $this->ClassName, $ActualMethodName), E_USER_ERROR);
  152. }
  153. // Make sure the arguments get passed in the same way whether firing a custom event or a magic one.
  154. $this->EventArguments = $Arguments;
  155. // Call the "Before" event handlers
  156. Gdn::PluginManager()->CallEventHandlers($this, $this->ClassName, $ReferenceMethodName, 'Before');
  157. // Call this object's method
  158. if (Gdn::PluginManager()->HasMethodOverride($this->ClassName, $ReferenceMethodName) === TRUE) {
  159. // The method has been overridden
  160. $this->HandlerType = HANDLER_TYPE_OVERRIDE;
  161. $Return = Gdn::PluginManager()->CallMethodOverride($this, $this->ClassName, $ReferenceMethodName);
  162. } else if (Gdn::PluginManager()->HasNewMethod($this->ClassName, $ReferenceMethodName) === TRUE) {
  163. $this->HandlerType = HANDLER_TYPE_NEW;
  164. $Return = Gdn::PluginManager()->CallNewMethod($this, $this->ClassName, $ReferenceMethodName);
  165. } else {
  166. // The method has not been overridden
  167. $Count = count($Arguments);
  168. if ($Count == 0) {
  169. $Return = $this->$ActualMethodName();
  170. } else if ($Count == 1) {
  171. $Return = $this->$ActualMethodName($Arguments[0]);
  172. } else if ($Count == 2) {
  173. $Return = $this->$ActualMethodName($Arguments[0], $Arguments[1]);
  174. } else if ($Count == 3) {
  175. $Return = $this->$ActualMethodName($Arguments[0], $Arguments[1], $Arguments[2]);
  176. } else if ($Count == 4) {
  177. $Return = $this->$ActualMethodName($Arguments[0], $Arguments[1], $Arguments[2], $Arguments[3]);
  178. } else {
  179. $Return = $this->$ActualMethodName($Arguments[0], $Arguments[1], $Arguments[2], $Arguments[3], $Arguments[4]);
  180. }
  181. }
  182. // Call the "After" event handlers
  183. Gdn::PluginManager()->CallEventHandlers($this, $this->ClassName, $MethodName, 'After');
  184. return $Return;
  185. }
  186. }