Completed
Push — master ( 51c7de...741841 )
by Alexey
37:01
created

Broadcast   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 174
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 6

Importance

Changes 0
Metric Value
wmc 21
lcom 2
cbo 6
dl 0
loc 174
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A on() 0 11 1
B process() 0 33 7
B emit() 0 35 6
A publish() 0 4 1
A channelName() 0 4 1
A channels() 0 14 3
A setEntityManager() 0 4 1
1
<?php
2
3
namespace SfCod\SocketIoBundle\Service;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use Exception;
7
use HTMLPurifier;
8
use Psr\Log\LoggerInterface;
9
use SfCod\SocketIoBundle\Events\EventInterface;
10
use SfCod\SocketIoBundle\events\EventPolicyInterface;
11
use SfCod\SocketIoBundle\Events\EventPublisherInterface;
12
use SfCod\SocketIoBundle\events\EventRoomInterface;
13
use SfCod\SocketIoBundle\Events\EventSubscriberInterface;
14
15
/**
16
 * Class Broadcast.
17
 *
18
 * @package SfCod\SocketIoBundle
19
 */
20
class Broadcast
21
{
22
    /**
23
     * @var array
24
     */
25
    protected static $channels = [];
26
    /**
27
     * @var RedisDriver
28
     */
29
    protected $redis;
30
    /**
31
     * @var LoggerInterface
32
     */
33
    protected $logger;
34
    /**
35
     * @var EventManager
36
     */
37
    protected $manager;
38
    /**
39
     * @var Process
40
     */
41
    protected $process;
42
    /**
43
     * @var EntityManagerInterface
44
     */
45
    protected $entityManager;
46
47
    /**
48
     * Broadcast constructor.
49
     */
50
    public function __construct(RedisDriver $redis, EventManager $manager, LoggerInterface $logger, Process $process)
51
    {
52
        $this->redis = $redis;
53
        $this->logger = $logger;
54
        $this->manager = $manager;
55
        $this->process = $process;
56
    }
57
58
    /**
59
     * Subscribe to event from client.
60
     *
61
     * @return \Symfony\Component\Process\Process
62
     *
63
     * @throws Exception
64
     */
65
    public function on(string $event, array $data)
66
    {
67
        // Clear data
68
        array_walk_recursive($data, function (&$item, $key) {
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
69
            $item = (new HtmlPurifier())->purify($item);
70
        });
71
72
        $this->logger->info(json_encode(['type' => 'on', 'name' => $event, 'data' => $data]));
73
74
        return $this->process->run($event, $data);
75
    }
76
77
    /**
78
     * Run process.
79
     */
80
    public function process(string $handler, array $data)
81
    {
82
        try {
83
            /** @var EventInterface|EventSubscriberInterface|EventPolicyInterface $eventHandler */
84
            $eventHandler = $this->manager->resolve($handler); //container->get(sprintf('socketio.%s', $handler));
85
86
            if (false === $eventHandler instanceof EventInterface) {
87
                throw new Exception('Event should implement EventInterface');
88
            }
89
90
            $eventHandler->setPayload($data);
91
92
            if (false === $eventHandler instanceof EventSubscriberInterface) {
93
                throw new Exception('Event should implement EventSubscriberInterface');
94
            }
95
96
            if (true === $eventHandler instanceof EventPolicyInterface && false === $eventHandler->can($data)) {
97
                return;
98
            }
99
100
            if ($this->entityManager) {
101
                $connection = $this->entityManager->getConnection();
102
                $connection->close();
103
                $connection->connect();
104
            }
105
106
            $this->logger->info(json_encode(['type' => 'process', 'name' => $handler, 'data' => $data]));
107
108
            $eventHandler->handle();
109
        } catch (Exception $e) {
110
            $this->logger->error($e);
111
        }
112
    }
113
114
    /**
115
     * Emit event to client.
116
     *
117
     * @throws Exception
118
     */
119
    public function emit(string $event, array $data)
120
    {
121
        $this->logger->info(json_encode(['type' => 'emit', 'name' => $event, 'data' => $data]));
122
123
        try {
124
            /** @var EventInterface|EventPublisherInterface|EventRoomInterface $eventHandler */
125
            $eventHandler = $this->manager->resolve($event); // container->get(sprintf('socketio.%s', $event));
126
127
            if (false === $eventHandler instanceof EventInterface) {
128
                throw new Exception('Event should implement EventInterface');
129
            }
130
131
            $eventHandler->setPayload($data);
132
133
            if (false === $eventHandler instanceof EventPublisherInterface) {
134
                throw new Exception('Event should implement EventPublisherInterface');
135
            }
136
137
            $data = $eventHandler->fire();
138
139
            if ($eventHandler instanceof EventRoomInterface) {
140
                $data['room'] = $eventHandler->room();
141
            }
142
143
            $eventHandlerClass = get_class($eventHandler);
144
            foreach ($eventHandlerClass::broadcastOn() as $channel) {
145
                $this->publish($this->channelName($channel), [
146
                    'name' => $eventHandlerClass::name(),
147
                    'data' => $data,
148
                ]);
149
            }
150
        } catch (Exception $e) {
151
            $this->logger->error($e);
152
        }
153
    }
154
155
    /**
156
     * Publish data to redis channel.
157
     */
158
    protected function publish(string $channel, array $data)
159
    {
160
        $this->redis->getClient(true)->publish($channel, json_encode($data));
161
    }
162
163
    /**
164
     * Prepare channel name.
165
     */
166
    protected function channelName(string $name): string
167
    {
168
        return $name . getenv('SOCKET_IO_NSP');
169
    }
170
171
    /**
172
     * Redis channels names.
173
     */
174
    public function channels(): array
175
    {
176
        if (empty(self::$channels)) {
177
            foreach ($this->manager->getList() as $eventHandlerClass) {
178
                self::$channels = array_merge(self::$channels, $eventHandlerClass::broadcastOn());
179
            }
180
            self::$channels = array_unique(self::$channels);
181
            self::$channels = array_map(function ($channel) {
182
                return $this->channelName($channel);
183
            }, self::$channels);
184
        }
185
186
        return self::$channels;
187
    }
188
189
    public function setEntityManager(EntityManagerInterface $entityManager)
190
    {
191
        $this->entityManager = $entityManager;
192
    }
193
}
194