Completed
Push — master ( 9cb398...3fed9f )
by Alexey
105:26 queued 65:22
created

Broadcast.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace yiicod\socketio;
4
5
use Exception;
6
use Yii;
7
use yii\helpers\ArrayHelper;
8
use yii\helpers\HtmlPurifier;
9
use yii\helpers\Json;
10
use yiicod\base\helpers\LoggerMessage;
11
use yiicod\socketio\drivers\RedisDriver;
12
use yiicod\socketio\events\EventPolicyInterface;
13
use yiicod\socketio\events\EventPubInterface;
14
use yiicod\socketio\events\EventRoomInterface;
15
use yiicod\socketio\events\EventSubInterface;
16
17
/**
18
 * Class Broadcast
19
 *
20
 * @package yiicod\socketio
21
 */
22
class Broadcast
23
{
24
    protected static $channels = [];
25
26
    /**
27
     * @var string
28
     */
29
    public static $yiiAlias = '@app/..';
30
31
    /**
32
     * Subscribe to event from client
33
     *
34
     * @param string $event
35
     * @param array $data
36
     *
37
     * @throws Exception
38
     */
39
    public static function on(string $event, array $data)
40
    {
41
        // Clear data
42
        array_walk_recursive($data, function (&$item, $key) {
0 ignored issues
show
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...
43
            $item = HtmlPurifier::process($item);
44
        });
45
46
        Yii::info(Json::encode([
47
            'type' => 'on',
48
            'name' => $event,
49
            'data' => $data,
50
        ]), 'socket.io');
51
52
        $eventClassName = self::getManager()->getList()[$event] ?? null;
53
        if (null === $eventClassName) {
54
            Yii::error(LoggerMessage::trace("Can not find $event", Json::encode($data)));
55
        }
56
57
        (new Process(self::$yiiAlias))->run($eventClassName, $data);
58
    }
59
60
    /**
61
     * Handle process from client
62
     *
63
     * @param string $handler
64
     * @param array $data
65
     */
66
    public static function process(string $handler, array $data)
67
    {
68
        try {
69
            /** @var EventSubInterface|EventPolicyInterface $event */
70
            $event = new $handler($data);
71
72
            if (false === $event instanceof EventSubInterface) {
73
                throw new Exception('Event should implement EventSubInterface');
74
            }
75
76
            Yii::$app->db->close();
77
            Yii::$app->db->open();
78
79
            if (true === $event instanceof EventPolicyInterface && false === $event->can($data)) {
80
                return;
81
            }
82
83
            $event->handle($data);
84
        } catch (Exception $e) {
85
            Yii::error(LoggerMessage::log($e, Json::encode($data)));
86
        }
87
    }
88
89
    /**
90
     * Emit event to client
91
     *
92
     * @param string $event
93
     * @param array $data
94
     *
95
     * @throws Exception
96
     */
97
    public static function emit(string $event, array $data)
98
    {
99
        $eventClassName = self::getManager()->getList()[$event] ?? null;
100
        try {
101
            if (null === $eventClassName) {
102
                throw new Exception("Can not find $event");
103
            }
104
105
            /** @var EventPubInterface|EventRoomInterface $event */
106
            $event = new $eventClassName($data);
107
108
            if (false === $event instanceof EventPubInterface) {
109
                throw new Exception('Event should implement EventPubInterface');
110
            }
111
112
            $data = $event->fire($data);
113
114
            if (true === $event instanceof EventRoomInterface) {
115
                $data['room'] = $event->room();
116
            }
117
118
            Yii::info(Json::encode([
119
                'type' => 'emit',
120
                'name' => $event,
121
                'data' => $data,
122
            ]), 'socket.io');
123
            foreach ($eventClassName::broadcastOn() as $channel) {
124
                static::publish(static::channelName($channel), [
125
                    'name' => $eventClassName::name(),
126
                    'data' => $data,
127
                ]);
128
            }
129
        } catch (Exception $e) {
130
            Yii::error(LoggerMessage::log($e));
131
        }
132
    }
133
134
    /**
135
     * Prepare channel name
136
     *
137
     * @param $name
138
     *
139
     * @return string
140
     */
141
    public static function channelName($name)
142
    {
143
        return $name . self::getManager()->nsp;
144
    }
145
146
    /**
147
     * Publish data to redis channel
148
     *
149
     * @param string $channel
150
     * @param array $data
151
     */
152
    public static function publish(string $channel, array $data)
153
    {
154
        static::getDriver()->getConnection(true)->publish($channel, Json::encode($data));
155
    }
156
157
    /**
158
     * Redis channels names
159
     *
160
     * @return array
161
     */
162
    public static function channels(): array
163
    {
164
        if (empty(self::$channels)) {
165
            foreach (self::getManager()->getList() as $eventClassName) {
166
                self::$channels = ArrayHelper::merge(self::$channels, $eventClassName::broadcastOn());
167
            }
168
            self::$channels = array_unique(self::$channels);
169
170
            self::$channels = array_map(function ($channel) {
171
                return static::channelName($channel);
172
            }, self::$channels);
173
            //Yii::info(Json::encode(self::$channels));
174
        }
175
176
        return self::$channels;
177
    }
178
179
    /**
180
     * @return RedisDriver
181
     */
182
    public static function getDriver()
183
    {
184
        return Yii::$app->broadcastDriver;
185
    }
186
187
    /**
188
     * @return EventManager
189
     */
190
    public static function getManager()
191
    {
192
        return Yii::$app->broadcastEvents;
193
    }
194
}
195