/
extension.php
115 lines (101 loc) · 3.96 KB
/
extension.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<?php
/**
* Klasse die Einsprungpunkte zur Erweiterung der Kernfunktionalitaet bietet.
*
* @author Markus Staab
*
* @package redaxo\core
*/
abstract class rex_extension
{
use rex_factory_trait;
public const EARLY = -1;
public const NORMAL = 0;
public const LATE = 1;
/**
* Array of registered extensions.
*
* @var array<string, array<self::*, list<array{callable, array<string, mixed>}>>>
*/
private static $extensions = [];
/**
* Registers an extension point.
*
* @template T
* @param rex_extension_point<T> $extensionPoint Extension point
* @return T Subject, maybe adjusted by the extensions
*
* @psalm-taint-specialize
*/
public static function registerPoint(rex_extension_point $extensionPoint)
{
if ($factoryClass = static::getExplicitFactoryClass()) {
return $factoryClass::registerPoint($extensionPoint);
}
$name = $extensionPoint->getName();
rex_timer::measure('EP: ' . $name, static function () use ($extensionPoint, $name) {
foreach ([self::EARLY, self::NORMAL, self::LATE] as $level) {
if (!isset(self::$extensions[$name][$level]) || !is_array(self::$extensions[$name][$level])) {
continue;
}
foreach (self::$extensions[$name][$level] as $extensionAndParams) {
[$extension, $params] = $extensionAndParams;
$extensionPoint->setExtensionParams($params);
/** @var T|null $subject */
$subject = call_user_func($extension, $extensionPoint);
// Update subject only if the EP is not readonly and the extension has returned something
if ($extensionPoint->isReadonly()) {
continue;
}
if (null === $subject) {
continue;
}
$extensionPoint->setSubject($subject);
}
}
});
return $extensionPoint->getSubject();
}
/**
* Registers an extension for an extension point.
*
* @template T as rex_extension_point
* @param string|string[] $extensionPoint Name(s) of extension point(s)
* @param callable(T):mixed $extension Callback extension
* @param self::* $level Runlevel (`rex_extension::EARLY`, `rex_extension::NORMAL` or `rex_extension::LATE`)
* @param array<string, mixed> $params Additional params
* @return void
*/
public static function register($extensionPoint, callable $extension, $level = self::NORMAL, array $params = [])
{
if ($factoryClass = static::getExplicitFactoryClass()) {
$factoryClass::register($extensionPoint, $extension, $level, $params);
return;
}
// bc
if (is_string($level)) {
trigger_error(__METHOD__ . ': Argument $level should be one of the constants rex_extension::EARLY/NORMAL/LATE, but string "' . $level . '" given', E_USER_WARNING);
$level = (int) $level;
}
if (!in_array($level, [self::EARLY, self::NORMAL, self::LATE], true)) {
throw new InvalidArgumentException('Argument $level should be one of the constants rex_extension::EARLY/NORMAL/LATE, but "' . (is_int($level) ? $level : get_debug_type($level)) . '" given');
}
foreach ((array) $extensionPoint as $ep) {
self::$extensions[$ep][$level][] = [$extension, $params];
}
}
/**
* Checks whether an extension is registered for the given extension point.
*
* @param string $extensionPoint Name of extension point
*
* @return bool
*/
public static function isRegistered($extensionPoint)
{
if ($factoryClass = static::getExplicitFactoryClass()) {
return $factoryClass::isRegistered($extensionPoint);
}
return !empty(self::$extensions[$extensionPoint]);
}
}