[Laravel] Event handling
이벤트 다루기
Laravel의 이벤트는 간단한 관찰자(observer) 패턴 구현을 제공하여 애플리케이션 내에서 발생하는 다양한 이벤트를 구독(subscribe)하고 수신(listen)할 수 있습니다. 이벤트 클래스는 일반적으로 app/Events 디렉토리에 저장되고 해당 리스너는 app/Listeners에 저장됩니다.
처음 라라벨 이벤트를 접하다보면 약간 어려운 개념일 수도 있는데 회원가입시 event를 발생시키고 리스너에서는 이 이벤트를 받아서 회원가입메일이나 기타 sms 등을 전송할 수 있으므로 코드를 간략하게 하는데 도움이 되면 queue와 함께 사용할경우는 이메일발송이나 http request와 같은 slow task(시간적 지연이 발생하는 작업)에 유리합니다.
여기서는 회원가입메일과 관련하여 간단한 이벤트를 만들어 보겠숩니다.
먼저 Event를 발생시키는 클래스와 그것을 수신하는 클래스를 만들어 보겠습니다.
이벤트 및 리스너 만들기
php artisan make:event Registered
php artisan make:listener SendRegisteredNotification --event=Registered
위와 같이 artisan 명령을 주게되면 아래와 같이 각각 만들어 집니다.
- app > Events > Registered.php
namespace App\Events;
..........
class Registered
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct()
{
//
}
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
- app > Listeners > SendRegisteredNotification.php
namespace App\Listeners;
use App\Events\Registered; // 위에서 생성한 Registered 를 받음
..........
class SendRegisteredNotification
{
public function __construct()
{
//
}
public function handle(Registered $event)
{
//
}
}
이벤트 등록하기
자동으로 등록하기
event와 listener가 각각 app/Events 및 app/Listeners 에 등록된 경우 아래와 같이 처리하면 자동으로 등록됩니다.
- app/Providers/EventServiceProvider.php
..........
class EventServiceProvider extends ServiceProvider
{
..........
public function shouldDiscoverEvents()
{
return true; // 기본값은 false 입니다.
}
}
수동으로 등록하기
약속된 위치에 존재 하지 않을 경우는 수동으로 등록하여야 하는데 이 부분은 laravel의 버전마다 조금씩 차이가 납니다.
- ver 8.x
app/Providers/EventServiceProvider.php
namespace App\Providers;
..........
use App\Events\Registered as MarketRegistered;
use App\Listeners\SendRegisteredNotification;
class EventServiceProvider extends ServiceProvider
{
..........
public function boot()
{
Event::listen(
MarketRegistered::class,
[SendRegisteredNotification::class, 'handle']
);
Event::listen(function (MarketRegistered $event) {
//
});
}
}
등록된 이벤트 확인
등록된 이벤트를 확인하기위해 아래 명령어를 입력합니다.
$ php artisan event:list
+-----------------------------------+-------------------------------------------------------------+
| Event | Listeners |
+-----------------------------------+-------------------------------------------------------------+
| App\Events\Registered | App\Listeners\SendRegisteredNotification@handle |
| Illuminate\Auth\Events\Registered | Illuminate\Auth\Listeners\SendEmailVerificationNotification |
+-----------------------------------+-------------------------------------------------------------+
상호작용
이벤트는 등록되었으므로 이제는 controller에서 event를 호출하는 법과 실제 listener에서 처리하는 방법을 간략하게 설명 드리겠습니다.
controller
..........
use App\Events\Registered;
class RegisterController extends Controller
{
..........
/**
* 회원가입
*/
public function store(Request $request)
{
..........
$user
Registered::dispatch($user);
// event(new Registered($user)); // dispatch 와 동일
}
}
- app > Events > Registered.php
namespace App\Events;
..........
class Registered
{
..........
public $user;
public function __construct($user)
{
$this->user = $user;
}
}
- app > Listeners > SendRegisteredNotification.php
namespace App\Listeners;
use App\Events\Registered;
..........
class SendRegisteredNotification
{
public function handle(Registered $event)
{
// $event->user 를 이용하여 $user에 대한 정보를 수신후 메일, sms, sns 등을 처리하면 된다.
}
}
subscriber
subscriber를 사용할 경우 다양한 이벤트를 한군데서 다룰 수 있는 장점이 있다.
- app/Providers/EventServiceProvider.php
use App\Listeners\UserEventSubscriber;
..........
class EventServiceProvider extends ServiceProvider
{
..........
protected $subscribe = [
UserEventSubscriber::class,
];
}
- App\Listeners\UserEventSubscriber.php
로그인, 로그아웃, 회원가입등에 대한 예인데 여기서는 회원가입에 대해서만 설명 드리겠습니다.
<?php
namespace App\Listeners;
use Illuminate\Auth\Events\Login;
use Illuminate\Auth\Events\Logout;
use App\Events\Registered;
class UserEventSubscriber
{
public function __construct()
{
}
/**
* Handle user login events.
*/
public function handleUserLogin($event) {}
/**
* Handle user logout events.
*/
public function handleUserLogout($event) {}
public function handleUserRegister($event) {
// 실행
}
/**
* Register the listeners for the subscriber.
*
* @param \Illuminate\Events\Dispatcher $events
* @return array
*/
public function subscribe($events)
{
return [
Login::class => 'handleUserLogin',
Logout::class => 'handleUserLogout',
Registered::class => 'handleUserRegister',
];
}
}
- controller
사용법은 단일 event를 listen 할때와 동일하다.
..........
use App\Events\Registered;
class RegisterController extends Controller
{
..........
/**
* 회원가입
*/
public function store(Request $request)
{
..........
$user
Registered::dispatch($user);
// event(new Registered($user)); // dispatch 와 동일
}
}
event vs job
라라벨에서 제공하는 event(with listener)와 job은 매우 유사한 기능을 제공합니다.
차이점이라면 job은 하나의 작업을 처리하고 event는 하나의 event로 다수의 작업이 가능하다는 것입니다. 물론 프로그램하기 나름이겠지만...