Receiver::callRoute()   A
last analyzed

Complexity

Conditions 4
Paths 28

Size

Total Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 39
rs 9.296
c 0
b 0
f 0
cc 4
nc 28
nop 2
1
<?php
2
/** @noinspection PhpUndefinedFieldInspection */
3
4
/**
5
 * Created by PhpStorm.
6
 * User: shanmaseen
7
 * Date: 23/03/19
8
 * Time: 07:40 م
9
 */
10
11
namespace Shamaseen\Laravel\Ratchet;
12
13
use Illuminate\Validation\ValidationException;
14
use Shamaseen\Laravel\Ratchet\Exceptions\WebSocketException;
15
use Shamaseen\Laravel\Ratchet\Facades\WsRoute;
16
use Shamaseen\Laravel\Ratchet\Objects\Clients\Client;
17
use Ratchet\ConnectionInterface;
18
use Ratchet\MessageComponentInterface;
19
use Shamaseen\Laravel\Ratchet\Requests\WsRequest;
20
use Shamaseen\Laravel\Ratchet\Traits\WebSocketMessagesManager;
21
22
/**
23
 * Class WebSocket
24
 * @package App\WebSockets
25
 */
26
class Receiver implements MessageComponentInterface
27
{
28
    use WebSocketMessagesManager;
29
30
    /**
31
     * @var Client[]
32
     */
33
    public $clients;
34
    private $routes;
35
    public $userAuthSocketMapper;
36
    public $rooms = [];
37
38
    /**
39
     * WebSocket constructor.
40
     */
41
    public function __construct()
42
    {
43
        $this->clients = [];
44
        /**
45
         * The key will be auth id, the value will be resourceId
46
         */
47
        $this->userAuthSocketMapper = [];
48
49
        $this->mainRoutes();
50
        include base_path() . '/routes/websocket.php';
51
        $this->routes = WsRoute::getRoutes();
52
    }
53
54
    /**
55
     * @param ConnectionInterface $conn
56
     */
57
    public function onOpen(ConnectionInterface $conn)
58
    {
59
        $this->clients[$conn->resourceId] = new Client();
0 ignored issues
show
Bug introduced by
Accessing resourceId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
60
        $this->clients[$conn->resourceId]->conn = $conn;
0 ignored issues
show
Bug introduced by
Accessing resourceId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
61
    }
62
63
    /**
64
     * @param ConnectionInterface $from
65
     * @param string $msg
66
     * @throws \Exception
67
     */
68
    public function onMessage(ConnectionInterface $from, $msg)
69
    {
70
        $msg = json_decode($msg,true);
71
        $this->callRoute($from,$msg);
72
    }
73
74
    function callRoute(ConnectionInterface $from, $msg)
0 ignored issues
show
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for callRoute.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
75
    {
76
        try {
77
            $this->checkForRequiredInMessage($msg, $from);
78
79
            $this->resetSession($msg['session']);
80
81
            $this->resetAuth($msg,$from);
82
83
            $route = $this->routes[$msg['route']];
84
85
            $class = $route->controller;
86
            $method = $route->method;
87
            $controller = new $class;
88
89
            $this->cloneProperties($this, $controller);
90
91
            $controller->conn = $from;
92
            $controller->receiver = $this;
93
94
            $controller->request = new WsRequest($msg);
95
            $controller->route = $route;
96
97
            if (!method_exists($controller, $method)) {
98
                $this->error($msg, $from, 'Method '.$method.' doesnt\'t exist !');
99
            }
100
101
            $controller->$method();
102
103
            \Session::save();
104
        } catch (WebSocketException $exception) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
105
106
        } catch (ValidationException $exception) {
107
            $this->sendToWebSocketUser($from, [
108
                'message' => $exception->getMessage(),
109
                'errors' => $exception->errors()
110
            ]);
111
        }
112
    }
113
114
    /**
115
     * @param ConnectionInterface $conn
116
     */
117
    public function onClose(ConnectionInterface $conn)
118
    {
119
        // The connection is closed, remove it, as we can no longer send it messages
120
        $client = $this->clients[$conn->resourceId];
0 ignored issues
show
Bug introduced by
Accessing resourceId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
121
        $routesToCall = $client->onCloseRoutes;
122
        foreach ($routesToCall as $route)
123
        {
124
            $msg = ['session'=>$client->session,'route'=>$route];
125
            $this->callRoute($conn,$msg);
126
        }
127
128
        unset($this->clients[$conn->resourceId]);
129
        unset($this->userAuthSocketMapper[array_search($conn->resourceId,$this->userAuthSocketMapper)]);
130
131
        echo "Connection {$conn->resourceId} has disconnected\n";
0 ignored issues
show
Bug introduced by
Accessing resourceId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
132
    }
133
134
    /**
135
     * @param ConnectionInterface $conn
136
     * @param \Exception $exception
137
     * @return null
138
     */
139
    public function onError(ConnectionInterface $conn, \Exception $exception)
140
    {
141
        echo "An error has occurred: {$exception->getMessage()}\n";
142
        echo "In {$exception->getFile()} line {$exception->getLine()}\n";
143
        echo $exception->getTraceAsString();
144
145
        $conn->close();
146
        return null;
147
    }
148
149
    /**
150
     * @param $msg
151
     * @param ConnectionInterface $from
152
     * @throws WebSocketException
153
     */
154
    function checkForRequiredInMessage($msg, $from)
0 ignored issues
show
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for checkForRequiredInMessage.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
155
    {
156
        if (!isset($msg['route']) || !isset($msg['session'])) {
157
            $this->error($msg, $from, 'Either the route is missing in the Request, Or you forget to add the session id ! please refer to the document in github for more details');
158
        }
159
160
        if (!isset($this->routes[$msg['route']])) {
161
            $this->error($msg, $from, 'No such route !');
162
        }
163
    }
164
165
    /**
166
     * @param Receiver $clonedObject
167
     * @param $clone
168
     */
169
    function cloneProperties($clonedObject, $clone)
0 ignored issues
show
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for cloneProperties.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
170
    {
171
        foreach (get_object_vars($clonedObject) as $key => $value) {
172
            $clone->$key = $value;
173
        }
174
    }
175
176
    function mainRoutes()
0 ignored issues
show
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for mainRoutes.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
177
    {
178
        WsRoute::make('initializeWebsocket', 'Shamaseen\Laravel\Ratchet\Controllers\InitializeController', 'index');
179
        WsRoute::make('room-enter', 'Shamaseen\Laravel\Ratchet\Controllers\RoomController', 'enterRoom');
180
        WsRoute::make('room-exit', 'Shamaseen\Laravel\Ratchet\Controllers\RoomController', 'exitRoom');
181
        WsRoute::make('send-to-user', 'Shamaseen\Laravel\Ratchet\Controllers\ChatController', 'sendMessageToUser');
182
        WsRoute::make('send-to-room', 'Shamaseen\Laravel\Ratchet\Controllers\ChatController', 'sendMessageToRoom');
183
    }
184
185
    /**
186
     * Read the session data from the handler.
187
     *
188
     * @param $session_id
189
     * @return array
190
     */
191
    protected function readFromHandler($session_id)
192
    {
193
        if ($data = \Session::getHandler()->read($session_id)) {
194
            $data = @unserialize($data);
195
196
            if ($data !== false && ! is_null($data) && is_array($data)) {
197
                return $data;
198
            }
199
        }
200
201
        return [];
202
    }
203
204
    function getUserId($session_array)
0 ignored issues
show
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for getUserId.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
205
    {
206
        return $session_array['login_web_59ba36addc2b2f9401580f014c7f58ea4e30989d'];
207
    }
208
209
    function getUserModel()
0 ignored issues
show
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for getUserModel.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
210
    {
211
        return \Config::get('laravel-ratchet.userModelNamespace','App\Entities\Users\User');
212
    }
213
214
    function resetSession($session_id)
0 ignored issues
show
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for resetSession.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
215
    {
216
        \Session::flush();
217
218
        \Session::setId($session_id);
219
220
        \Session::start();
221
    }
222
223
    /**
224
     * @param object $msg
225
     * @param ConnectionInterface $from
226
     * @throws WebSocketException
227
     */
228
    function resetAuth($msg,$from)
0 ignored issues
show
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for resetAuth.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
Coding Style introduced by
Expected 1 space between comma and argument "$from"; 0 found
Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
229
    {
230
        $data = $this->readFromHandler($msg['session']);
231
232
        if(!empty($data))
0 ignored issues
show
Coding Style introduced by
Expected 1 space(s) after IF keyword; 0 found
Loading history...
233
        {
234
            $user_id = $this->getUserId($data);
235
            $user = $this->getUserModel()::find($user_id);
236
            if(!$user)
0 ignored issues
show
Coding Style introduced by
Expected 1 space(s) after IF keyword; 0 found
Loading history...
237
            {
238
                $this->error($msg, $from, 'There is no such user.');
239
            }
240
            \Auth::setUser($user);
241
242
            $this->clients[$from->resourceId]->id = \Auth::id();
0 ignored issues
show
Bug introduced by
Accessing resourceId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
243
            $this->clients[$from->resourceId]->session = $msg['session'];
0 ignored issues
show
Bug introduced by
Accessing resourceId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
244
            $this->userAuthSocketMapper[\Auth::id()] = $from->resourceId;
0 ignored issues
show
Bug introduced by
Accessing resourceId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
245
        }
246
        else
0 ignored issues
show
Coding Style introduced by
Expected 1 space(s) after ELSE keyword; newline found
Loading history...
247
        {
248
            $this->error($msg, $from, 'Unauthenticated.');
249
        }
250
    }
251
}
252