Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
46 / 46
100.00% covered (success)
100.00%
18 / 18
CRAP
100.00% covered (success)
100.00%
1 / 1
Manager
100.00% covered (success)
100.00%
46 / 46
100.00% covered (success)
100.00%
18 / 18
32
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
3
 on
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 off
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
 get
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 has
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getResults
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 alive
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 trigger
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
6
 __set
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __get
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __isset
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __unset
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 offsetSet
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 offsetGet
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 offsetExists
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 offsetUnset
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 count
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getIterator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Event;
15
16use Pop\Utils\CallableObject;
17use ArrayAccess;
18use ArrayIterator;
19use Countable;
20use IteratorAggregate;
21
22/**
23 * Event manager class
24 *
25 * @category   Pop
26 * @package    Pop\Event
27 * @author     Nick Sagona, III <dev@nolainteractive.com>
28 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
29 * @license    http://www.popphp.org/license     New BSD License
30 * @version    4.2.0
31 */
32class Manager implements ArrayAccess, Countable, IteratorAggregate
33{
34
35    /**
36     * Constant to stop the event manager
37     * @var string
38     */
39    const STOP = 'Pop\Event\Manager::STOP';
40
41    /**
42     * Constant to send a kill signal to the application
43     * @var string
44     */
45    const KILL = 'Pop\Event\Manager::KILL';
46
47    /**
48     * Event listeners
49     * @var array
50     */
51    protected array $listeners = [];
52
53    /**
54     * Event results
55     * @var array
56     */
57    protected array $results = [];
58
59    /**
60     * Event 'alive' tracking flag
61     * @var bool
62     */
63    protected bool $alive = true;
64
65    /**
66     * Constructor
67     *
68     * Instantiate the event manager object.
69     *
70     * @param  ?string $name
71     * @param  mixed   $action
72     * @param  int     $priority
73     */
74    public function __construct(?string $name = null, mixed $action = null, int $priority = 0)
75    {
76        if (($name !== null) && ($action !== null)) {
77            $this->on($name, $action, $priority);
78        }
79    }
80
81    /**
82     * Attach an event listener
83     *
84     *     $event->on('event.name', 'someFunction');
85     *     $event->on('event.name', function() { ... });
86     *     $event->on('event.name', new SomeClass());
87     *     $event->on('event.name', [new SomeClass, 'foo']);
88     *     $event->on('event.name', 'SomeClass');
89     *     $event->on('event.name', 'SomeClass->foo');
90     *     $event->on('event.name', 'SomeClass::bar');
91     *
92     * @param  string $name
93     * @param  mixed  $action
94     * @param  int    $priority
95     * @return Manager
96     */
97    public function on(string $name, mixed $action, int $priority = 0): static
98    {
99        if (!isset($this->listeners[$name])) {
100            $this->listeners[$name] = new \SplPriorityQueue();
101        }
102        $this->listeners[$name]->insert(new CallableObject($action), (int)$priority);
103
104        return $this;
105    }
106
107    /**
108     * Detach an event listener
109     *
110     * @param  string $name
111     * @param  mixed  $action
112     * @return Manager
113     */
114    public function off(string $name, mixed $action): static
115    {
116        // If the event exists, loop through and remove the action if found.
117        if (isset($this->listeners[$name])) {
118            $newListeners = new \SplPriorityQueue();
119
120            $listeners = clone $this->listeners[$name];
121            $listeners->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);
122
123            foreach ($listeners as $value) {
124                $item = $listeners->current();
125                if ($action !== $item['data']) {
126                    $newListeners->insert($item['data'], $item['priority']);
127                }
128            }
129
130            $this->listeners[$name] = $newListeners;
131        }
132
133        return $this;
134    }
135
136    /**
137     * Return an event
138     *
139     * @param  string $name
140     * @return mixed
141     */
142    public function get(string $name): mixed
143    {
144        $listener = null;
145        if (isset($this->listeners[$name])) {
146            $listener = $this->listeners[$name];
147        }
148
149        return $listener;
150    }
151
152    /**
153     * Determine whether the event manage has an event registered with it
154     *
155     * @param  string $name
156     * @return bool
157     */
158    public function has(string $name): bool
159    {
160        return (isset($this->listeners[$name]));
161    }
162
163    /**
164     * Return the event results
165     *
166     * @param  string $name
167     * @return mixed
168     */
169    public function getResults(string $name): mixed
170    {
171        return $this->results[$name] ?? null;
172    }
173
174    /**
175     * Determine if the project application is still alive or has been killed
176     *
177     * @return bool
178     */
179    public function alive(): bool
180    {
181        return $this->alive;
182    }
183
184    /**
185     * Trigger an event listener priority
186     *
187     * @param  string $name
188     * @param  array  $params
189     * @return void
190     */
191    public function trigger(string $name, array $params = []): void
192    {
193        if (isset($this->listeners[$name])) {
194            if (!isset($this->results[$name])) {
195                $this->results[$name] = [];
196            }
197
198            foreach ($this->listeners[$name] as $action) {
199                if (end($this->results[$name]) == self::STOP) {
200                    return;
201                }
202
203                $params['result']       = end($this->results[$name]);
204                $result                 = $action->call($params);
205                $this->results[$name][] = $result;
206
207                if ($result == self::KILL) {
208                    $this->alive = false;
209                }
210            }
211        }
212    }
213
214    /**
215     * Set an event
216     *
217     * @param  string $name
218     * @param  mixed  $value
219     * @return void
220     */
221    public function __set(string $name, mixed $value): void
222    {
223        $this->on($name, $value);
224    }
225
226    /**
227     * Get an event
228     *
229     * @param  string $name
230     * @return mixed
231     */
232    public function __get(string $name): mixed
233    {
234        return $this->get($name);
235    }
236
237    /**
238     * Determine if an event exists
239     *
240     * @param  string $name
241     * @return bool
242     */
243    public function __isset(string $name): bool
244    {
245        return $this->has($name);
246    }
247
248    /**
249     * Unset an event
250     *
251     * @param  string $name
252     * @return void
253     */
254    public function __unset(string $name): void
255    {
256        if (isset($this->listeners[$name])) {
257            unset($this->listeners[$name]);
258        }
259    }
260
261    /**
262     * Set an event
263     *
264     * @param  mixed $offset
265     * @param  mixed  $value
266     * @return void
267     */
268    public function offsetSet(mixed $offset, mixed $value): void
269    {
270        $this->on($offset, $value);
271    }
272
273    /**
274     * Get an event
275     *
276     * @param  mixed $offset
277     * @return mixed
278     */
279    public function offsetGet(mixed $offset): mixed
280    {
281        return $this->get($offset);
282    }
283
284    /**
285     * Determine if an event exists
286     *
287     * @param  string $offset
288     * @return bool
289     */
290    public function offsetExists($offset): bool
291    {
292        return $this->has($offset);
293    }
294
295    /**
296     * Unset an event
297     *
298     * @param  mixed $offset
299     * @return void
300     */
301    public function offsetUnset(mixed $offset): void
302    {
303        if (isset($this->listeners[$offset])) {
304            unset($this->listeners[$offset]);
305        }
306    }
307
308    /**
309     * Return count
310     *
311     * @return int
312     */
313    public function count(): int
314    {
315        return count($this->listeners);
316    }
317
318    /**
319     * Get iterator
320     *
321     * @return ArrayIterator
322     */
323    public function getIterator(): ArrayIterator
324    {
325        return new ArrayIterator($this->listeners);
326    }
327
328}