PacketHandler::doDispatch()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 9.4285
cc 3
eloc 5
nc 3
nop 2
crap 3
1
<?php
2
3
namespace Thruster\Component\PacketHandler;
4
5
use Thruster\Component\PacketHandler\Exception\ProviderNotFoundException;
6
7
/**
8
 * Class PacketHandler
9
 *
10
 * @package Thruster\Component\PacketHandler
11
 * @author  Aurimas Niekis <[email protected]>
12
 */
13
class PacketHandler
14
{
15
    /**
16
     * @var StreamHandler[]
17
     */
18
    private $providers;
19
20
    /**
21
     * @var array
22
     */
23
    private $handlers;
24
25
    /**
26
     * @var array
27
     */
28
    private $sortedHandlers;
29
30 12
    public function __construct()
31
    {
32 12
        $this->providers      = [];
33 12
        $this->handlers       = [];
34 12
        $this->sortedHandlers = [];
35 12
    }
36
37
    /**
38
     * @param StreamHandler $streamHandler
39
     * @param string $identifier
40
     *
41
     * @return PacketHandler
42
     */
43 6
    public function addProvider(StreamHandler $streamHandler, $identifier = null) : self
44
    {
45 6
        if (null === $identifier) {
46 4
            $this->providers[] = $streamHandler;
47
        } else {
48 2
            $this->providers[$identifier] = $streamHandler;
49
        }
50
51 6
        $streamHandler->on('package', function ($package) use ($streamHandler) {
52
            $this->onPackage($package, $streamHandler);
53 6
        });
54
55 6
        return $this;
56
    }
57
58 3
    public function removeProvider(StreamHandler $streamHandler = null, $identifier = null)
59
    {
60 3
        if (null === $streamHandler && null === $identifier) {
61 1
            return;
62
        }
63
64 2
        if (null === $identifier) {
65 1
            if (false !== ($key = array_search($streamHandler, $this->providers, true))) {
66 1
                unset($this->providers[$key]);
67
            }
68
        } else {
69 1
            if (false !== isset($this->providers[$identifier])) {
70 1
                unset($this->providers[$identifier]);
71
            }
72
        }
73 2
    }
74
75 4
    public function hasProvider($identifier) : bool
76
    {
77 4
        return isset($this->providers[$identifier]);
78
    }
79
80 4
    public function getProvider($identifier) : StreamHandler
81
    {
82 4
        if (false === $this->hasProvider($identifier)) {
83 1
            throw new ProviderNotFoundException($identifier);
84
        }
85
86 3
        return $this->providers[$identifier];
87
    }
88
89
    /**
90
     * @return StreamHandler[]
91
     */
92 5
    public function getProviders() : array
93
    {
94 5
        return $this->providers;
95
    }
96
97
    /**
98
     * @param PacketInterface $packet
99
     *
100
     * @return $this
101
     */
102 1
    public function dispatch(PacketInterface $packet)
103
    {
104 1
        foreach ($this->providers as $provider) {
105 1
            $provider->send($packet);
106
        }
107
108 1
        return $this;
109
    }
110
111
    /**
112
     * @param Package $package
113
     */
114 3
    public function onPackage(Package $package, StreamHandler $streamHandler)
115
    {
116
        /** @var PacketInterface $packet */
117 3
        $data = $package->getData();
118 3
        $packet = array_shift($data);
119
120 3
        if (false === ($packet instanceof PacketInterface)) {
121 1
            return;
122
        }
123
124 2
        $packet->setStream($package->getStream());
125 2
        $packet->setStreamHandler($streamHandler);
126
127 2
        $packetType = $packet->getName();
128
129 2
        if (false === isset($this->handlers[$packetType])) {
130 1
            return;
131
        }
132
133 1
        $this->doDispatch($this->getHandlers($packetType), $packet);
134 1
    }
135
136
    /**
137
     * @param string $packetType
138
     * @param bool   $withPriorities
139
     *
140
     * @return array
141
     */
142 3
    public function getHandlers(string $packetType = null, bool $withPriorities = false) : array
143
    {
144 3
        if (true === $withPriorities) {
145 2
            return $packetType ? $this->handlers[$packetType] : array_filter($this->handlers);
146
        }
147
148 3
        if (null !== $packetType) {
149 1
            if (!isset($this->sortedHandlers[$packetType])) {
150 1
                $this->sortHandlers($packetType);
151
            }
152
153 1
            return $this->sortedHandlers[$packetType];
154
        }
155
156 2
        foreach ($this->handlers as $packetType => $packetHandlers) {
157 2
            if (false === isset($this->sortedHandlers[$packetType])) {
158 2
                $this->sortHandlers($packetType);
159
            }
160
        }
161
162 2
        return array_filter($this->sortedHandlers);
163
    }
164
165
    /**
166
     * @param string $packetType
167
     *
168
     * @return bool
169
     */
170 2
    public function hasHandlers(string $packetType = null) : bool
171
    {
172 2
        return (bool) count($this->getHandlers($packetType));
173
    }
174
175
    /**
176
     * @param string   $packetType
177
     * @param callable $handler
178
     * @param int      $priority
179
     *
180
     * @return $this
181
     */
182 3
    public function addHandler(string $packetType, callable $handler, int $priority = 0) : self
183
    {
184 3
        $this->handlers[$packetType][$priority][] = $handler;
185
186 3
        unset($this->sortedHandlers[$packetType]);
187
188 3
        return $this;
189
    }
190
191
    /**
192
     * @param string   $packetType
193
     * @param callable $handler
194
     *
195
     * @return $this
196
     */
197 2
    public function removeHandler(string $packetType, callable $handler) : self
198
    {
199 2
        if (false === isset($this->handlers[$packetType])) {
200 1
            return $this;
201
        }
202
203 2
        foreach ($this->handlers[$packetType] as $priority => $handlers) {
204 2
            if (false !== ($key = array_search($handler, $handlers, true))) {
205 2
                unset($this->handlers[$packetType][$priority][$key], $this->sortedHandlers[$packetType]);
206
            }
207
208 2
            if (count($this->handlers[$packetType][$priority]) < 1) {
209 2
                unset($this->handlers[$packetType][$priority]);
210
            }
211
        }
212
213 2
        if (count($this->handlers[$packetType]) < 1) {
214 2
            unset($this->handlers[$packetType]);
215
        }
216
217 2
        return $this;
218
    }
219
220
    /**
221
     * @param PacketSubscriberInterface $subscriber
222
     *
223
     * @return $this
224
     */
225 1
    public function addSubscriber(PacketSubscriberInterface $subscriber) : self
226
    {
227 1
        foreach ($subscriber->getSubscribedPackets() as $packetType => $params) {
228 1
            if (is_string($params)) {
229 1
                $this->addHandler($packetType, [$subscriber, $params]);
230 1
            } elseif (is_string($params[0])) {
231 1
                $this->addHandler($packetType, [$subscriber, $params[0]], $params[1] ?? 0);
232
            } else {
233 1
                foreach ($params as $handler) {
234 1
                    $this->addHandler($packetType, [$subscriber, $handler[0]], $handler[1] ?? 0);
235
                }
236
            }
237
        }
238
239 1
        return $this;
240
    }
241
242
243
    /**
244
     * @param PacketSubscriberInterface $subscriber
245
     *
246
     * @return $this
247
     */
248 1
    public function removeSubscriber(PacketSubscriberInterface $subscriber)
249
    {
250 1
        foreach ($subscriber->getSubscribedPackets() as $packetType => $params) {
251 1
            if (is_array($params) && is_array($params[0])) {
252 1
                foreach ($params as $handler) {
253 1
                    $this->removeHandler($packetType, [$subscriber, $handler[0]]);
254
                }
255
            } else {
256 1
                $this->removeHandler($packetType, [$subscriber, is_string($params) ? $params : $params[0]]);
257
            }
258
        }
259 1
        return $this;
260
    }
261
262
    /**
263
     * @param array           $handlers
264
     * @param PacketInterface $packet
265
     */
266 1
    private function doDispatch($handlers, PacketInterface $packet)
267
    {
268 1
        foreach ($handlers as $handler) {
269 1
            call_user_func($handler, $packet, $this);
270
271 1
            if ($packet->isPropagationStopped()) {
272 1
                break;
273
            }
274
        }
275 1
    }
276
277
    /**
278
     * @param string $packetType
279
     */
280 3
    private function sortHandlers(string $packetType)
281
    {
282 3
        $this->sortedHandlers[$packetType] = [];
283
284 3
        if (isset($this->handlers[$packetType])) {
285 3
            krsort($this->handlers[$packetType]);
286 3
            $this->sortedHandlers[$packetType] = call_user_func_array('array_merge', $this->handlers[$packetType]);
287
        }
288 3
    }
289
}
290