1
|
|
|
<?php |
2
|
|
|
namespace Elgg; |
3
|
|
|
|
4
|
|
|
use Elgg\HooksRegistrationService\Hook; |
|
|
|
|
5
|
|
|
|
6
|
|
|
/** |
7
|
|
|
* Plugin Hooks (and Events) |
8
|
|
|
* |
9
|
|
|
* @tip Use ->hooks from the service provider. |
10
|
|
|
* |
11
|
|
|
* @access private |
12
|
|
|
*/ |
13
|
|
|
class PluginHooksService extends HooksRegistrationService { |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* @var EventsService |
17
|
|
|
*/ |
18
|
|
|
private $events; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* Constructor |
22
|
|
|
* |
23
|
|
|
* @param EventsService $events Events |
24
|
|
|
*/ |
25
|
4417 |
|
public function __construct(EventsService $events = null) { |
26
|
4417 |
|
if ($events === null) { |
27
|
|
|
// for unit tests |
28
|
246 |
|
$events = new EventsService(new HandlersService()); |
29
|
|
|
} |
30
|
|
|
|
31
|
4417 |
|
$this->events = $events; |
32
|
4417 |
|
} |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Get the events API |
36
|
|
|
* |
37
|
|
|
* @return EventsService |
38
|
|
|
*/ |
39
|
5031 |
|
public function getEvents() { |
40
|
5031 |
|
return $this->events; |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Triggers a plugin hook |
45
|
|
|
* |
46
|
|
|
* @see elgg_trigger_plugin_hook |
47
|
|
|
* @access private |
48
|
|
|
*/ |
49
|
1896 |
|
public function trigger($name, $type, $params = null, $value = null) { |
50
|
|
|
|
51
|
|
|
// This starts as a string, but if a handler type-hints an object we convert it on-demand inside |
52
|
|
|
// \Elgg\HandlersService::call and keep it alive during all handler calls. We do this because |
53
|
|
|
// creating objects for every triggering is expensive. |
54
|
1896 |
|
$hook = 'hook'; |
55
|
|
|
/* @var Hook|string $hook */ |
56
|
|
|
|
57
|
1896 |
|
$handlers = $this->events->getHandlersService(); |
58
|
|
|
|
59
|
1896 |
|
foreach ($this->getOrderedHandlers($name, $type) as $handler) { |
60
|
517 |
|
$exit_warning = null; |
61
|
|
|
|
62
|
517 |
|
if (in_array($name, ['forward', 'action', 'route'])) { |
63
|
|
|
// assume the handler is going to exit the request... |
64
|
30 |
|
$exit_warning = function () use ($name, $type, $handler, $handlers) { |
65
|
|
|
_elgg_services()->deprecation->sendNotice( |
66
|
|
|
"'$name', '$type' plugin hook should not be used to serve a response. Instead return an " |
67
|
|
|
. "appropriate ResponseBuilder instance from an action or page handler. Do not terminate " |
68
|
|
|
. "code execution with exit() or die() in {$handlers->describeCallable($handler)}", |
69
|
|
|
'2.3' |
70
|
|
|
); |
71
|
30 |
|
}; |
72
|
30 |
|
$this->events->registerHandler('shutdown', 'system', $exit_warning); |
73
|
|
|
} |
74
|
|
|
|
75
|
517 |
|
list($success, $return, $hook) = $handlers->call($handler, $hook, [$name, $type, $value, $params]); |
76
|
|
|
|
77
|
516 |
|
if ($exit_warning) { |
78
|
|
|
// an exit did not occur, so no need for the warning... |
79
|
30 |
|
$this->events->unregisterHandler('shutdown', 'system', $exit_warning); |
80
|
|
|
} |
81
|
|
|
|
82
|
516 |
|
if (!$success) { |
83
|
2 |
|
continue; |
84
|
|
|
} |
85
|
515 |
|
if ($return !== null) { |
86
|
483 |
|
$value = $return; |
87
|
483 |
|
if ($hook instanceof Hook) { |
88
|
515 |
|
$hook->setValue($return); |
89
|
|
|
} |
90
|
|
|
} |
91
|
|
|
} |
92
|
|
|
|
93
|
1895 |
|
return $value; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* {@inheritdoc} |
98
|
|
|
*/ |
99
|
4980 |
|
public function registerHandler($name, $type, $callback, $priority = 500) { |
100
|
4980 |
|
if (($name == 'view' || $name == 'view_vars') && $type !== 'all') { |
101
|
35 |
|
$type = ViewsService::canonicalizeViewName($type); |
102
|
|
|
} |
103
|
|
|
|
104
|
4980 |
|
return parent::registerHandler($name, $type, $callback, $priority); |
105
|
|
|
} |
106
|
|
|
} |
107
|
|
|
|
Let?s assume that you have a directory layout like this:
and let?s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/Foo.php
are loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php
However, as
OtherDir/Foo.php
does not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php
, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: