Completed
Push — master ( 06e909...4a8c36 )
by Hong
02:24
created

Provider::getEventClass()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.3222
c 0
b 0
f 0
cc 5
nc 7
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\Queue\PriorityQueue;
15
use Phoole\Base\Reflect\ParameterTrait;
16
use Psr\EventDispatcher\EventDispatcherInterface;
17
use Psr\EventDispatcher\ListenerProviderInterface;
18
19
/**
20
 * Provider
21
 *
22
 * @package Phoole\Event
23
 */
24
class Provider implements ListenerProviderInterface
25
{
26
    use ParameterTrait;
27
28
    /**
29
     * event classes listened
30
     * @var PriorityQueue[]
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 PriorityQueue();
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
     * @throws \InvalidArgumentException    unknown type of callable found
58
     * @throws \RuntimeException            reflection problem found
59
     * @return ListenerProviderInterface $this
60
     */
61
    public function attach(callable $callable, int $priority = 50): ListenerProviderInterface
62
    {
63
        $class = $this->getEventClass($callable);
64
        if (!isset($this->listened[$class])) {
65
            $this->listened[$class] = new PriorityQueue();
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
     * @throws \InvalidArgumentException    unknown type of callable found
76
     * @throws \RuntimeException            reflection problem found
77
     * @return string                       classname or interface name
78
     */
79
    protected function getEventClass(callable $callable): string
80
    {
81
        try {
82
            $params = $this->getCallableParameters($callable);
83
84
            $error = 'Listener must declare one object as event';
85
            if (1 != count($params)) {
86
                throw new \InvalidArgumentException($error);
87
            }
88
89
            $type = $params[0]->getType()->getName();
90
            if (class_exists($type) || interface_exists($type)) {
91
                return $type;
92
            }
93
            throw new \InvalidArgumentException($error);
94
        } catch (\Throwable $e) {
95
            throw new \RuntimeException($e->getMessage());
96
        }
97
    }
98
}
99