In this lesson, we will look at how we can add more than one Notification to be sent out to the user. We will create a few more Notifications and schedule them to be sent out at different times.
Currently, we only have a Notification that is sent 1 hour before the booking, but we need new ones that are sent at:
We can get this quickly done by using the php artisan make:notification
command:
php artisan make:notification BookingReminder2Hphp artisan make:notification BookingReminder5Minphp artisan make:notification BookingStartedNotification
And then we will edit all the Notifications to accept the Booking Model as a parameter:
app/Notifications/BookingReminder2H.php
use App\Models\Booking;use Illuminate\Notifications\Messages\MailMessage;use Illuminate\Notifications\Notification; class BookingReminder2H extends Notification{ public function __construct(protected Booking $booking) { } public function via($notifiable): array { return ['mail']; } public function toMail($notifiable): MailMessage { return (new MailMessage) ->line('The introduction to the notification.') ->action('Notification Action', url('/')) ->line('Thank you for using our application!'); } public function toArray($notifiable): array { return []; }}
app/Notifications/BookingReminder5MIN.php
use App\Models\Booking;use Illuminate\Notifications\Messages\MailMessage;use Illuminate\Notifications\Notification; class BookingReminder5MIN extends Notification{ public function __construct(protected Booking $booking) { } public function via($notifiable): array { return ['mail']; } public function toMail($notifiable): MailMessage { return (new MailMessage) ->line('The introduction to the notification.') ->action('Notification Action', url('/')) ->line('Thank you for using our application!'); } public function toArray($notifiable): array { return []; }}
app/Notifications/BookingStartedNotification.php
use App\Models\Booking;use Illuminate\Notifications\Messages\MailMessage;use Illuminate\Notifications\Notification; class BookingStartedNotification extends Notification{ public function __construct(protected Booking $booking) { } public function via($notifiable): array { return ['mail']; } public function toMail($notifiable): MailMessage { return (new MailMessage) ->line('The introduction to the notification.') ->action('Notification Action', url('/')) ->line('Thank you for using our application!'); } public function toArray($notifiable): array { return []; }}
Our basic Notifications are ready to go. Next up are more preparations for scheduling them.
Next is the actual scheduling part of the Notifications. We will modify our Controller to schedule the Notifications:
app/Http/Controllers/BookingController.php:
use App\Http\Requests\StoreBookingRequest;use App\Http\Requests\UpdateBookingRequest;use App\Models\Booking;use Illuminate\Http\RedirectResponse;use Illuminate\Http\Request; class BookingController extends Controller{ public function index() { $bookings = Booking::query() ->with(['user']) ->get(); return view('bookings.index', compact('bookings')); } public function create() { return view('bookings.create'); } public function store(StoreBookingRequest $request): RedirectResponse { $booking = $request->user()->bookings()->create($request->validated()); $startTime = CarbonImmutable::parse(toUserDateTime($booking->start, $booking->user), $booking->user->timezone); // Schedule 2H reminder $twoHoursTime = fromUserDateTime($startTime->subHours(2), $booking->user); if (now('UTC')->lessThan($twoHoursTime)) { $booking->user->scheduledNotifications()->create([ 'notification_class' => BookingReminder2H::class, 'notifiable_id' => $booking->id, 'notifiable_type' => Booking::class, 'sent' => false, 'processing' => false, 'scheduled_at' => $twoHoursTime, 'sent_at' => null, 'tries' => 0, ]); } // Schedule 1H reminder $oneHourTime = fromUserDateTime($startTime->subHour(), $booking->user); if (now('UTC')->lessThan($oneHourTime)) { $booking->user->scheduledNotifications()->create([ 'notification_class' => BookingReminder1H::class, 'notifiable_id' => $booking->id, 'notifiable_type' => Booking::class, 'sent' => false, 'processing' => false, 'scheduled_at' => $oneHourTime, 'sent_at' => null, 'tries' => 0, ]); } // Schedule 5 min reminder $fiveMinutesTime = fromUserDateTime($startTime->subMinutes(5), $booking->user); if (now('UTC')->lessThan($fiveMinutesTime)) { $booking->user->scheduledNotifications()->create([ 'notification_class' => BookingReminder5MIN::class, 'notifiable_id' => $booking->id, 'notifiable_type' => Booking::class, 'sent' => false, 'processing' => false, 'scheduled_at' => $fiveMinutesTime, 'sent_at' => null, 'tries' => 0, ]); } // Schedule started reminder $startingTime = fromUserDateTime($startTime, $booking->user); if (now('UTC')->lessThan($startingTime)) { $booking->user->scheduledNotifications()->create([ 'notification_class' => BookingStartedNotification::class, 'notifiable_id' => $booking->id, 'notifiable_type' => Booking::class, 'sent' => false, 'processing' => false, 'scheduled_at' => $startingTime, 'sent_at' => null, 'tries' => 0, ]); } return redirect()->route('booking.index'); } public function edit(Booking $booking) { return view('bookings.edit', compact('booking')); } public function update(UpdateBookingRequest $request, Booking $booking): RedirectResponse { $booking->update($request->validated()); $startTime = CarbonImmutable::parse(toUserDateTime($booking->start, $booking->user), $booking->user->timezone); $hasScheduledNotifications = ScheduledNotification::query() ->where('notifiable_id', $booking->id) ->where('notifiable_type', Booking::class) ->where('user_id', $booking->user_id) ->exists(); // First we need to check if there are any already scheduled notifications if ($hasScheduledNotifications) { // Then in this example, we simply delete them. You can however update them if you want. $booking->scheduledNotifications() ->where('user_id', $booking->user_id) ->delete(); } // Since we are clearing the scheduled notifications, we need to create them again for the new date // Schedule 2H reminder $twoHoursTime = fromUserDateTime($startTime->subHours(2), $booking->user); if (now('UTC')->lessThan($twoHoursTime)) { $booking->user->scheduledNotifications()->create([ 'notification_class' => BookingReminder2H::class, 'notifiable_id' => $booking->id, 'notifiable_type' => Booking::class, 'sent' => false, 'processing' => false, 'scheduled_at' => $twoHoursTime, 'sent_at' => null, 'tries' => 0, ]); } // Schedule 1H reminder $oneHourTime = fromUserDateTime($startTime->subHour(), $booking->user); if (now('UTC')->lessThan($oneHourTime)) { $booking->user->scheduledNotifications()->create([ 'notification_class' => BookingReminder1H::class, 'notifiable_id' => $booking->id, 'notifiable_type' => Booking::class, 'sent' => false, 'processing' => false, 'scheduled_at' => $oneHourTime, 'sent_at' => null, 'tries' => 0, ]); } // Schedule 5 min reminder $fiveMinutesTime = fromUserDateTime($startTime->subMinutes(5), $booking->user); if (now('UTC')->lessThan($fiveMinutesTime)) { $booking->user->scheduledNotifications()->create([ 'notification_class' => BookingReminder5MIN::class, 'notifiable_id' => $booking->id, 'notifiable_type' => Booking::class, 'sent' => false, 'processing' => false, 'scheduled_at' => $fiveMinutesTime, 'sent_at' => null, 'tries' => 0, ]); } // Schedule started reminder $startingTime = fromUserDateTime($startTime, $booking->user); if (now('UTC')->lessThan($startingTime)) { $booking->user->scheduledNotifications()->create([ 'notification_class' => BookingStartedNotification::class, 'notifiable_id' => $booking->id, 'notifiable_type' => Booking::class, 'sent' => false, 'processing' => false, 'scheduled_at' => $startingTime, 'sent_at' => null, 'tries' => 0, ]); } return redirect()->route('booking.index'); } public function destroy(Request $request, Booking $booking): RedirectResponse { abort_unless($booking->user_id === $request->user()->id, 404); $booking->delete(); $booking->scheduledNotifications() ->where('user_id', $booking->user_id) ->where('user_id', $booking->user_id) ->delete(); return redirect()->route('booking.index'); }}
Now we will have 4 Notifications scheduled for us:
Now that we have our scheduled Notifications in the database, we need to send them. For this, we'll modify our Job:
app/Jobs/ProcessNotificationJob.php
use App\Notifications\BookingReminder1H;use App\Notifications\BookingReminder2H;use App\Notifications\BookingReminder5MIN;use App\Notifications\BookingStartedNotification; // ... public function handle(): void{ if ($this->notification->sent || $this->notification->tries >= config('app.notificationAttemptAmount')) { return; } if (!$this->notification->notifiable) { // Makes sure that the notifiable is still available $this->fail(); return; } try { switch ($this->notification->notification_class) { case BookingReminder1H::class: $this->notification->user->notify(new BookingReminder1H($this->notification->notifiable)); break; case BookingReminder2H::class: $this->notification->user->notify(new BookingReminder2H($this->notification->notifiable)); break; case BookingReminder5MIN::class: $this->notification->user->notify(new BookingReminder5MIN($this->notification->notifiable)); break; case BookingStartedNotification::class: $this->notification->user->notify(new BookingStartedNotification($this->notification->notifiable)); break; } $this->notification->update(['processing' => false, 'sent' => true, 'sent_at' => now()]); } catch (Exception $exception) { $this->fail($exception); }}
As you can see, we just need to add more cases to our switch
statement. And once that is done - our Notifications are going to be sent out.