Display Desktop Notifications in PHP CLI Applications

Ash Allen - Jan 30 - - Dev Community

Introduction

There may be times when you're building a long-running script in PHP and you want to notify the user when the script has finished running. This could be to let them know that the script has finished successfully or to let them know that there was an error.

I've wanted to do this a few times after creating some long-running Artisan commands in my Laravel projects.

A great (and really cool!) way to do this is to use desktop notifications.

In this article, we're going to take a look at how to use the "JoliNotif" (jolicode/jolinotif) package to display desktop notifications from your PHP CLI applications. I'm mainly a Laravel developer, so the examples will be based around triggering the notifications from Laravel Artisan commands, but the concepts should be easy enough to apply to our PHP CLI applications.

What is JoliNotif?

JoliNotif is a cross-platform package that allows you to display desktop notifications from your PHP applications running on Windows, macOS, and Linux.

It was built and is maintained by JoliCode. At the time of writing this article, it has over 5.2 million downloads and 1.3k stars on GitHub.

It's a great package and is super easy to use!

A few years ago, I built a small Laravel package as a proof of concept called "Laravel Executor". It was a package that allowed you to build scripts using PHP and then execute them from an Artisan command. The idea behind it was that you could build a deployment script or other utilities with it. It was mainly built as a fun little project for me to practice my web development skills and to learn more about building Laravel packages.

I used JoliNotif in Laravel Executor so that developers could add notifications to their Artisan commands. I thought it was a cool little feature that added that extra bit of polish to the package.

If you're building a package, CLI application, or Laravel Artisan command, you might want also want to add desktop notifications to it.

So let's get stuck in and take a look at how to use it!

Install the Package

To get started with using jolicode/jolinotif, we'll need to install it into our project using Composer. We can do this by running the following command in our project root:

composer require jolicode/jolinotif
Enter fullscreen mode Exit fullscreen mode

The package should now be installed and ready to use!

Create a Basic Notification

To create a notification, we first need to create a new Joli\JoliNotif\Notification class instance. This is the object that holds the data about the notification you want to display to the user.

After we've created the new instance, we want to pass it to a "Notifier" which is responsible for displaying the notification to the user. We'll cover notifiers in a bit more detail later in this article. You can access the notifier using the NotifierFactory::create() method.

To send a basic notification, we can do the following:

use Joli\JoliNotif\Notification;
use Joli\JoliNotif\NotifierFactory;

$notification = (new Notification())
    ->setBody('The long script has finished!')
    ->setTitle('My Awesome PHP CLI App!');

NotifierFactory::create()->send($notification);
Enter fullscreen mode Exit fullscreen mode

Running the following code above would result in a desktop notification being displayed to the user that looks something like this:

Basic desktop notification

It's worth noting that the body of the notification (set using the setBody method) is a required field. If you don't set it, then an exception will be thrown when trying to display the notification.

To give some context as to how you might want to use this in a Laravel Artisan command, let's look at a quick example. We'll imagine that we've built a long-running Artisan command that does some processing and we want to notify the user when it's finished. Our command might look something like this:

declare(strict_types=1);

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Joli\JoliNotif\Notification;
use Joli\JoliNotif\NotifierFactory;

final class DesktopNotification extends Command
{
    protected $signature = 'app:desktop-notification';

    protected $description = 'Run a long script';

    public function handle(): int
    {
        // Run the long script here...

        $this->sendDesktopNotification();

        return self::SUCCESS;
    }

    private function sendDesktopNotification(): void
    {
        $notification = (new Notification())
            ->setBody('The long script has finished!')
            ->setTitle('My Awesome PHP CLI App!');

        NotifierFactory::create()->send($notification);
    }
}
Enter fullscreen mode Exit fullscreen mode

Customise the Notification

Depending on the notifier that's being used, you can customise the notification in a number of ways.

Change the Subtitle

Some notifiers allow you to add a subtitle to the notification. This is a small piece of text that's displayed underneath the title of the notification. To add a subtitle to the notification, you can use the addOption method on the notification object like so:

$notification = (new Notification())
    ->setBody('The long script has finished!')
    ->setTitle('My Awesome PHP CLI App!')
    ->addOption('subtitle', 'This is a subtitle');

NotifierFactory::create()->send($notification);
Enter fullscreen mode Exit fullscreen mode

Running the above code on a macOS machine would result in a notification that looks something like this:

Basic notification with subtitle

It's worth noting that if the notifier doesn't support subtitles, then it will just be ignored and not displayed to the user.

Change the Sound

Depending on the notifier that's being used, you can also change the sound that's played when the notification is displayed to the user. To do this, you can use the addOption method on the notification object like so:

$notification = (new Notification())
    ->setBody('The long script has finished!')
    ->setTitle('My Awesome PHP CLI App!')
    ->addOption('sound', 'Funk');

NotifierFactory::create()->send($notification);
Enter fullscreen mode Exit fullscreen mode

The GitHub repo lists the following sounds that are available to use on a macOS machine: Basso, Frog, Hero, Pop, Submarine, Blow, Funk, Morse, Purr, Tink, Bottle, Glass, Ping, Sosumi.

However, this is a non-exhaustive list, so you might want to do some investigating to see which sounds are available on the OS that you're intending the application to run on.

Change the Icon

Some (but not many) of the available notifiers allow you to change the icon of the notification. This is great for adding a bit of extra branding to your notifications if they're going to be running on another user's machine.

To change the icon of the notification, you can use the setIcon method on the notification object like so:

$notification = (new Notification())
    ->setBody('The long script has finished!')
    ->setTitle('My Awesome PHP CLI App!')
    ->setIcon('/absolute/path/to/my/icon.png');

NotifierFactory::create()->send($notification);
Enter fullscreen mode Exit fullscreen mode

As we can see in the code example above, we've passed the icon's absolute path to the setIcon method.

If you attempt to set an icon and the machine's notifier doesn't support it, then it will just be ignored and not displayed to the user.

Notifiers

As we've briefly mentioned, JoliNotif uses the concept of "notifiers" to display the notifications on the user's desktop. These are the underlying notification systems that are available on the device that can be used to trigger desktop notifications. By default, it will attempt to resolve a notifier based on the operating system that the application is running on.

As we've mentioned with the customisation options above, due to the small differences between the notifiers, it means that there may be some features that are available on some operating systems but not on others.

If a notifier can't be found that the package can use and is supported by the OS, then no errors will be thrown. Instead, the notification will just be ignored and not displayed to the user. Depending on the context of what the notification was used for, this might not be an issue.

Available Notifiers

At the time of writing this article, JoliNotif supports the following notifiers:

  • Linux
    • KDialogNotifier - Supports: Body, Title
    • NotifySendNotifier - Supports: Body, Title, Icon
  • macOS
    • GrowlNotifyNotifier - Supports: Body, Title, Icon
    • TerminalNotifierNotifier - Supports: Body, Title
    • AppleScriptNotifier - Supports: Body, Title
  • Windows
    • SnoreToastNotifier - Supports: Body, Title, Icon
    • ToasterNotifier - Supports: Body, Title, Icon
    • NotifuNotifier - Supports: Body, Title, Icon

Manually Specifying a Notifier

There may be times when you want to manually specify a notifier (or group of notifiers) to attempt to use. This could be due to you wanting to use a specific feature that's only available on a certain notifier.

To do this, you can pass your desired notifier in an array to the NotifierFactory::create() method as the first argument. For example, if you wanted to use the TerminalNotifier you could do the following:

NotifierFactory::create([new TerminalNotifierNotifier()])->send($notification);
Enter fullscreen mode Exit fullscreen mode

In this case, JoliNotif will attempt to use the TerminalNotifier notifier to display the notification. If it can't find it, or if it's not supported by the OS, then the notification will be ignored. Otherwise, it will be displayed to the user.

Creating Your Own Notifier

You may want to create your own notifier to use with JoliNotif. For example, you may want to use a notifier that's not currently supported by the package. Although this isn't something I've needed to do myself, it's still good to know that it's possible.

To create your own notifier, you'll need to create a class that implements the package's Joli\JoliNotif\Notifier interface. If you're unsure about what interfaces are, you might want to check out my "Using Interfaces to Write Better PHP Code" article. The interface looks like so:

namespace Joli\JoliNotif;

interface Notifier
{
    public const PRIORITY_LOW = 0;
    public const PRIORITY_MEDIUM = 50;
    public const PRIORITY_HIGH = 100;

    /**
     * This method is called to check whether the notifier can be used on the
     * current system or not.
     */
    public function isSupported(): bool;

    /**
     * The supported notifier with the higher priority will be preferred.
     */
    public function getPriority(): int;

    /**
     * Send the given notification.
     *
     * @throws Exception\InvalidNotificationException if the notification is invalid
     */
    public function send(Notification $notification): bool;
}
Enter fullscreen mode Exit fullscreen mode

So you may have a class that looks something like this:

namespace App\Notifiers;

use Joli\JoliNotif\Notification;
use Joli\JoliNotif\Notifier;

final class MyCustomNotifier implements Notifier
{
    public function isSupported(): bool
    {
        // Check if the notifier is supported on the current system...
    }

    public function getPriority(): int
    {
        // Return the priority of the notifier...
    }

    public function send(Notification $notification): bool
    {
        // Send the notification...
    }
}
Enter fullscreen mode Exit fullscreen mode

Once you've configured your new notifier, you can then pass it to the NotifierFactory::create() method as we did in the previous section like so:

NotifierFactory::create([new MyCustomNotifier()])->send($notification);
Enter fullscreen mode Exit fullscreen mode

If your new MyCustomNotifier class is supported by the current system, then your notifier's send method will be called and the notification will be displayed to the user.

Other Types of Notifications

In this article, we've covered how to display desktop notifications from your PHP CLI applications. But there may be times that you want to notify your users in other ways, such as sending SMS messages, emails, broadcasts using WebSockets, or even WhatsApp messages.

Of course, the use case for using these types of notifications is a little different to using desktop notifications. But if you're interested in learning more about these types of notifications, you might want to check out some of my other articles:

👉 Send an SMS in Laravel Using Vonage (Previously Nexmo)

👉 Send WhatsApp Messages in Laravel With Vonage's Native SDK

👉 A Guide to Using Websockets in Laravel

Conclusion

Hopefully, this article has given a quick insight into how you can use the jolicode/jolinotif package to display desktop notifications from your PHP CLI applications and Laravel Artisan commands.

If you enjoyed reading this post, I'd love to hear about it. Likewise, if you have any feedback to improve the future ones, I'd also love to hear that too.

You might also be interested in checking out my 220+ page ebook "Battle Ready Laravel" which covers similar topics in more depth.

Or, you might want to check out my other 440+ ebook "Consuming APIs in Laravel" which teaches you how to use Laravel to consume APIs from other services.

Keep on building awesome stuff! 🚀

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .