Elgg  Version 4.3
HooksRegistrationService.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg;
4 
8 
14 abstract class HooksRegistrationService {
15 
16  use Loggable;
17 
18  const REG_KEY_PRIORITY = 0;
19  const REG_KEY_INDEX = 1;
20  const REG_KEY_HANDLER = 2;
21 
22  const OPTION_DEPRECATION_MESSAGE = 'deprecation_message';
23  const OPTION_DEPRECATION_VERSION = 'deprecation_version';
24 
28  private $next_index = 0;
29 
33  private $registrations = [];
34 
38  private $backups = [];
39 
54  public function registerHandler($name, $type, $callback, $priority = 500) {
55  if (empty($name) || empty($type) || !is_callable($callback, true)) {
56  return false;
57  }
58 
59  $services = _elgg_services();
60  if (in_array($this->getLogger()->getLevel(false), [LogLevel::WARNING, LogLevel::NOTICE, LogLevel::INFO, LogLevel::DEBUG])) {
61  if (!$services->handlers->isCallable($callback)) {
62  $this->getLogger()->warning('Handler: ' . $services->handlers->describeCallable($callback) . ' is not callable');
63  }
64  }
65 
66  $this->registrations[$name][$type][] = [
67  self::REG_KEY_PRIORITY => $priority,
68  self::REG_KEY_INDEX => $this->next_index,
69  self::REG_KEY_HANDLER => $callback,
70  ];
71  $this->next_index++;
72 
73  return true;
74  }
75 
89  public function unregisterHandler($name, $type, $callback) {
90  if (empty($this->registrations[$name][$type])) {
91  return false;
92  }
93 
94  $matcher = $this->getMatcher($callback);
95 
96  foreach ($this->registrations[$name][$type] as $i => $registration) {
97  if ($matcher) {
98  if (!$matcher->matches($registration[self::REG_KEY_HANDLER])) {
99  continue;
100  }
101  } else {
102  if ($registration[self::REG_KEY_HANDLER] != $callback) {
103  continue;
104  }
105  }
106 
107  unset($this->registrations[$name][$type][$i]);
108  return true;
109  }
110 
111  return false;
112  }
113 
124  public function clearHandlers($name, $type) {
125  unset($this->registrations[$name][$type]);
126  }
127 
141  public function getAllHandlers() {
142  $ret = [];
143  foreach ($this->registrations as $name => $types) {
144  foreach ($types as $type => $registrations) {
145  foreach ($registrations as $registration) {
146  $priority = $registration[self::REG_KEY_PRIORITY];
147  $handler = $registration[self::REG_KEY_HANDLER];
148  $ret[$name][$type][$priority][] = $handler;
149  }
150  }
151  }
152 
153  return $ret;
154  }
155 
166  public function hasHandler($name, $type) {
167  return !empty($this->registrations[$name][$type]);
168  }
169 
178  public function getOrderedHandlers($name, $type) {
179  $registrations = [];
180 
181  if (!empty($this->registrations[$name][$type])) {
182  if ($name !== 'all' && $type !== 'all') {
183  array_splice($registrations, count($registrations), 0, $this->registrations[$name][$type]);
184  }
185  }
186  if (!empty($this->registrations['all'][$type])) {
187  if ($type !== 'all') {
188  array_splice($registrations, count($registrations), 0, $this->registrations['all'][$type]);
189  }
190  }
191  if (!empty($this->registrations[$name]['all'])) {
192  if ($name !== 'all') {
193  array_splice($registrations, count($registrations), 0, $this->registrations[$name]['all']);
194  }
195  }
196  if (!empty($this->registrations['all']['all'])) {
197  array_splice($registrations, count($registrations), 0, $this->registrations['all']['all']);
198  }
199 
200  usort($registrations, function ($a, $b) {
201  // priority first
202  if ($a[self::REG_KEY_PRIORITY] < $b[self::REG_KEY_PRIORITY]) {
203  return -1;
204  }
205  if ($a[self::REG_KEY_PRIORITY] > $b[self::REG_KEY_PRIORITY]) {
206  return 1;
207  }
208  // then insertion order
209  return ($a[self::REG_KEY_INDEX] < $b[self::REG_KEY_INDEX]) ? -1 : 1;
210  });
211 
212  $handlers = [];
213  foreach ($registrations as $registration) {
214  $handlers[] = $registration[self::REG_KEY_HANDLER];
215  }
216 
217  return $handlers;
218  }
219 
227  protected function getMatcher($spec) {
228  if (is_string($spec) && false !== strpos($spec, '::')) {
229  list ($type, $method) = explode('::', $spec, 2);
230  return new MethodMatcher($type, $method);
231  }
232 
233  if (!is_array($spec) || empty($spec[0]) || empty($spec[1]) || !is_string($spec[1])) {
234  return null;
235  }
236 
237  if (is_object($spec[0])) {
238  $spec[0] = get_class($spec[0]);
239  }
240 
241  if (!is_string($spec[0])) {
242  return null;
243  }
244 
245  return new MethodMatcher($spec[0], $spec[1]);
246  }
247 
258  public function backup() {
259  $this->backups[] = $this->registrations;
260  $this->registrations = [];
261  }
262 
269  public function restore() {
270  $backup = array_pop($this->backups);
271  if (is_array($backup)) {
272  $this->registrations = $backup;
273  }
274  }
275 
285  protected function checkDeprecation($name, $type, array $options = []) {
286  $options = array_merge([
287  self::OPTION_DEPRECATION_MESSAGE => '',
288  self::OPTION_DEPRECATION_VERSION => '',
289  ], $options);
290 
291  $handlers = $this->hasHandler($name, $type);
292  if (!$handlers || !$options[self::OPTION_DEPRECATION_MESSAGE]) {
293  return;
294  }
295 
296  $this->logDeprecatedMessage(
297  $options[self::OPTION_DEPRECATION_MESSAGE],
298  $options[self::OPTION_DEPRECATION_VERSION]
299  );
300  }
301 }
clearHandlers($name, $type)
Clears all callback registrations for a plugin hook.
hasHandler($name, $type)
Is a handler registered for this specific name and type? "all" handlers are not considered.
if(!$user||!$user->canDelete()) $name
Definition: delete.php:22
registerHandler($name, $type, $callback, $priority=500)
Register a callback as a plugin hook handler.
$type
Definition: delete.php:21
$options
Elgg admin footer.
Definition: footer.php:6
backup()
Temporarily remove all event/hook registrations (before tests)
trait Loggable
Enables adding a logger.
Definition: Loggable.php:14
Base class for events and hooks.
getMatcher($spec)
Create a matcher for the given callable (if it&#39;s for a static or dynamic method)
checkDeprecation($name, $type, array $options=[])
Check if handlers are registered on a deprecated hook/event.
getLogger()
Returns logger.
Definition: Loggable.php:37
Identify a static/dynamic method callable, even if contains an object to which you don&#39;t have a refer...
_elgg_services()
Get the global service provider.
Definition: elgglib.php:638
getAllHandlers()
Returns all registered handlers as array( $name => array( $type => array( $priority => array( callbac...
$handler
Definition: add.php:7
unregisterHandler($name, $type, $callback)
Unregister a callback as a plugin hook of event handler.
$priority
logDeprecatedMessage(string $message, string $version)
Sends a message about deprecated use of a function, view, etc.
Definition: Loggable.php:80
restore()
Restore backed up event/hook registrations (after tests)
getOrderedHandlers($name, $type)
Returns an ordered array of handlers registered for $name and $type.