laravel-notification-channels / fcm

Firebase Cloud Messaging (FCM) notifications channel for Laravel
https://laravel-notification-channels.com/
MIT License
495 stars 127 forks source link

Migration guide? #175

Closed Synchro closed 1 year ago

Synchro commented 1 year ago

I've been using this package for a while, but just noticed that the API has changed substantially. My code looks like this:

class CheckoutComplete extends FcmNotification
{
    public function __construct(private readonly Location $location)
    {
        //
    }

    public function toFcm($notifiable): FcmMessage
    {
        $title = __('☕🥗 Thanks for checking out!');
        $body = __(
            'Your order at :location is complete, enjoy!',
            ['location' => $this->location->title()]
        );

        $message = FcmMessage::create()
            ->setData(
                [
                    'title' => $title,
                    'body'  => $body,
                    'type'  => NotificationType::CHECKOUT_COMPLETE->value,
                ]
            )
            ->setAndroid(
                AndroidConfig::create()
                    ->setFcmOptions(AndroidFcmOptions::create()->setAnalyticsLabel('analytics'))
            )->setApns(
                ApnsConfig::create()
                    ->setFcmOptions(ApnsFcmOptions::create()->setAnalyticsLabel('analytics_ios'))
            );
        if ($notifiable->device_platform === DevicePlatforms::IOS) {
            $message->setNotification(
                Notification::create()
                    ->setTitle($title)
                    ->setBody($body)
                    ->setImage(asset('storage/' . $this->location->customer->image))
            );
        }
        return $message;
    }

But now I look at the examples and it's all quite different - setData on the FcmMessage class now seems to be just data, but setAndroid and setApns seems to have disappeared entirely. I'm keen to update to the bleeding edge because I need the support for multicast errors you added recently.

Is there a guide listing what I need to do to update my code?

Synchro commented 1 year ago

I gather from examples that it should go like this:

class CheckoutComplete extends Notification
{
    public function __construct(private readonly Location $location)
    {
        //
    }

    public function via($notifiable)
    {
        return [FcmChannel::class];
    }

    public function toFcm($notifiable)
    {
        return (new FcmMessage(notification: new FcmNotification(
            title: __('☕🥗 Thanks for checking out!'),
            body : __(
                'Your order at :location is complete, enjoy!',
                ['location' => $this->location->title()]
            ),
            image: asset('storage/' . $this->location->customer->image)
        )))
            ->custom(
                [
                    'android' => [
                        'fcm_options' => [
                            'analytics_label' => 'analytics',
                        ],
                    ],
                    'apns'    => [
                        'fcm_options' => [
                            'analytics_label' => 'analytics_ios',
                        ],
                    ],
                ]
            );
    }
}

The notable changes seem to be:

  1. Extend the stock Laravel Notification class instead of FcmNotification
  2. Add the via() method to point it at FCM
  3. Set title, body, and image through constructor params
  4. Replace the setAndroid and setApns with equivalent options in custom (I've not found docs on what's available in there)

Having done this, my notifications are being delivered and multicast failures are turning up in my event handler (yay!) – but did I miss anything important?

Synchro commented 1 year ago

It took me a while to track down a readable error message within the NotificationFailed event handler, but eventually found one like this:

$report = Arr::get($event->data, 'report');
$errorMessage = $report->error()->getMessage();

$report->error() returns an Exception of some kind, such as \Kreait\Firebase\Exception\Messaging\InvalidMessage.

Rather than deleting tokens in the event of any failure, it's good to check that they are explicitly invalid rather than that the submission process failed, so I'm doing that with:

if ($report->messageTargetWasInvalid()) {
    ...
dwightwatson commented 1 year ago

It looks like you've uncovered all the changes I can think of. I might put these into an upgrade guide to go with the final release. It hadn't even crossed my mind, oops!

I'll try and get this all sorted and tagged by next week.

Synchro commented 1 year ago

One small thing I spotted - I'm sure that toFcm() used to declare an FcmMessage return type, but that appears to have gone. Is that right?

dwightwatson commented 1 year ago

Here's the changes between the last 3.x version and the current 4.x beta: https://github.com/laravel-notification-channels/fcm/compare/3.2.1...4.0.0beta2

It doesn't look like the docs used to have an FcmMessage return type but it won't make a difference - totally up to you if you want to implement that or not. It's application code so it's personal preference.

dwightwatson commented 1 year ago

I've added a CHANGELOG which I think covers most of the important changes. Not a full migration guide as the majority of changes are in the toFcm method which will require reviewing the docs. Let me know if you have any thoughts, otherwise open to PRs.

Synchro commented 1 year ago

Thanks for confirming what I need to do, for adding the changelog, and releasing 4.0!