Passed
Push — master ( eb9c5f...4cd870 )
by Mohammad
04:38
created

Receiver::getUserModel()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
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 App\Entities\User\User;
14
use Illuminate\Validation\ValidationException;
15
use Shamaseen\Laravel\Ratchet\Exceptions\WebSocketException;
16
use Shamaseen\Laravel\Ratchet\Facades\WsRoute;
17
use Shamaseen\Laravel\Ratchet\Objects\Clients\Client;
18
use Ratchet\ConnectionInterface;
19
use Ratchet\MessageComponentInterface;
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
        try {
71
            $msg = json_decode($msg);
72
73
            $this->checkForRequiredInMessage($msg, $from);
74
75
            $this->resetSession($msg->session);
76
77
            $this->resetAuth($msg,$from);
78
79
            $route = $this->routes[$msg->route];
80
81
            $class = $route->controller;
82
            $method = $route->method;
83
            $controller = new $class;
84
85
            $this->cloneProperties($this, $controller);
86
87
            $controller->conn = $from;
88
            $controller->receiver = $this;
89
            $controller->request = $msg;
90
            $controller->route = $route;
91
92
            if (!method_exists($controller, $method)) {
93
                $this->error($msg, $from, 'Method doesnt\'t exist !');
94
            }
95
96
            $controller->$method();
97
98
            \Session::save();
99
        } catch (WebSocketException $exception) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
100
101
        } catch (ValidationException $exception) {
102
            $this->sendToWebSocketUser($from, [
103
                'message' => $exception->getMessage(),
104
                'errors' => $exception->errors()
105
            ]);
106
        }
107
    }
108
109
    /**
110
     * @param ConnectionInterface $conn
111
     */
112
    public function onClose(ConnectionInterface $conn)
113
    {
114
        // The connection is closed, remove it, as we can no longer send it messages
115
        unset($this->clients[$conn->resourceId]);
116
117
        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...
118
    }
119
120
    /**
121
     * @param ConnectionInterface $conn
122
     * @param \Exception $exception
123
     */
124
    public function onError(ConnectionInterface $conn, \Exception $exception)
125
    {
126
        echo "An error has occurred: {$exception->getMessage()}\n";
127
        echo "In {$exception->getFile()} line {$exception->getLine()}\n";
128
129
        $conn->close();
130
        echo 'end';
131
        die;
0 ignored issues
show
Coding Style Compatibility introduced by
The method onError() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
132
    }
133
134
    /**
135
     * @param $msg
136
     * @param ConnectionInterface $from
137
     * @throws WebSocketException
138
     */
139
    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...
140
    {
141
        if (!isset($msg->route) || !isset($msg->session)) {
142
            $this->error($msg, $from, 'You can\'t send a request without route !');
143
        }
144
145
        if (!isset($this->routes[$msg->route])) {
146
            $this->error($msg, $from, 'No such route !');
147
        }
148
    }
149
150
    /**
151
     * @param Receiver $clonedObject
152
     * @param $clone
153
     */
154
    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...
155
    {
156
        foreach (get_object_vars($clonedObject) as $key => $value) {
157
            $clone->$key = $value;
158
        }
159
    }
160
161
    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...
162
    {
163
        WsRoute::make('initializeWebsocket', 'Shamaseen\Laravel\Ratchet\Controllers\InitializeController', 'index');
164
        WsRoute::make('room-enter', 'Shamaseen\Laravel\Ratchet\Controllers\RoomController', 'enterRoom');
165
        WsRoute::make('room-exit', 'Shamaseen\Laravel\Ratchet\Controllers\RoomController', 'exitRoom');
166
        WsRoute::make('send-to-user', 'Shamaseen\Laravel\Ratchet\Controllers\ChatController', 'sendMessageToUser');
167
        WsRoute::make('send-to-room', 'Shamaseen\Laravel\Ratchet\Controllers\ChatController', 'sendMessageToRoom');
168
    }
169
170
    /**
171
     * Read the session data from the handler.
172
     *
173
     * @param $session_id
174
     * @return array
175
     */
176
    protected function readFromHandler($session_id)
0 ignored issues
show
Coding Style Naming introduced by
The variable $session_id is not named in camelCase.

This check marks variable names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
177
    {
178
        if ($data = \Session::getHandler()->read($session_id)) {
179
            $data = @unserialize($data);
180
181
            if ($data !== false && ! is_null($data) && is_array($data)) {
182
                return $data;
183
            }
184
        }
185
186
        return [];
187
    }
188
189
    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...
Coding Style Naming introduced by
The variable $session_array is not named in camelCase.

This check marks variable names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
190
    {
191
        return $session_array['login_web_59ba36addc2b2f9401580f014c7f58ea4e30989d'];
192
    }
193
194
    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...
195
    {
196
        return User::class;
197
    }
198
199
    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...
Coding Style Naming introduced by
The variable $session_id is not named in camelCase.

This check marks variable names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
200
    {
201
        \Session::flush();
202
203
        \Session::setId($session_id);
204
205
        \Session::start();
206
    }
207
208
    /**
209
     * @param object $msg
210
     * @param ConnectionInterface $from
211
     * @throws WebSocketException
212
     */
213
    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...
Coding Style Naming introduced by
The variable $user_id is not named in camelCase.

This check marks variable names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style Naming introduced by
The variable $user_model is not named in camelCase.

This check marks variable names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
214
    {
215
        $data = $this->readFromHandler($msg->session);
216
217
        if(!empty($data))
0 ignored issues
show
Coding Style introduced by
Expected 1 space(s) after IF keyword; 0 found
Loading history...
218
        {
219
            $user_id = $this->getUserId($data);
220
            /** @var User $user_model */
221
            $user_model = $this->getUserModel();
222
            $user = $user_model::find($user_id);
223
            if(!$user)
0 ignored issues
show
Coding Style introduced by
Expected 1 space(s) after IF keyword; 0 found
Loading history...
224
            {
225
                $this->error($msg, $from, 'There is no such user.');
226
            }
227
            \Auth::setUser($user);
228
229
            $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...
230
            $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...
231
        }
232
        else
0 ignored issues
show
Coding Style introduced by
Expected 1 space(s) after ELSE keyword; newline found
Loading history...
233
        {
234
            $this->error($msg, $from, 'Unauthenticated.');
235
        }
236
    }
237
}