• 컨트롤러 코드가 간결해진다.
  • 이벤트 처리 로직을 유연하게 확장하거나 축소할 수 있다.(여러 개의 이벤트 리스너)
  • 사용자에게 빠른 UI 응답을 제공한다.(무겁고 시간이 걸리는 일은 이벤트로 던져 다른 클래스에서 처리)


컨트롤러에 이벤트 던지기

app/Http/Controllers/ArticlesController.php

    public function store(\App\Http\Requests\ArticlesRequest $request)
    {

        $article = \App\User::find(1)->articles()->create($request->all());

        if(!$article){
            return back()->with('flash_message', '글이 저장되지 않았습니다.')->withInput();
        }

        dump('이벤트를 던집니다.');
        echo "<br>";
        event(new \App\Events\ArticleCreated($article));
        dump('이벤트를 던졌습니다.');
        echo "<br>";

        //return redirect(route('articles.index'))->with('flash_message', '작성하신 글이 저장되었습니다.');

    }

이벤트 레지스트리 채널 등록

app/Http/Providers/EventServiceProvider.php

    public function boot()
    {
        parent::boot();

        \Event::listen(
            \App\Events\ArticleCreated::class,
            \App\Listeners\ArticlesEventListener::class
        );
    }

listen() 첫번째 인자는 지정한 이벤트가 발생하면 두번째 인자의 클래스에게 처리를 위임한다라는 뜻이다.

 

위와 같이 등록한 후에 아래와 같이 입력하면  

php artisan event:generate

app/Events/ArticleCreated.php

app/Listeners/ArticlesEventListener.php

 2개의 파일이 생성된다.


이벤트 클래스 작성

app/Events/ArticleCreated.php

class ArticleCreated
{
    use InteractsWithSockets, SerializesModels;

    public $article;

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

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

이벤트 채널은 DTO(Data Transfer Object)다. 

다른 클래스가 DTO의 프로퍼티에 접근할 수 있게 public 로 선언하자.

__construct(\App\Article $article) 인자는 모델과 변수인 것 같다.


이벤트 리스너 클래스 작성

app/Listeners/ArticlesEventListener.php

<?php

namespace App\Listeners;

//use App\Events\article.created;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

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

    /**
     * Handle the event.
     *
     * @param  article.created  $event
     * @return void
     */
    public function handle(\App\Events\ArticleCreated $event)
    {
        dump('이벤트를 받았습니다. 받은 데이터(상태)는 다음과 같습니다.');
        dump($event->article->toArray());
    }
}

결과 화면 창


실용적인 이벤트 시스템

포럼 글이 작성되면 관리자에게 메일을 보낸다고 가정하자

컨트롤러에서 기존 이벤트를 던지는 코드는 삭제하고 주석처리했던 return 구문은 살리자.

그리고 새로운 이벤트의 이름으로 작성해주자 ArticleEvent

event(new \App\Events\ArticlesEvent($article));

이벤트 레지스트리 채널 등록

app/Http/Providers/EventServiceProvider.php

 \App\Events\ArticlesEvent::class 로 수정해주자

    public function boot()
    {
        parent::boot();

        \Event::listen(
            \App\Events\ArticlesEvent::class,
            \App\Listeners\ArticlesEventListener::class
        );
    }

이벤트 채널과 리스너 뼈대 코드 한 번에 만들기

php artisan event:generate

이벤트 클래스 뼈대만 만들기

php artisan make:event ArticlesEvent

\App\Listeners\ArticlesEventListener.php 는 이미 있기 때문에 ArticlesEvent 클래스만 생성된다.


이벤트 소스 작성

app/Events/ArticlesEvent.php

<?php

namespace App\Events;

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

class ArticlesEvent
{
    use InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public $article;

    public $action;

    public function __construct(\App\Article $article, $action = 'created')
    {
        $this->article = $article;
        $this->action = $action;
    }

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

이벤트 리스너 소스 작성

app/Listeners/ArticlesEventListener.php

<?php

namespace App\Listeners;

//use App\Events\article.created;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

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

    /**
     * Handle the event.
     *
     * @param  article.created  $event
     * @return void
     */
    public function handle(\App\Events\ArticlesEvent $event)
    {
        if($event->action === 'created'){
            \Log::info(sprintf(
                '새로운 포럼 글이 등록되었습니다.: %s',
                $event->article->title
            ));
        }
    }
}

포럼에 새 글을 작성해보자

http://localhost:8000/articles/create

storage/logs/laravel.log 에 가보면 마지막줄에 기록이 되었다.


라라벨 내장 이벤트 채널

 

마이그레이션 및 모델

php artisan make:migration add_last_ligin_column_on_users_table --table=users

database/migrations/TIMESTAMP_addadd_last_ligin_column_on_users_table.php

    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->timestamp('last_login')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('last_login');
        });
    }
php artisan migrate


app\User.php

class User extends Authenticatable
{
	protected $dates = ['last_login'];
}

이벤트 리스너

이벤트 레지스트리에 이벤트 채널과 리스너를 동록한다. 

사용자가 로그인하면 방출하는 라라벨 내장 이벤트는 Illuminate\Auth\Events\Login

이벤트를 소비할 APP\Listeners\UsersEventListener에 연결하자

    protected $listen = [
        \Illuminate\Auth\Events\Login::class => [
            \APP\Listeners\UsersEventListener::class
        ],
    ];

이벤트 채널 및 리스너 뼈대 코드 만들기

php artisan event:generate

app/Http/Listeners/UsersEventListener.php

    public function handle(Login $event)
    {
        $event->user->last_login = \Carbon\Carbon::now();
        return $event->user->save();
    }

로그인 창을 열어 로그인을 해보자

데이터가 제대로 입력이 되었다.

+ Recent posts