Igor Simic
3 years ago

How to make event, listener and notification in Laravel


How to generate event and listener inside of Laravel app? And on top of that send notification when event happens? 
That is what we will talk about in this post...


So, welcome stranger... Let's say we have next scenario: when someone wrote a comment on a post, we want to inform author of that post and let him know that he got new comment.
Logic to achieve this is simple, we will trigger event when comment is written, listener will accept the data and trigger notification.
Easy pease...

OK, first thing first, let's generate event and listener inside of our app. First we will define where are we going to place them. Open
Providers/EventServiceProvider.php  and let's define our event and listener, add these lines:
\App\Http\Modules\Comments\Events\CommentCreatedEvent::class => [
    \App\Http\Modules\Comments\Listeners\CommentCreatedListener::class,
],
NOTE: as you can see we are using kind of modular kind of approach for structuring the files, here you can read more about it.

Now when we have this created, lets run artisan command to generate these classes:
php artisan event:generate
This artisan will create Event and Listener in one go.

Now, open our newly created Event and let's add $data param which will be using to pass some data in a listener -> notification
<?php

namespace App\Http\Modules\Comments\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class CommentCreatedEvent
{
    use Dispatchable, InteractsWithSockets, SerializesModels;
    public $data;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($data) // <- add this param
    {
        //
        $this->data = $data;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}

Now let's go to our comment service and let' trigger our event. Open your service for writing the comments and just before you return the data to the user trigger event:

// ...
// your logic for adding the comment goes above

$created_comment_event_data = [

    'content_author' => $this->getCommentedContentAuthor($added_comment->id), // get author of the commented content
    'comment_data' => $added_comment

];

event( new CommentCreatedEvent($created_comment_event_data) );

// returning your comment back to frontend (or wherever you are returning it
return $added_comment;
And now in our listener, go to method handle and here we will grab the content author from $created_comment_event_data
 and send him notification informing him that he has now comment:
<?php

namespace App\Http\Modules\Comments\Listeners;

use App\Http\Modules\Auth_Module\Models\User;
use App\Http\Modules\Comments\Events\CommentCreatedEvent;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class CommentCreatedListener
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  CommentCreatedEvent  $event
     * @return void
     */
    public function handle(CommentCreatedEvent $event)
    {

        User::where('id',$event->data['content_author']->id)
            ->get()
            ->each(function($user) use ($event){
                $user->notify(new CommentNotification($event->data));
            });

    }
}

As you can see here we are already calling CommentNotification, so let's create it
 php artisan make:notification ../Http/Modules/Comments/Notifications/CommentCreatedNotification
And here is how our Notification looks like:
<?php

namespace App\Notifications\..\Http\Modules\Comments\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class CommentCreatedNotification extends Notification
{
    use Queueable;
    private $data;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct($data) // we need this to access passed data from listener
    {
        //
        $this->data = $data;
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['database']; 
    }

    /**
     * Get the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        return (new MailMessage)
                    ->line('The introduction to the notification.')
                    ->action('Notification Action', url('/'))
                    ->line('Thank you for using our application!');
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            'message' => $this->data->content_author->users->name.' commented your post',
            'comment' => $this->data->comment_data->body
        ];
    }
}