Completed
Pull Request — master (#447)
by Alexandru
08:09
created

RedisPusherBroadcaster::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 4
1
<?php
2
3
namespace BeyondCode\LaravelWebSockets\PubSub\Broadcasters;
4
5
use Illuminate\Broadcasting\Broadcasters\Broadcaster;
6
use Illuminate\Broadcasting\Broadcasters\UsePusherChannelConventions;
7
use Illuminate\Contracts\Redis\Factory as Redis;
8
use Illuminate\Support\Arr;
9
use Illuminate\Support\Str;
10
use Pusher\Pusher;
11
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
12
13
class RedisPusherBroadcaster extends Broadcaster
14
{
15
    use UsePusherChannelConventions;
16
17
    /**
18
     * The Pusher SDK instance.
19
     *
20
     * @var \Pusher\Pusher
21
     */
22
    protected $pusher;
23
24
    /**
25
     * The Pusher app ID, to be passed in the payload.
26
     *
27
     * @var string
28
     */
29
    protected $appId;
30
31
    /**
32
     * The Redis instance.
33
     *
34
     * @var \Illuminate\Contracts\Redis\Factory
35
     */
36
    protected $redis;
37
38
    /**
39
     * The Redis connection to use for broadcasting.
40
     *
41
     * @var string|null
42
     */
43
    protected $connection;
44
45
    /**
46
     * Create a new broadcaster instance.
47
     *
48
     * @param  Pusher  $pusher
49
     * @param  mixed  $appId
50
     * @param  \Illuminate\Contracts\Redis\Factory  $redis
51
     * @param  string|null  $connection
52
     */
53
    public function __construct(Pusher $pusher, $appId, Redis $redis, $connection = null)
54
    {
55
        $this->pusher = $pusher;
56
        $this->appId = $appId;
57
        $this->redis = $redis;
58
        $this->connection = $connection;
59
    }
60
61
    /**
62
     * Authenticate the incoming request for a given channel.
63
     *
64
     * @param  \Illuminate\Http\Request  $request
65
     * @return mixed
66
     * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
67
     */
68
    public function auth($request)
69
    {
70
        $channelName = $this->normalizeChannelName($request->channel_name);
71
72
        if ($this->isGuardedChannel($request->channel_name) &&
73
            ! $this->retrieveUser($request, $channelName)) {
74
            throw new AccessDeniedHttpException;
75
        }
76
77
        return parent::verifyUserCanAccessChannel(
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (verifyUserCanAccessChannel() instead of auth()). Are you sure this is correct? If so, you might want to change this to $this->verifyUserCanAccessChannel().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
78
            $request, $channelName
79
        );
80
    }
81
82
    /**
83
     * Return the valid authentication response.
84
     *
85
     * @param  \Illuminate\Http\Request  $request
86
     * @param  mixed  $result
87
     * @return mixed
88
     * @throws \Pusher\PusherException
89
     */
90
    public function validAuthenticationResponse($request, $result)
91
    {
92
        if (Str::startsWith($request->channel_name, 'private')) {
93
            return $this->decodePusherResponse(
94
                $request, $this->pusher->socket_auth($request->channel_name, $request->socket_id)
95
            );
96
        }
97
98
        $channelName = $this->normalizeChannelName($request->channel_name);
99
100
        return $this->decodePusherResponse(
101
            $request,
102
            $this->pusher->presence_auth(
103
                $request->channel_name, $request->socket_id,
104
                $this->retrieveUser($request, $channelName)->getAuthIdentifier(), $result
105
            )
106
        );
107
    }
108
109
    /**
110
     * Decode the given Pusher response.
111
     *
112
     * @param  \Illuminate\Http\Request  $request
113
     * @param  mixed  $response
114
     * @return array
115
     */
116
    protected function decodePusherResponse($request, $response)
117
    {
118
        if (! $request->input('callback', false)) {
119
            return json_decode($response, true);
120
        }
121
122
        return response()->json(json_decode($response, true))
0 ignored issues
show
Bug introduced by
The method json does only exist in Illuminate\Contracts\Routing\ResponseFactory, but not in Illuminate\Http\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
123
            ->withCallback($request->callback);
124
    }
125
126
    /**
127
     * Broadcast the given event.
128
     *
129
     * @param  array  $channels
130
     * @param  string  $event
131
     * @param  array  $payload
132
     * @return void
133
     */
134
    public function broadcast(array $channels, $event, array $payload = [])
135
    {
136
        $connection = $this->redis->connection($this->connection);
137
138
        $payload = json_encode([
139
            'appId' => $this->appId,
140
            'event' => $event,
141
            'data' => $payload,
142
            'socket' => Arr::pull($payload, 'socket'),
143
        ]);
144
145
        foreach ($this->formatChannels($channels) as $channel) {
146
            $connection->publish("{$this->appId}:{$channel}", $payload);
147
        }
148
    }
149
}
150