Completed
Pull Request — master (#447)
by Alexandru
15:06 queued 01:45
created

PresenceChannel   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 7
lcom 1
cbo 3
dl 0
loc 131
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A subscribe() 0 32 1
A unsubscribe() 0 31 2
A getChannelData() 0 10 1
A getUserIds() 0 8 1
A getHash() 0 10 2
1
<?php
2
3
namespace BeyondCode\LaravelWebSockets\Channels;
4
5
use BeyondCode\LaravelWebSockets\Server\Exceptions\InvalidSignature;
6
use Ratchet\ConnectionInterface;
7
use stdClass;
8
9
class PresenceChannel extends PrivateChannel
10
{
11
    /**
12
     * Subscribe to the channel.
13
     *
14
     * @see    https://pusher.com/docs/pusher_protocol#presence-channel-events
15
     * @param  \Ratchet\ConnectionInterface  $connection
16
     * @param  \stdClass  $payload
17
     * @return void
18
     * @throws InvalidSignature
19
     */
20
    public function subscribe(ConnectionInterface $connection, stdClass $payload)
21
    {
22
        parent::subscribe($connection, $payload);
23
24
        $this->channelManager->userJoinedPresenceChannel(
0 ignored issues
show
Bug introduced by
The property channelManager does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
25
            $connection,
26
            $user = json_decode($payload->channel_data),
27
            $this->getName(),
28
            $payload
29
        );
30
31
        $this->channelManager
32
            ->getChannelMembers($connection->app->id, $this->getName())
0 ignored issues
show
Bug introduced by
Accessing app 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...
33
            ->then(function ($users) use ($connection) {
34
                $connection->send(json_encode([
35
                    'event' => 'pusher_internal:subscription_succeeded',
36
                    'channel' => $this->getName(),
37
                    'data' => json_encode($this->getChannelData($users)),
38
                ]));
39
            });
40
41
        $memberAddedPayload = [
42
            'event' => 'pusher_internal:member_added',
43
            'channel' => $this->getName(),
44
            'data' => $payload->channel_data,
45
        ];
46
47
        $this->broadcastToEveryoneExcept(
48
            (object) $memberAddedPayload, $connection->socketId,
0 ignored issues
show
Bug introduced by
Accessing socketId 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...
49
            $connection->app->id
0 ignored issues
show
Bug introduced by
Accessing app 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...
50
        );
51
    }
52
53
    /**
54
     * Unsubscribe connection from the channel.
55
     *
56
     * @param  \Ratchet\ConnectionInterface  $connection
57
     * @return void
58
     */
59
    public function unsubscribe(ConnectionInterface $connection)
60
    {
61
        parent::unsubscribe($connection);
62
63
        $this->channelManager
64
            ->getChannelMember($connection, $this->getName())
65
            ->then(function ($user) use ($connection) {
66
                $user = @json_decode($user);
67
68
                if (! $user) {
69
                    return;
70
                }
71
72
                $this->channelManager->userLeftPresenceChannel(
73
                    $connection, $user, $this->getName()
74
                );
75
76
                $memberRemovedPayload = [
77
                    'event' => 'pusher_internal:member_removed',
78
                    'channel' => $this->getName(),
79
                    'data' => json_encode([
80
                        'user_id' => $user->user_id,
81
                    ]),
82
                ];
83
84
                $this->broadcastToEveryoneExcept(
85
                    (object) $memberRemovedPayload, $connection->socketId,
0 ignored issues
show
Bug introduced by
Accessing socketId 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...
86
                    $connection->app->id
0 ignored issues
show
Bug introduced by
Accessing app 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...
87
                );
88
            });
89
    }
90
91
    /**
92
     * Get the Presence channel data.
93
     *
94
     * @param  array  $users
95
     * @return array
96
     */
97
    protected function getChannelData(array $users): array
98
    {
99
        return [
100
            'presence' => [
101
                'ids' => $this->getUserIds($users),
102
                'hash' => $this->getHash($users),
103
                'count' => count($users),
104
            ],
105
        ];
106
    }
107
108
    /**
109
     * Get the Presence Channel's users.
110
     *
111
     * @param  array  $users
112
     * @return array
113
     */
114
    protected function getUserIds(array $users): array
115
    {
116
        return collect($users)
117
            ->map(function ($user) {
118
                return (string) $user->user_id;
119
            })
120
            ->values();
121
    }
122
123
    /**
124
     * Compute the hash for the presence channel integrity.
125
     *
126
     * @param  array  $users
127
     * @return array
128
     */
129
    protected function getHash(array $users): array
130
    {
131
        $hash = [];
132
133
        foreach ($users as $socketId => $user) {
134
            $hash[$user->user_id] = $user->user_info ?? [];
135
        }
136
137
        return $hash;
138
    }
139
}
140