Parse and validate AT Protocol Lexicons with DTO generation for Laravel
1<?php
2
3namespace SocialDept\AtpSchema\Support;
4
5use Closure;
6
7class ExtensionManager
8{
9 /**
10 * Registered hooks.
11 *
12 * @var array<string, array<Closure>>
13 */
14 protected array $hooks = [];
15
16 /**
17 * Register a hook callback.
18 */
19 public function hook(string $name, Closure $callback): self
20 {
21 if (! isset($this->hooks[$name])) {
22 $this->hooks[$name] = [];
23 }
24
25 $this->hooks[$name][] = $callback;
26
27 return $this;
28 }
29
30 /**
31 * Execute all hooks for a given name.
32 *
33 * @return array<mixed>
34 */
35 public function execute(string $name, mixed ...$args): array
36 {
37 if (! isset($this->hooks[$name])) {
38 return [];
39 }
40
41 $results = [];
42
43 foreach ($this->hooks[$name] as $callback) {
44 $results[] = $callback(...$args);
45 }
46
47 return $results;
48 }
49
50 /**
51 * Execute hooks and return the first non-null result.
52 */
53 public function executeUntil(string $name, mixed ...$args): mixed
54 {
55 if (! isset($this->hooks[$name])) {
56 return null;
57 }
58
59 foreach ($this->hooks[$name] as $callback) {
60 $result = $callback(...$args);
61
62 if ($result !== null) {
63 return $result;
64 }
65 }
66
67 return null;
68 }
69
70 /**
71 * Execute hooks with a value that can be modified by each hook.
72 */
73 public function filter(string $name, mixed $value, mixed ...$args): mixed
74 {
75 if (! isset($this->hooks[$name])) {
76 return $value;
77 }
78
79 foreach ($this->hooks[$name] as $callback) {
80 $value = $callback($value, ...$args);
81 }
82
83 return $value;
84 }
85
86 /**
87 * Check if a hook has any callbacks registered.
88 */
89 public function has(string $name): bool
90 {
91 return isset($this->hooks[$name]) && count($this->hooks[$name]) > 0;
92 }
93
94 /**
95 * Get all callbacks for a hook.
96 *
97 * @return array<Closure>
98 */
99 public function get(string $name): array
100 {
101 return $this->hooks[$name] ?? [];
102 }
103
104 /**
105 * Remove all callbacks for a hook.
106 */
107 public function remove(string $name): self
108 {
109 unset($this->hooks[$name]);
110
111 return $this;
112 }
113
114 /**
115 * Clear all hooks.
116 */
117 public function clear(): self
118 {
119 $this->hooks = [];
120
121 return $this;
122 }
123
124 /**
125 * Get count of callbacks for a hook.
126 */
127 public function count(string $name): int
128 {
129 return count($this->hooks[$name] ?? []);
130 }
131
132 /**
133 * Get all registered hook names.
134 *
135 * @return array<string>
136 */
137 public function names(): array
138 {
139 return array_keys($this->hooks);
140 }
141}