Completed
Pull Request — master (#18)
by
unknown
39:59
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
     * Subscribe to event from client
28
     *
29
     * @param string $event
30
     * @param array $data
31
     *
32
     * @throws Exception
33
     */
34
    public static function on(string $event, array $data)
35
    {
36
        // Clear data
37
        array_walk_recursive($data, function (&$item, $key) {
38
            $item = HtmlPurifier::process($item);
39
        });
40
41
        Yii::info(Json::encode([
42
            'type' => 'on',
43
            'name' => $event,
44
            'data' => $data,
45
        ]), 'socket.io');
46
47
        $eventClassName = self::getManager()->getList()[$event] ?? null;
48
        if (null === $eventClassName) {
49
            Yii::error(LoggerMessage::trace("Can not find $event", Json::encode($data)));
0 ignored issues
show
\yii\helpers\Json::encode($data) is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
50
        }
51
52
        Yii::$container->get(Process::class)->run($eventClassName, $data);
53
    }
54
55
    /**
56
     * Handle process from client
57
     *
58
     * @param string $handler
59
     * @param array $data
60
     */
61
    public static function process(string $handler, array $data)
62
    {
63
        try {
64
            /** @var EventSubInterface|EventPolicyInterface $event */
65
            $event = new $handler($data);
66
67
            if (false === $event instanceof EventSubInterface) {
68
                throw new Exception('Event should implement EventSubInterface');
69
            }
70
71
            Yii::$app->db->close();
72
            Yii::$app->db->open();
73
74
            if (true === $event instanceof EventPolicyInterface && false === $event->can($data)) {
75
                return;
76
            }
77
78
            $event->handle($data);
79
        } catch (Exception $e) {
80
            Yii::error(LoggerMessage::log($e, Json::encode($data)));
81
        }
82
    }
83
84
    /**
85
     * Emit event to client
86
     *
87
     * @param string $event
88
     * @param array $data
89
     *
90
     * @throws Exception
91
     */
92
    public static function emit(string $event, array $data)
93
    {
94
        $eventClassName = self::getManager()->getList()[$event] ?? null;
95
        try {
96
            if (null === $eventClassName) {
97
                throw new Exception("Can not find $event");
98
            }
99
100
            /** @var EventPubInterface|EventRoomInterface $event */
101
            $event = new $eventClassName($data);
102
103
            if (false === $event instanceof EventPubInterface) {
104
                throw new Exception('Event should implement EventPubInterface');
105
            }
106
107
            $data = $event->fire($data);
108
109
            if (true === $event instanceof EventRoomInterface) {
110
                $data['room'] = $event->room();
111
            }
112
113
            Yii::info(Json::encode([
114
                'type' => 'emit',
115
                'name' => $event,
116
                'data' => $data,
117
            ]), 'socket.io');
118
            foreach ($eventClassName::broadcastOn() as $channel) {
119
                static::publish(static::channelName($channel), [
120
                    'name' => $eventClassName::name(),
121
                    'data' => $data,
122
                ]);
123
            }
124
        } catch (Exception $e) {
125
            Yii::error(LoggerMessage::log($e));
126
        }
127
    }
128
129
    /**
130
     * Prepare channel name
131
     *
132
     * @param $name
133
     *
134
     * @return string
135
     */
136
    public static function channelName($name)
137
    {
138
        return $name . self::getManager()->nsp;
139
    }
140
141
    /**
142
     * Publish data to redis channel
143
     *
144
     * @param string $channel
145
     * @param array $data
146
     */
147
    public static function publish(string $channel, array $data)
148
    {
149
        static::getDriver()->getConnection(true)->publish($channel, Json::encode($data));
150
    }
151
152
    /**
153
     * Redis channels names
154
     *
155
     * @return array
156
     */
157
    public static function channels(): array
158
    {
159
        if (empty(self::$channels)) {
160
            foreach (self::getManager()->getList() as $eventClassName) {
161
                self::$channels = ArrayHelper::merge(self::$channels, $eventClassName::broadcastOn());
162
            }
163
            self::$channels = array_unique(self::$channels);
164
165
            self::$channels = array_map(function ($channel) {
166
                return static::channelName($channel);
167
            }, self::$channels);
168
            //Yii::info(Json::encode(self::$channels));
169
        }
170
171
        return self::$channels;
172
    }
173
174
    /**
175
     * @return RedisDriver
176
     */
177
    public static function getDriver()
178
    {
179
        return Yii::$app->broadcastDriver;
180
    }
181
182
    /**
183
     * @return EventManager
184
     */
185
    public static function getManager()
186
    {
187
        return Yii::$app->broadcastEvents;
188
    }
189
}
190