FcmChannel   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 143
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 5
dl 0
loc 143
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B send() 0 39 7
A messaging() 0 12 3
A sendToFcm() 0 12 3
A sendToFcmMulticast() 0 4 1
A failedNotification() 0 12 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 ReflectionException;
14
use Throwable;
15
16
class FcmChannel
17
{
18
    const MAX_TOKEN_PER_REQUEST = 500;
19
20
    /**
21
     * @var \Illuminate\Contracts\Events\Dispatcher
22
     */
23
    protected $events;
24
25
    /**
26
     * FcmChannel constructor.
27
     *
28
     * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher
29
     */
30
    public function __construct(Dispatcher $dispatcher)
31
    {
32
        $this->events = $dispatcher;
33
    }
34
35
    /**
36
     * @var string|null
37
     */
38
    protected $fcmProject = null;
39
40
    /**
41
     * Send the given notification.
42
     *
43
     * @param mixed $notifiable
44
     * @param \Illuminate\Notifications\Notification $notification
45
     *
46
     * @return array
47
     * @throws \NotificationChannels\Fcm\Exceptions\CouldNotSendNotification
48
     * @throws \Kreait\Firebase\Exception\FirebaseException
49
     */
50
    public function send($notifiable, Notification $notification)
51
    {
52
        $token = $notifiable->routeNotificationFor('fcm', $notification);
53
54
        if (empty($token)) {
55
            return [];
56
        }
57
58
        // Get the message from the notification class
59
        $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...
60
61
        if (! $fcmMessage instanceof Message) {
62
            throw CouldNotSendNotification::invalidMessage();
63
        }
64
65
        $this->fcmProject = null;
66
        if (method_exists($notification, 'fcmProject')) {
67
            $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...
68
        }
69
70
        $responses = [];
71
72
        try {
73
            if (is_array($token)) {
74
                // Use multicast when there are multiple recipients
75
                $partialTokens = array_chunk($token, self::MAX_TOKEN_PER_REQUEST, false);
76
                foreach ($partialTokens as $tokens) {
77
                    $responses[] = $this->sendToFcmMulticast($fcmMessage, $tokens);
78
                }
79
            } else {
80
                $responses[] = $this->sendToFcm($fcmMessage, $token);
81
            }
82
        } catch (MessagingException $exception) {
83
            $this->failedNotification($notifiable, $notification, $exception);
84
            throw CouldNotSendNotification::serviceRespondedWithAnError($exception);
85
        }
86
87
        return $responses;
88
    }
89
90
    /**
91
     * @return \Kreait\Firebase\Messaging
92
     */
93
    protected function messaging()
94
    {
95
        try {
96
            $messaging = app('firebase.manager')->project($this->fcmProject)->messaging();
97
        } catch (BindingResolutionException $e) {
98
            $messaging = app('firebase.messaging');
99
        } catch (ReflectionException $e) {
100
            $messaging = app('firebase.messaging');
101
        }
102
103
        return $messaging;
104
    }
105
106
    /**
107
     * @param \Kreait\Firebase\Messaging\Message $fcmMessage
108
     * @param $token
109
     * @return array
110
     * @throws \Kreait\Firebase\Exception\MessagingException
111
     * @throws \Kreait\Firebase\Exception\FirebaseException
112
     */
113
    protected function sendToFcm(Message $fcmMessage, $token)
114
    {
115
        if ($fcmMessage instanceof CloudMessage) {
116
            $fcmMessage = $fcmMessage->withChangedTarget('token', $token);
117
        }
118
119
        if ($fcmMessage instanceof FcmMessage) {
120
            $fcmMessage->setToken($token);
121
        }
122
123
        return $this->messaging()->send($fcmMessage);
124
    }
125
126
    /**
127
     * @param $fcmMessage
128
     * @param array $tokens
129
     * @return \Kreait\Firebase\Messaging\MulticastSendReport
130
     * @throws \Kreait\Firebase\Exception\MessagingException
131
     * @throws \Kreait\Firebase\Exception\FirebaseException
132
     */
133
    protected function sendToFcmMulticast($fcmMessage, array $tokens)
134
    {
135
        return $this->messaging()->sendMulticast($fcmMessage, $tokens);
136
    }
137
138
    /**
139
     * Dispatch failed event.
140
     *
141
     * @param mixed $notifiable
142
     * @param \Illuminate\Notifications\Notification $notification
143
     * @param \Throwable $exception
144
     * @return array|null
145
     */
146
    protected function failedNotification($notifiable, Notification $notification, Throwable $exception)
147
    {
148
        return $this->events->dispatch(new NotificationFailed(
149
            $notifiable,
150
            $notification,
151
            self::class,
152
            [
153
                'message' => $exception->getMessage(),
154
                'exception' => $exception,
155
            ]
156
        ));
157
    }
158
}
159