The Laravel framework has an excellent notification system that can be used to send emails, SMS messages, or other types of notifications to users. But there is another popular way to inform users: a daily summary of the events of that day. In this article I will show you a demo project with both.

The complete project code is available on Github, the link is at the end of the article.


Demo project: Subscribe to job offers by tags

Fairly realistic scenario: a job site project in which potential employees/freelancers can subscribe to new jobs by their industry tags and would be notified by email.

To make notifications personal, we added two new fields to the typical Laravel registration form:

In terms of database, there are two new structures besides the default Laravel:

  • Column users.notifications_frequency (varchar with values ​​“immediately” or “once”)
  • Painting SKILLS and pivot table skill_user with columns skill_id And User ID

Immediate notification: when admin posts a new job

Here is a form allowing the administrator to post new job offers:

When this form is completed, the controller saves the data – here is app/Http/Controllers/Admin/JobsController.php:


public function store(StoreJobRequest $request)
{
    $job = Job::create($request->all());

    return redirect()->route('admin.jobs.index');
}

The “Skills” field is important to us – it will determine who gets notified.

Notifications are triggered with the Eloquent Observer class – app/Observers/JobObserver.php:


use App\Job;
use App\Notifications\NewJobImmediateNotification;
use App\User;
use Notification;

class JobObserver
{

    public function created(Job $job)
    {
        $job->skills()->sync(request()->input('skills', []));
        $skills = $job->skills->pluck('id');
        $users = User::where('notifications_frequency', 'immediately')
            ->whereHas('skills', function ($query) use ($skills) {
                $query->whereIn('id', $skills);
            })->get();

        Notification::send($users, new NewJobImmediateNotification($job));
    }
}

You can learn more about Eloquent Observers here in the official documentation. It’s basically a simple class that automatically triggers its methods whenever an Eloquent model is created/updated/deleted, etc.

To register an observer with a particular model, we need to add this piece of code in app/Job.php:


use App\Observers\JobObserver;

class Job extends Model
{
    public static function boot()
    {
        parent::boot();
        self::observe(new JobObserver);
    }
}

Now what is happening inside this JobObserver method created()? Let’s repeat:


$job->skills()->sync(request()->input('skills', []));
$skills = $job->skills->pluck('id');
$users = User::where('notifications_frequency', 'immediately')
    ->whereHas('skills', function ($query) use ($skills) {
        $query->whereIn('id', $skills);
    })->get();

Notification::send($users, new NewJobImmediateNotification($job));

SO:

  1. Professional skills are recorded in a pivot table;
  2. We obtain the IDs of these skills and query users who subscribed to these tags with “immediate” notifications;
  3. We send notifications to each of them.

Now what’s inside app/Notifications/NewJobImmediateNotification.php?


class NewJobImmediateNotification extends Notification
{

    public function __construct($job)
    {
        $this->job = $job;
    }

    public function toMail($notifiable)
    {
        return (new MailMessage)
                    ->subject('New job has been posted')
                    ->line('A new job listing has been posted: '.$this->job->title)
                    ->line('Skills: '.$this->job->skills->implode('name', ', '))
                    ->line('Description: '.$this->job->description)
                    ->line('Contact email: '.$this->job->contact_email)
                    ->action('View job', route('admin.jobs.show', $this->job->id))
                    ->line('Thank you for using our application!');
    }
}

As you can see, we pass $work as a parameter of this class, so we need to transform it into a private variable in __construction() method. And then it’s just a matter of forming the notification email line by line.

Here is the email received:

Laravel Email Notification


Daily summary: new jobs of the day

As I mentioned, it is quite common to send daily/weekly summary emails with new system events, in part to protect users from “spamming” emails every time.

To achieve this, we create the Artisan command which will be called as follows: php craftsman jobs: digest.

Here is our app/Console/Commands/SendDailyJobsEmails.php:


use App\Job;
use App\Notifications\NewJobsDailyNotification;
use App\User;
use Illuminate\Console\Command;

class SendDailyJobsEmails extends Command
{

    protected $signature="jobs:digest";

    protected $description = 'Send daily emails to users with list of new jobs';

    public function handle()
    {
        $jobs = Job::with('skills')
            ->whereHas('skills')
            ->whereBetween('created_at', [now()->subDay(), now()])
            ->get();

        $users = User::with('skills')
            ->where('notifications_frequency', 'once')
            ->get();

        foreach($users as $user)
        {
            $userSkills = $user->skills;
            $userJobs = $jobs->filter(function ($job) use ($userSkills) {
                return $job->skills->contains(function($key, $value) use($userSkills) {
                    return $userSkills->contains($value);
                });
            });

            if($userJobs->count())
            {
                $user->notify(new NewJobsDailyNotification($userJobs));
            }
        }     
    }
}

The code is self-explanatory, with some collection filtering used.

Let’s take a look at app/Notifications/NewJobsDailyNotification.php:


class NewJobsDailyNotification extends Notification
{
    public function __construct($jobs)
    {
        $this->jobs = $jobs;
    }

    public function toMail($notifiable)
    {
        return (new MailMessage)->markdown('mail.jobs', ['jobs' => $this->jobs]);
    }
}

The structure of this notification is a bit more complicated, so it was worth separating it into a separate template. Here is resources/views/mail/jobs.blade.php:


@component('mail::message')
# Hello
There are new jobs for you
@foreach($jobs as $job) Title: {{ $job->title }}
Skills: {{ $job->skills->implode('name', ', ') }}
Description: {{ $job->description }}
Contact email: {{ $job->contact_email }}
@if(!$loop->last) * * * @endif @endforeach @component('mail::button', ['url' => route('admin.jobs.index')]) View Jobs @endcomponent Thanks,
{{ config('app.name') }} @endcomponent

You can learn more about Markdown syntax here, also read my article Laravel Mail Notifications: How to Customize Templates.

Last thing – we need to plan this daily order, we do app/Console/Kernel.php:


class Kernel extends ConsoleKernel
{
    protected function schedule(Schedule $schedule)
    {
        $schedule->command('jobs:digest')
                 ->dailyAt('20:00');
    }
}

And there you have it, every evening, users received an email like this:

As promised, Github repository with the whole project: LaravelDaily/Laravel-Notifications-Daily-Immediate



Technology

Another Tech Information

Similar Posts