WrappedListener::getInfo()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 2
nop 1
dl 0
loc 13
ccs 8
cts 8
cp 1
crap 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Biurad opensource projects.
7
 *
8
 * PHP version 7.2 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 Biurad Group (https://biurad.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Biurad\Events;
19
20
use Psr\EventDispatcher\StoppableEventInterface;
21
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
22
use Symfony\Contracts\EventDispatcher\Event;
23
24
/**
25
 * @author Fabien Potencier <[email protected]>
26
 * @author Divine Niiquaye Ibok <[email protected]>
27
 */
28
final class WrappedListener
29
{
30
    /** @var mixed */
31
    private $listener;
32
33
    /** @var string */
34
    private $name;
35
36
    /** @var bool */
37
    private $called;
38
39
    /** @var bool */
40
    private $stoppedPropagation;
41
42
    /** @var null|EventDispatcherInterface */
43
    private $dispatcher;
44
45
    /** @var string */
46
    private $duration;
47
48
    /** @var null|string */
49
    private $pretty;
50
51
    /** @var null|int */
52
    private $priority;
53
54
    /**
55
     * @param mixed                    $listener
56
     * @param null|string              $name
57
     * @param EventDispatcherInterface $dispatcher
58
     */
59 28
    public function __construct($listener, ?string $name, EventDispatcherInterface $dispatcher = null)
60
    {
61 28
        if (\is_callable($listener)) {
62 26
            $listener = \Closure::fromCallable($listener);
63
        }
64
65 28
        $this->listener           = $listener;
66 28
        $this->dispatcher         = $dispatcher;
67 28
        $this->called             = false;
68 28
        $this->stoppedPropagation = false;
69
70 28
        $this->trackEventListener($this->listener);
71
72 28
        if (null !== $name) {
73 1
            $this->name = $name;
74
        }
75 28
    }
76
77 17
    public function __invoke(Event $event, string $eventName, EventDispatcherInterface $dispatcher): void
78
    {
79 17
        $dispatcher = $this->dispatcher ?? $dispatcher;
80
81 17
        $this->called   = true;
82 17
        $this->priority = $dispatcher->getListenerPriority($eventName, $this->listener);
83 17
        $timeStart      = \microtime(true);
84
85
        try {
86 17
            ($this->listener)($event, $eventName, $dispatcher);
87 4
        } catch (\TypeError $e) {
88 4
            if (!$dispatcher instanceof TraceableEventDispatcher) {
89 1
                throw $e;
90
            }
91
92 3
            if ($this->isLazyDispatcher($dispatcher)) {
93 3
                $dispatcher->getResolver()->call($this->listener, [
0 ignored issues
show
Bug introduced by
The method getResolver() does not exist on Biurad\Events\TraceableEventDispatcher. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

93
                $dispatcher->/** @scrutinizer ignore-call */ 
94
                             getResolver()->call($this->listener, [
Loading history...
94 3
                    \get_class($event)               => $event,
95 3
                    'eventName'                      => $eventName,
96 3
                    \get_class($dispatcher)          => $dispatcher,
97
                ]);
98
            }
99
        }
100
101 16
        $this->duration = \number_format((\microtime(true) - $timeStart) * 1000, 2) . 'ms';
102
103 16
        if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
104 2
            $this->stoppedPropagation = true;
105
        }
106 16
    }
107
108
    /**
109
     * @return mixed
110
     */
111 16
    public function getWrappedListener()
112
    {
113 16
        return $this->listener;
114
    }
115
116 17
    public function wasCalled(): bool
117
    {
118 17
        return $this->called;
119
    }
120
121 17
    public function stoppedPropagation(): bool
122
    {
123 17
        return $this->stoppedPropagation;
124
    }
125
126 25
    public function getPretty(): ?string
127
    {
128 25
        return $this->pretty;
129
    }
130
131
    /**
132
     * @param string $eventName
133
     *
134
     * @return array<string,mixed>
135
     */
136 4
    public function getInfo(string $eventName): array
137
    {
138 4
        $priority = $this->priority;
139
140 4
        if (null === $priority && null !== $this->dispatcher) {
141 2
            $priority = $this->dispatcher->getListenerPriority($eventName, $this->listener);
142
        }
143
144
        return [
145 4
            'event'      => $eventName,
146 4
            'priority'   => $priority,
147 4
            'duration'   => $this->duration,
148 4
            'pretty'     => $this->pretty,
149
        ];
150
    }
151
152 3
    private function isLazyDispatcher(EventDispatcherInterface $dispatcher): bool
153
    {
154 3
        if ($dispatcher instanceof TraceableEventDispatcher) {
155 3
            $dispatcher = $dispatcher->getDispatcher();
156
        }
157
158 3
        return $dispatcher instanceof LazyEventDispatcher;
159
    }
160
161
    /**
162
     * @param mixed $listener
163
     */
164 28
    private function trackEventListener($listener): void
165
    {
166 28
        if (\is_array($listener)) {
167 1
            $this->name   = \is_object($listener[0]) ? get_debug_type($listener[0]) : $listener[0];
168 1
            $this->pretty = $this->name . '::' . $listener[1];
169
170 1
            return;
171
        }
172
173 27
        if ($listener instanceof \Closure) {
174 26
            $r = new \ReflectionFunction($listener);
175
176 26
            if (false !== \strpos($r->name, '{closure}')) {
177 20
                $this->pretty = $this->name = 'closure';
178 6
            } elseif (null !== $class = $r->getClosureScopeClass()) {
179 5
                $this->name   = $class->name;
180 5
                $this->pretty = $this->name . '::' . $r->name;
181
            } else {
182 1
                $this->pretty = $this->name = $r->name;
183
            }
184
185 26
            return;
186
        }
187
188 1
        $this->pretty = \is_string($listener) ? $this->name = $listener : null;
189 1
    }
190
}
191