Completed
Push — master ( aa3135...09344c )
by Pierre
121:26 queued 118:18
created

Dispatcher.php$0 ➔ closureToListener()   A

Complexity

Conditions 1

Size

Total Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 38
ccs 0
cts 8
cp 0
crap 2
rs 9.312
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A Dispatcher.php$0 ➔ __construct() 0 8 2
A Dispatcher.php$0 ➔ publish() 0 3 1
1
<?php
2
3
namespace App\Component\Pubsub;
4
5
use Closure;
6
use Exception;
7
8
class Dispatcher implements DispatcherInterface
9
{
10
11
    /**
12
     * listener stack.
13
     * Struct : [resName][event][hash]
14
     *
15
     * @var array
16
     */
17
    protected $stack = array();
18
19
    /**
20
     * Subscribes the listener to the resource's events.
21
     * If $resName is *, 
22
     * then the listener will be dispatched when the specified event 
23
     * is fired.
24
     * If $event is *, 
25
     * then the listener will be dispatched 
26
     * for any dispatched event of the specified resource.
27
     * If $resName and $event is *, 
28
     * the listener will be dispatched 
29
     * for any dispatched event for any resource.
30
     *
31
     * @param ListenerInterface $listener
32
     * @param String $resName
33
     * @param Mixed $event
34
     * @return Dispatcher
35
     */
36
    public function subscribe(
37
        ListenerInterface $listener,
38
        $resName = self::ALL,
39
        $event = self::ALL
40
    ): DispatcherInterface {
41
        $hash = $this->hash($listener);
42
        $this->stack[$resName][$event][$hash] = $listener;
43
        return $this;
44
    }
45
46
    /**
47
     * Subscribes the listener to the resource's events.
48
     * If $resName is *, 
49
     * then the listener will be dispatched when the specified event 
50
     * is fired.
51
     * If $event is *, 
52
     * then the listener will be dispatched 
53
     * for any dispatched event of the specified resource.
54
     * If $resName and $event is *, 
55
     * the listener will be dispatched 
56
     * for any dispatched event for any resource.
57
     *
58
     * @param Closure $closure
59
     * @param String $resName
60
     * @param Mixed $event
61
     * @return Dispatcher
62
     */
63
    public function subscribeClosure(
64
        Closure $closure,
65
        $resName = self::ALL,
66
        $event = self::ALL
67
    ): DispatcherInterface {
68
        $listener = $this->closureToListener($closure);
69
        $hash = $this->hash($listener);
70
        $this->stack[$resName][$event][$hash] = $listener;
71
        return $this;
72
    }
73
74
    /**
75
     * Unsubscribes the listener from the resource's events
76
     *
77
     * @param ListenerInterface $listener
78
     * @param String $resName
79
     * @param Mixed $event
80
     * @return Dispatcher
81
     */
82
    public function unsubscribe(
83
        ListenerInterface $listener,
84
        $resName = self::ALL,
85
        $event = self::ALL
86
    ): DispatcherInterface {
87
        $hash = $this->hash($listener);
88
        unset($this->stack[$resName][$event][$hash]);
89
        return $this;
90
    }
91
92
    /**
93
     * Publishes an event to all the listeners 
94
     * listening to the specified event 
95
     * for the specified resource
96
     *
97
     * @param EventInterface $event
98
     * @return Dispatcher
99
     */
100
    public function publish(EventInterface $event): DispatcherInterface
101
    {
102
        $resName = $event->getResourceName();
103
        $eventName = $event->getEventName();
104
        $this
105
            ->dispatchAllHandlers($event)
106
            ->dispatchResourcedHandlers($resName, $event)
107
            ->dispatchResourcedEventedHandlers($resName, $eventName, $event);
108
        return $this;
109
    }
110
111
    /**
112
     * dispatch to all handlers the wildcard handlers
113
     *
114
     * @param EventInterface $event
115
     * @return void
116
     */
117
    protected function dispatchAllHandlers(
118
        EventInterface $event
119
    ): DispatcherInterface {
120
        if (isset($this->stack[self::ALL][self::ALL])) {
121
            foreach ($this->stack[self::ALL][self::ALL] as $listener) {
122
                $listener->publish($event);
123
            }
124
        }
125
        return $this;
126
    }
127
128
    /**
129
     * dispatch to handlers identified by resource name
130
     * despite the event
131
     *
132
     * @param string $resName
133
     * @param EventInterface $event
134
     * @return void
135
     */
136
    protected function dispatchResourcedHandlers(
137
        string $resName,
138
        EventInterface $event
139
    ): DispatcherInterface {
140
        if (isset($this->stack[$resName][self::ALL])) {
141
            foreach ($this->stack[$resName][self::ALL] as $listener) {
142
                $listener->publish($event);
143
            }
144
        }
145
        return $this;
146
    }
147
148
    /**
149
     * dispatch to handlers identified by resource name and event name
150
     *
151
     * @param string $resName
152
     * @param EventInterface $event
153
     * @return void
154
     */
155
    protected function dispatchResourcedEventedHandlers(
156
        string $resName,
157
        string $eventName,
158
        EventInterface $event
159
    ): DispatcherInterface {
160
        if (isset($this->stack[$resName][$eventName])) {
161
            foreach ($this->stack[$resName][$eventName] as $listener) {
162
                $listener->publish($event);
163
            }
164
        }
165
        return $this;
166
    }
167
168
    /**
169
     * return hash for a listener instance
170
     *
171
     * @param ListenerInterface $listener
172
     * @return string
173
     */
174
    protected function hash(ListenerInterface $listener): string
175
    {
176
        return spl_object_hash($listener);
177
    }
178
179
    /**
180
     * transform closure to listener
181
     *
182
     * @param Closure $closure
183
     * @return ListenerInterface
184
     */
185
    protected function closureToListener(Closure $closure): ListenerInterface
186
    {
187
        $listener = new class ($closure) implements ListenerInterface
188
        {
189
            /**
190
             * listener as closure
191
             *
192
             * @var Closure
193
             */
194
            protected $closure;
195
196
            /**
197
             * instanciate
198
             *
199
             * @param Closure $closure
200
             */
201
            public function __construct(Closure $closure)
202
            {
203
                if (func_num_args($closure) === 0) {
0 ignored issues
show
Unused Code introduced by
The call to func_num_args() has too many arguments starting with $closure. ( Ignorable by Annotation )

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

203
                if (/** @scrutinizer ignore-call */ func_num_args($closure) === 0) {

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
204
                    throw new Exception(
205
                        self::ERR_CLOSURE_ARG_MISSING
0 ignored issues
show
Bug introduced by
The constant anonymous//src/App/Compo...ERR_CLOSURE_ARG_MISSING was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
206
                    );
207
                }
208
                $this->closure = $closure;
209
            }
210
211
            /**
212
             * publish
213
             *
214
             * @param EventInterface $event
215
             * @return void
216
             */
217
            public function publish(EventInterface $event)
218
            {
219
                call_user_func($this->closure, $event);
220
            }
221
        };
222
        return $listener;
223
    }
224
}
225