Provider::getListenersForEvent()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 10

Duplication

Lines 10
Ratio 100 %

Importance

Changes 0
Metric Value
dl 10
loc 10
rs 9.9332
c 0
b 0
f 0
cc 4
nc 3
nop 1
1
<?php
2
3
/**
4
 * Phoole (PHP7.2+)
5
 *
6
 * @category  Library
7
 * @package   Phoole\Event
8
 * @copyright Copyright (c) 2019 Hong Zhang
9
 */
10
declare(strict_types=1);
11
12
namespace Phoole\Event;
13
14
use Phoole\Base\Reflect\ParameterTrait;
15
use Phoole\Base\Queue\UniquePriorityQueue;
16
use Psr\EventDispatcher\ListenerProviderInterface;
17
18
/**
19
 * Provider
20
 *
21
 * @package Phoole\Event
22
 */
23
class Provider implements ListenerProviderInterface
24
{
25
    use ParameterTrait;
26
27
    /**
28
     * event classes listened
29
     *
30
     * @var UniquePriorityQueue[]
31
     */
32
    protected $listened = [];
33
34
    /**
35
     * @param  object $event
36
     *   An event for which to return the relevant listeners.
37
     * @return iterable
38
     *   An iterable (array, iterator, or generator) of callables.  Each
39
     *   callable MUST be type-compatible with $event.
40
     */
41 View Code Duplication
    public function getListenersForEvent(object $event): iterable
42
    {
43
        $queue = new UniquePriorityQueue();
44
        foreach ($this->listened as $class => $q) {
45
            if (is_a($event, $class) && count($q)) {
46
                $queue = $queue->combine($q);
47
            }
48
        }
49
        return $queue;
50
    }
51
52
    /**
53
     * Attach a listener (with default priority 50) to the provider
54
     *
55
     * @param  callable $callable  MUST be type-compatible with $event.
56
     * @param  int      $priority  range 0 - 100, 0 means lower priority
57
     * @return $this
58
     * @throws \RuntimeException            reflection problem found
59
     * @throws \InvalidArgumentException    unknown type of callable found
60
     */
61
    public function attach(callable $callable, int $priority = 50)
62
    {
63
        $class = $this->getEventClass($callable);
64
        if (!isset($this->listened[$class])) {
65
            $this->listened[$class] = new UniquePriorityQueue();
66
        }
67
        $this->listened[$class]->insert($callable, $priority);
68
        return $this;
69
    }
70
71
    /**
72
     * Get callable's first argument EVENT class.
73
     *
74
     * @param  callable $callable
75
     * @return string                       classname or interface name
76
     * @throws \RuntimeException            reflection problem found
77
     * @throws \InvalidArgumentException    unknown type of callable found
78
     */
79
    protected function getEventClass(callable $callable): string
80
    {
81
        try {
82
            $params = $this->getCallableParameters($callable);
83
            $error = 'Listener must declare one object as event';
84
85
            // only one parameter allowed
86
            if (1 != count($params)) {
87
                throw new \InvalidArgumentException($error);
88
            }
89
90
            // must be object
91
            $type = $params[0]->getType()->getName();
92
            if (class_exists($type) || interface_exists($type)) {
93
                return $type;
94
            }
95
            throw new \InvalidArgumentException($error);
96
        } catch (\Throwable $e) {
97
            throw new \RuntimeException($e->getMessage());
98
        }
99
    }
100
}