0

I have a Symfony backend w/ a NativeScript Mobile App. Wanting to implement push notifications, but struggling to find decent examples and documentation about what is involved on the Symfony end.

I also require the ability to poll an XML file every X amount of seconds, and look for a flag is set to true - if so, push a notification to all connected devices FROM the backend.

Any recommendations?

1 Answers1

0

We use "Google firebase" for that. You (or your client) first need a Google firebase account.

In our case Firebase is the connection between a Symfony backend in php and a mobile PWA (Progressive web app) written in another language (for us that is Vue javascript).

It is a service specially for handling messaging. Like they say themselves "Firebase Cloud Messaging | Cross-Platform Messaging"

I'm only going to focus on the Symfony part in my answer. The other side (the Vue app) will also have to implement firebase but that is another story.

In Symfony install a bundle that connects firebase with Symfony, we took kreait/firebase-bundle

Follow the documentation and you will get this line in your composer.json

"kreait/firebase-bundle": "^2.0"

app/config.yml

kreait_firebase:
projects:
    some_client_name_pwa:
        credentials: '%kernel.root_dir%/config/google/some-client-name-firebase-adminsdk-123456-some-code.json'

The json file as mentioned in the previous code block is automatically created by doing what this person says: https://stackoverflow.com/a/40799378/5418514

This file then contains the credentials from firebase and some more stuff htdocs/app/config/google/some-client-name-firebase-adminsdk-123456-some-code.json

{
    "type": "service_account",
    "project_id": "some-client-name",
    "private_key_id": "12345some_id",
    "private_key": "-----BEGIN PRIVATE KEY-----\n_some_private_key_\n-----END PRIVATE KEY-----\n",
    "client_email": "firebase-adminsdk-123456_some-code@some-client-name.iam.gserviceaccount.com",
    "client_id": "12345_some_client_id",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-123456_some-code%40some-client-name.iam.gserviceaccount.com"
}

App\CoreBundle\Service

<?php

namespace App\CoreBundle\Service;

use App\UserBundle\Entity\User;
use Kreait\Firebase\Messaging;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RequestStack;

class WebPushNotificationService implements LoggerAwareInterface
{
    /**
     * @var Messaging
     */
    private $messaging;

    /**
     * @var RequestStack
     */
    private $requestStack;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * WebPushNotificationService constructor.
     *
     * @param Messaging $messaging
     * @param RequestStack $requestStack
     */
    public function __construct(Messaging $messaging, RequestStack $requestStack)
    {
        $this->messaging = $messaging;
        $this->requestStack = $requestStack;
    }

    public function sendMessageToUser(User $user, string $title, string $body)
    {
        if (!$user->getWebPushToken()) {
            return;
        }

        try {
            $icon = $this->requestStack->getCurrentRequest()->getSchemeAndHttpHost() . ($user->getLocale() === 'fr' ? '/images/logo_fr.jpg' : '/images/logo.jpg');

            $message = Messaging\CloudMessage::withTarget('token', $user->getWebPushToken())
                ->withNotification(Messaging\Notification::create($title, $body, $icon));

            // Example from https://firebase.google.com/docs/cloud-messaging/admin/send-messages#webpush_specific_fields
            $config = Messaging\WebPushConfig::fromArray([
                'notification' => [
                    'title' => $title,
                    'body' => $body,
                    'icon' => $icon,
                ],
            ]);

            $message = $message->withWebPushConfig($config);

            $this->messaging->send($message);

        } catch (\Throwable $throwable) {
            $this->logger->error(sprintf('Error sending webpush notification to user "%s" with error "%s"', $user->getId(), $throwable->getMessage()));
            return false;
        }

        return true;
    }

    public function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}

Register it as a service:

SomeBundle/Resources/config/services.yml

App\CoreBundle\Service\WebPushNotificationService:
    autowire: true
    autoconfigure: true
    arguments:
        $messaging: '@kreait_firebase.some_client_name_pwa.messaging'
    calls:
        - ['setLogger', ['@monolog.logger']]

In your User object add

/**
 * @var string|null
 *
 * @ORM\Column(type="string", nullable=true)
 */
private $webPushToken;

/**
 * @return string|null
 */
public function getWebPushToken(): ?string
{
    return $this->webPushToken;
}

/**
 * @param string|null $webPushToken
 */
public function setWebPushToken(?string $webPushToken): void
{
    $this->webPushToken = $webPushToken;
}

To use it:

$this->webPushNotificationService->sendMessageToUser($recipient, $title, $body);

PS: There is probably some more to be done but this should help you on your way. Remember to also implement firebase into your mobile app. Depending on the language it is written in you should look for documentation for implementing "Google firebase" in that programming language.

Julesezaar
  • 2,658
  • 1
  • 21
  • 21