Completed
Pull Request — master (#75)
by
unknown
01:12
created

FcmChannel::getToken()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.7333
c 0
b 0
f 0
cc 4
nc 4
nop 1
1
<?php
2
3
namespace NotificationChannels\Fcm;
4
5
use Illuminate\Contracts\Container\BindingResolutionException;
6
use Illuminate\Contracts\Events\Dispatcher;
7
use Illuminate\Notifications\Events\NotificationFailed;
8
use Illuminate\Notifications\Notification;
9
use Kreait\Firebase\Exception\MessagingException;
10
use Kreait\Firebase\Messaging\CloudMessage;
11
use Kreait\Firebase\Messaging\Message;
12
use NotificationChannels\Fcm\Exceptions\CouldNotSendNotification;
13
use Throwable;
14
15
class FcmChannel
16
{
17
    const MAX_TOKEN_PER_REQUEST = 500;
18
19
    /**
20
     * @var \Illuminate\Contracts\Events\Dispatcher
21
     */
22
    protected $events;
23
24
    /**
25
     * FcmChannel constructor.
26
     *
27
     * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher
28
     */
29
    public function __construct(Dispatcher $dispatcher)
30
    {
31
        $this->events = $dispatcher;
32
    }
33
34
    /**
35
     * @var string|null
36
     */
37
    protected $fcmProject = null;
38
39
    /**
40
     * Send the given notification.
41
     *
42
     * @param mixed $notifiable
43
     * @param \Illuminate\Notifications\Notification $notification
44
     *
45
     * @return array
46
     * @throws \NotificationChannels\Fcm\Exceptions\CouldNotSendNotification
47
     * @throws \Kreait\Firebase\Exception\FirebaseException
48
     */
49
    public function send($notifiable, Notification $notification)
50
    {
51
        $token = $this->getToken($notifiable);
52
53
        // Get the message from the notification class
54
        $fcmMessage = $notification->toFcm($notifiable);
0 ignored issues
show
Bug introduced by
The method toFcm() does not seem to exist on object<Illuminate\Notifications\Notification>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
55
56
        if (! $fcmMessage instanceof Message) {
57
            throw CouldNotSendNotification::invalidMessage();
58
        }
59
60
        $this->fcmProject = null;
61
        if (method_exists($notification, 'fcmProject')) {
62
            $this->fcmProject = $notification->fcmProject($notifiable, $fcmMessage);
0 ignored issues
show
Bug introduced by
The method fcmProject() does not seem to exist on object<Illuminate\Notifications\Notification>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
63
        }
64
65
        $responses = [];
66
67
        try {
68
            if (is_array($token)) {
69
                // Use multicast when there are multiple recipients
70
                $partialTokens = array_chunk($token, self::MAX_TOKEN_PER_REQUEST, false);
71
                foreach ($partialTokens as $tokens) {
72
                    $responses[] = $this->sendToFcmMulticast($fcmMessage, $tokens);
73
                }
74
            } else {
75
                $responses[] = $this->sendToFcm($fcmMessage, $token);
76
            }
77
        } catch (MessagingException $exception) {
78
            $this->failedNotification($notifiable, $notification, $exception);
79
            throw CouldNotSendNotification::serviceRespondedWithAnError($exception);
80
        }
81
82
        return $responses;
83
    }
84
85
    /**
86
     * @param $notifiable
87
     *
88
     * @return mixed
89
     * @throws CouldNotSendNotification
90
     */
91
    protected function getToken($notifiable)
92
    {
93
        if ($notifiable->routeNotificationFor(self::class)) {
94
            return $notifiable->routeNotificationFor(self::class);
95
        }
96
97
        if ($notifiable->routeNotificationFor('fcm')) {
98
            return $notifiable->routeNotificationFor('fcm');
99
        }
100
101
        if (isset($notifiable->fcm_token)) {
102
            return $notifiable->fcm_token;
103
        }
104
105
        throw CouldNotSendNotification::invalidToken();
106
    }
107
108
    /**
109
     * @return \Kreait\Firebase\Messaging
110
     */
111
    protected function messaging()
112
    {
113
        try {
114
            $messaging = app('firebase.manager')->project($this->fcmProject)->messaging();
115
        } catch (BindingResolutionException $e) {
116
            $messaging = app('firebase.messaging');
117
        }
118
119
        return $messaging;
120
    }
121
122
    /**
123
     * @param \Kreait\Firebase\Messaging\Message $fcmMessage
124
     * @param $token
125
     * @return array
126
     * @throws \Kreait\Firebase\Exception\MessagingException
127
     * @throws \Kreait\Firebase\Exception\FirebaseException
128
     */
129
    protected function sendToFcm(Message $fcmMessage, $token)
130
    {
131
        if ($fcmMessage instanceof CloudMessage) {
132
            $fcmMessage = $fcmMessage->withChangedTarget('token', $token);
133
        }
134
135
        if ($fcmMessage instanceof FcmMessage) {
136
            $fcmMessage->setToken($token);
137
        }
138
139
        return $this->messaging()->send($fcmMessage);
140
    }
141
142
    /**
143
     * @param $fcmMessage
144
     * @param array $tokens
145
     * @return \Kreait\Firebase\Messaging\MulticastSendReport
146
     * @throws \Kreait\Firebase\Exception\MessagingException
147
     * @throws \Kreait\Firebase\Exception\FirebaseException
148
     */
149
    protected function sendToFcmMulticast($fcmMessage, array $tokens)
150
    {
151
        return $this->messaging()->sendMulticast($fcmMessage, $tokens);
152
    }
153
154
    /**
155
     * Dispatch failed event.
156
     *
157
     * @param mixed $notifiable
158
     * @param \Illuminate\Notifications\Notification $notification
159
     * @param \Throwable $exception
160
     * @return array|null
161
     */
162
    protected function failedNotification($notifiable, Notification $notification, Throwable $exception)
163
    {
164
        return $this->events->dispatch(new NotificationFailed(
165
            $notifiable,
166
            $notification,
167
            self::class,
168
            [
169
                'message' => $exception->getMessage(),
170
                'exception' => $exception,
171
            ]
172
        ));
173
    }
174
}
175