Laravel Watchable Package

James Mills > Blog > Laravel Watchable Package

I created this package to ‘scratch my own itch’. I have a model called Order. I wanted to notify certain people (only people who were watching the order) when the status of the order changed.

In this article, I will give you some boilerplate code that you can use in your application to wrap around the Laravel Watchable package.  If you fancy reading a little more about why I needed to build it in the first place, read the “A little background into ‘Why'” at the end of the page.

The problem

In the documentation, under the Using The Notification Facade section, you can see the example below.

Notification::send($users, new InvoicePaid($invoice));

However, the question is, how do you get the users? What I want to be able to do is send a collection of users who are watching the model.

The solution

Install the Laravel Watchable Package (https://github.com/jamesmills/watchable)

Remember to add the trait to your model. Throughout this post, I will use Order as the example.

<?php

use Illuminate\Database\Eloquent\Model;
use JamesMills\Watchable\Traits\Watchable;

class Order extends Model {
    use Watchable;
} 

Once you have the package installed this will help you handle the watchable request on the model. However, you will still need to add some additional functionality to your application. Below is some scaffolding which I hope will help.

I have created a separate controller to deal with this so that I can reuse the same controller for any models I want to be ‘watchable’.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class WatchController extends Controller
{
    public function update($uuid, Request $request)
    {
        $model_name = ucfirst($request->get('model'));

        $class = 'App\\' . $model_name;

        if (!class_exists($class)) {
            flash()->error('Model not found');

            return redirect()->back();
        }

        $model_to_watch = $class::findByUuidOrFail($uuid);
        $model_to_watch->toggleWatch();

        if ($model_to_watch->isWatched()) {
            flash()->success('You are now watching this ' . $model_name);
        } else {
            flash()->success('You are no longer watching this ' . $model_name);
        }

        return redirect()->back();
    }
}

To use this controller remember to add the route!

Route::resource('/watch', 'WatchController', ['only' => ['update']]);

Now you can use the example below in your view file when you are showing the model you want to be watchable.

Important: The key thing to remember is that we send a hidden field with the ‘key’ as the model name you want to watch/unwatch. This is what makes our controller code reusable.

{{ Form::open(['url' => route('watch.update', $order->uuid), 'method' => 'PUT']) }}
{{ method_field('PATCH') }}
{{ Form::hidden('model', 'order') }}

@if ($order->isWatched())
    <button class="btn btn-success">
        <i class="fa fa-bell" aria-hidden="true"></i>
        Unwatch
    </button>
@else
    <button class="btn btn-secondary">
        <i class="fa fa-bell-o" aria-hidden="true"></i>
        Watch
    </button>
@endif

{{ Form::close() }}

Now that we have added the ability for someone to be able to watch your model we can simply get the watchers of the model when we perform an action on it.

The below is a simplified version of what we have in our application when an order gets paused.

$order = Order::find(22);
$order->status = 'paused';
$order->save();

Notification::send($order->collectWatchers(), new OrderPaused($order));

Notes

I use the Laracasts Easy Flash Messages for the flash()->success(‘message’) messages you can see in the controller to display the watching status back to the user after they have clicked the button.

A little background into ‘Why’

At Clicksco we are experts in traffic acquisition and we use this skill to drive traffic to highly optimised landing pages to generate form fill leads for a number of partners focusing in the financial industry.

We partner with a company called Lead Byte for lead processing and delivery which we use in combination with a number of in-house systems to manage the entire lead lifecycle.

A few months ago I was working on a new lead ordering module which would allow us to create an order for leads and have the system manage it. A lead order is when a company comes to us and says they will buy X number of leads from us. They might require people looking for Y product and the value of their fund might have to be above Z.

Within Lead Byte we set all the delivery configurations so we can delivery the lead directly to the clients CRM. We also set up rules to make sure the correct partner gets the correct leads. The one thing we were missing was being able to create a lead order to fit various scenarios. (Example: Send 
20 leads daily until a total of 500 leads have been sent or until 22nd Oct 17).

Using a combination of Laravel, Pusher and Vue we implemented our solution in our main system (we call this the PMD). What was missing was a way for us to notify specific people when certain things happened to an order. For example, when the daily frequency was met and the order was paused. Or, when the total number of leads for the order was delivered so the order is closed. Using Laravel 5.5 Notifications it’s easy to send out these notifications using a selection of different channels but the tricky part comes when you need to decide who to send the notification to.

The is why the Laravel Watchable package was developed. I allow anyone who can log into the system to ‘watch’ an order. Once they are a watcher of a lead order they will automatically get all notifications of all order status changes. It’s easy to find the order, get all its watchers and then send a notification to everyone who is watching.

Leave a Reply

Your email address will not be published. Required fields are marked *