bpolaszek/webpush-bundle

How to add PushNotification::ACTIONS

Closed this issue · 6 comments

zogs commented

I could not find any example of how to add any actions.

I tried like that but it throw an exception :

$pushNotification = new PushNotification('title', [
      PushNotification::BODY => "this is the body",
      PushNotification::ACTIONS => ["action" => "read", "title" => "Read", "link" => "http://example.com"]
    ]);
Error: Method BenTools\WebPushBundle\Model\Message\PushNotification::__toString() must not throw an exception, caught ErrorException: Notice: Array to string conversion
in [vendor/bentools/webpush-bundle/src/Model/Message/PushNotification.php ](http://dev.local/_profiler/open?file=vendor/bentools/webpush-bundle/src/Model/Message/PushNotification.php&line=1#line1)(line 1)

I looked over but did not find why the _toString method was called. Any hints ?
Thank you

zogs commented

I found a workaround if anyone's interested !
We have to encode ACTIONS and DATA to json

$pushNotification = new PushNotification('title', [
      PushNotification::BODY => "this is the body",
      PushNotification::ACTIONS => json_encode(["action" => "read", "title" => "Read"])
      PushNotifications::DATA => json_encode(["link" => "http://ect.com"])
    ]);

and decode it in the service-worker...

self.addEventListener('push', event => {
    try {
        const Notification = event.data.json();

        if(Notification.options.actions) {
          Notification.options.actions = JSON.parse(Notification.options.actions);
        }
        if(Notification.options.data) {
          Notification.options.data = JSON.parse(Notification.options.data);
        }
        event.waitUntil(
            self.registration.showNotification(Notification.title || '', Notification.options || {})
        );
    } catch (e) {
        console.error(e);
    }
});

and voila !

zogs commented

I forgot, the notificationclick part looks like that :

self.addEventListener('notificationclick', event => {

    if (event.action === 'read') {
      const url = event.notification.data.link || null;
      if (url) {
          event.waitUntil(
              clients.matchAll({
                  type: 'window'
              })
              .then(windowClients => {
                  for (const client of windowClients) {
                      if (client.url === url && 'focus' in client) {
                          return client.focus();
                      }
                  }

                  if (clients.openWindow) {
                      return clients.openWindow(url);
                  }
              })
          );
      }
    }
});

Hello there,

The __toString() method is called in order to provide the string representation of the notification's payload.

$pushNotification = new PushNotification('title', [
      PushNotification::BODY => "this is the body",
      PushNotification::ACTIONS => ["action" => "read", "title" => "Read", "link" => "http://example.com"]
    ]);
echo $pushNotification;

This doesn't throw any error on my side 🤔

zogs commented

You are right, I can confirm it works using it this way. But i still get an error sometimes, so i digged a little deeper...
Looks like the error happen when its conjugated with a null PushNotification::IMAGE (or ICON, TAG, or BODY actually)

$pushNotification = new PushNotification('title', [
      PushNotification::BODY => "this is the body",
      PushNotification::ACTIONS => ["action" => "read", "title" => "Read", "link" => "http://example.com"],
      PushNotification::IMAGE=> null,
    ]);
echo $pushNotification;
// shoud trigger an error

Passing null values does not seems to be trouble in other cases, but when ACTIONS is present it does...

Okay, seems to be related to some sanitization removing null values to save bandwidth.
Didn't get errors on my side because AFAIR __toString can now yell exceptions as of PHP 8.1.

Can you try with #33?

zogs commented

Can confirm it works ! At least on PHP7.3