Event 클라스 DI해서 사용하기

라라벨에서 사용자 이벤트를 사용하려면 이미 존재하는 Event Facade를 사용하면 쉽게 사용할수 있습니다.

// aEvent라는 이벤트를 listen
Event::listen("aEvent", function($eventData)
{
    var_dump($eventData);
});

// aEvent fire..
Event::fire('aEvent', ['test']);

이 방법으로 사용하면 사용이 편하긴 한데..컨트롤러 같은 어플리케이션 레이어가 아닌 도메인 레이어에서 사용할 때는 많이 꺼려집니다. 일반 클라스에서 Dependency Injection을 사용해서 Event 클라스를 사용하는 방법을 팁으로 적어 보겠습니다.

2가지를 해보겠습니다.

  1. 이벤트 프로바이더를 만들어서 라라벨 Event Facade의 실제 클라스인 Illuminate\Events\Dispatcher를 IoC 컨테이너에 바인딩하고 이벤트 리스너를 등록.
  2. 예제로 CartItemAdded 이벤트를 만들고 CartItemAddedHandler를 만들도록 하겠습니다.

이벤트 프라바이더 만들기

사용자 프로바이더를 만들기 위해서 사용자 폴더(?)를 만들겠습니다.

app폴더 안에 lib\Acme 폴더를 만들어 줍니다.

app
    lib
       Acme

Acme 폴더안에 EventHandlers, Events, Providers 폴더를 만듭니다.

app
    lib
       Acme
           EventsHandlers
           Events
           Providers

Providers안에 Events.php를 만들고 내용은 아래처럼 합니다

<?php namespace Acme\Providers;

use Illuminate\Support\ServiceProvider;

class Events extends ServiceProvider
{
    public function register()
    {

        $dispatcher = new \Illuminate\Events\Dispatcher;
        $this->app->instance('Illuminate\Events\Dispatcher', $dispatcher);

        $dispatcher->listen("CartItemAdded", "Acme\EventHandlers\CartItemAddedHandler");

    }
}

Events 폴더에 CartItemAdded.php르 만들고 내용은 아래처럼 합니다.

<?php namespace Acme\Events;

class CartItemAdded
{
    public function __construct($productName)
    {
        $this->productName = $productName;
    }

    public function getProductName()
    {
        return $this->productName;
    }
}

마찬가지로 EventHandlers에도 CartItemAddedHandler.php를 만들고 내용은 아래처럼 합니다. 라라벨에 이벤트 등록할때 클로져가 아닌 string을 넘겨주면 클라스로 간주하고 클라스에서 handle 메소드를 불러줍니다.

<?php namespace Acme\EventHandlers;

use Acme\Events\CartItemAdded;

class CartItemAddedHandler
{
    public function handle(CartItemAdded $eventMessage)
    {
        var_dump($eventMessage->getProductName());
    }
}

이제 lib/Acme를 오토로더에 등록해줘야 합니다.

composer.json을 열고고 autoload키에 아래 내용을 추가해 줍니다.

"psr-0": {
    "Acme": "app/lib"
}

autoload키의 전체 내용은 이렇습니다.

"autoload": {
    "classmap": [
        "app/commands",
        "app/controllers",
        "app/models",
        "app/database/migrations",
        "app/database/seeds",
        "app/tests/TestCase.php"
    ],
    "psr-0": {
        "Acme": "app/lib"
    }
}

터미널로 가서 composer dump-auload 한번 실행해 줍니다.

이제 테스트를 해보겠습니다. 간단하게 Route에서 하겠습니다.

Cart라는 도메인 오브젝트가 있을때 아래처럼 사용하시면 됩니다.

Route 내용

use Illuminate\Events\Dispatcher as EventDispatcher;
use Acme\Events\CartItemAdded;

class Cart 
{

    protected $dispatcher;

    public function __construct(EventDispatcher $eventDispatcher)
    {
        $this->dispatcher = $eventDispatcher;
    }

    public function addItem($productName)
    {
        // do something here


        // fire event
        $this->dispatcher->fire('CartItemAdded', new CartItemAdded($productName));
    }

}


Route::get('/', function()
{

    $Cart = App::make('Cart');
    $Cart->addItem('this is a test');

});
comments powered by Disqus