웹/모바일 개발/웹개발

[PHP laravel 5.7] 라라벨 이벤트(Event)와 큐(Queue) 그리고 메일 발송 [1]

라스모르 2019. 1. 2. 08:30

오늘은 라라벨에서 이벤트와 큐에 대해서 알아보도록 한다.


예전 포스팅에서 사용했던 태스크(Task) 프로젝트를 가지고 이벤트와 큐를 처리해보자. 




1. 이벤트(Event)와 리스너(Listener) 세팅


먼저 이벤트와 리스너를 정의한다. 여기서는 로그인한 사용자가 기등록한 태스크를 완료처리할 때를 이벤트 시점으로 정의하고 이때 해당 태스크를 등록한 사용자에게 태스크가 완료처리되었다는 이메일을 발송한다. 즉, 여기서 이벤트는 사용자가 태스크를 완료처리했을 때로 정의하고 이러한 이벤트가 발생하였을 때 리스너에서 해당 이벤트에 대해 메일을 발송하는 시나리오다.


기본적으로 라라벨에서 제공하는 php artisan 명령어를 이용해 이벤트 따로 리스너 따로 각각 생성하는데 여기서는 한 번에 이벤트와 그에 맞는 리스너를 생성해보자.


EventServiceProvider.php 파일을 열어 $listen 배열항목에 새로 생성할 이벤트와 리스너를 적어준다.


    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        
        'App\Events\TaskCompleted' => [
            'App\Listeners\SendEmailForCompletion'
        ],

    ];


우리는 태스크를 완료처리하는 이벤트로 TaskCompleted라는 이름의 이벤트를 정의하고 이 이벤트가 발생했을 때 이메일을 발송하는 SendEmailForCompletion이라는 이름의 리스너를 정의하였다. 


이렇게 정의하고 php artisan 명령어를 실행하면 한 번에 이벤트와 리스너 클래스가 생성된다. 


php artisan event:generate


event:generate 명령은 이벤트와 리스너를 정의한 EventServiceProvider 파일에서 세팅되지 않은 이벤트와 리스너를 찾아 생성하는 역할을 한다. 





2. 라라벨 이벤트(Laravel Event) 정의


이벤트를 정의해보자. 생성된 이벤트 파일(TaskCompleted.php)을 열어본다. 


<?php

namespace App\Events;

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

class TaskCompleted
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $task;

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

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

이벤트 클래스에서는 발생한 이벤트에 관련된 어떤 데이터든지 받을 수 있다. 


여기서는 태스크를 완료처리하는 시점의 이벤트이므로 이 시점에서 완료처리되는 태스크 모델 객체를 받아서 처리하려고 한다. 이를 위해 생성자에서 Task 모델의 eloquent 객체를 받도록 코드를 추가하였다.  


이벤트에서 건드릴 것은 이게 전부다.





3. 라라벨 리스너(Laravel Listener) 정의


리스너 파일을 열어 본다.

<?php namespace App\Listeners; use App\Events\TaskCompleted; use App\Jobs\SendEmailJob; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Mail; class SendEmailForCompletion { /** * Create the event listener. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param TaskCompleted $event * @return void */ public function handle(TaskCompleted $event) { Log::info(get_class($event) . ' 이벤트를 수신하였습니다.'); Log::info(sprintf('%s (%s)님에게 완료알림 메일을 보내려고 합니다', $event->task->user->name, $event->task->user->email)); } } ?>

handle 메소드에서 이벤트를 처리하는데 인자를 보면 TaskCompleted 이벤트의 객체를 받는 것을 볼 수 있다. 


앞서 이벤트 클래스를 보면 public 한정자를 갖는 $task 변수를 정의했었는데 리스너의 handler() 메소드에서는 인자를 통해 넘어온 $event 객체의 바로 이 task 속성을 이용하여 전송된 이벤트 데이터를 처리할 수 있게된다.


여기서는 단순히 넘어온 이벤트가 어떤 클래스의 이벤트인지를 출력하도록 하였다. 그리고 이벤트가 발생했을 때 완료처리된 해당 태스크 정보를 받아서 태스크의 작성자에게 완료메일을 보내려고 한다는 로그를 남기도록 하였다. 



로그인 사용자의 태스크에서 Complete 버튼을 클릭해보자. 그러면 TaskCompleted 이벤트가 발송한다.  그리고 EventServiceProvider에서 이 이벤트와 연결된 리스너를 찾아 handler() 메소드에서 정의한 처리로직이 실행될 것이다. 

여기서는 단순히 로그를 남기도록 하였으므로 태스크가 완료되었다는 플래시 메시지외에는 실제로 변경되는 부분은 없을 것이다.


[2018-12-28 11:06:46] local.INFO: App\Events\TaskCompleted 이벤트를 수신하였습니다.
[2018-12-28 11:06:46] local.INFO: Trystan Goldner (arlie.franecki@example.net)님에게 완료알림 메일을 보내려고 합니다


이것이 라라벨에서 이벤트와 리스너가 동작하는 방식이다. 


다음 포스팅에서는 이렇게 생성된 이벤트와 리스너에서 실제 메일을 발송하는 로직을 추가해보고 마지막에서는 이 로직을 큐를 이용하여 좀 더 빠르게 처리하는 예를 볼 것이다.