15
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Laravelでイベントとリスナーを使ってみる

Last updated at Posted at 2020-03-26

#イベントとは
プログラムから何らかの操作があった際などに処理を実行する仕組です
イベントを発行することでイベントクラスを呼び出すことができ
イベント自体に処理はなく、イベントでは主に値を扱いその値をリスナーへと受け渡します

#リスナーとは
発生したイベントを受け取りイベントの発生を監視しているのがリスナー
リスナーで実際に処理が行われ
リスナーはイベント毎に作成し登録する必要があります

#イベントを利用する方法
イベントを利用するには、イベントクラスとそれに対応するリスナークラスを作成すし登録する必要があり
そして、必要に応じてイベントを発行すればそのイベントを受け取るイベントリスナーの処理が実行される仕組みになります

#イベントとリスナーを作成する
イベントクラスとイベントリスナークラスを作成するには
providersEventServiceProviderを利用します
EventServiceProvider.phpには$listenboot()メソッドが用意されています
イベントクラスとイベントリスナークラスの作成には$listenを使用します

EventServiceProvider.php
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        'App\Events\ItemEvent' => [
            'App\Listeners\ItemEventLister'
        ]
    ];

今回はこのように記述しておきます
次に、下記コマンドを実行します

$ php artisan event:generate

このコマンドの実行により、$lintenに登録したイベントクラスとイベントリスナークラスが自動的に作成されます
イベントクラスはapp/Eventsファオルだに作成され
イベントリスナークラスはapp\Listnersフォルダに作成されます

それでは実際に作成された2つのファイルの構成を見ていきます

#イベントクラスの構成
ItemEventクラスは下記のようになっています

ItemEvent.php
<?php

namespace App\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 ItemEvent
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct()
    {
       //
    }

    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}

イベントクラス内には様々なトレイトが用意されているのと
またメソッドは__construct()broadcastOn()の二つのメソッドが用意されていますが
基本的には、イベントは値を扱うのがメインになりますので__construct()以外はほとんと使用しません
忘れてはいけないのは、イベントクラスは値を扱うのが仕事なので処理などは必要ないです

次に、イベントリスナークラスの構成を見てみます

#イベントリスナークラスの構成
ItemEventListerクラスは下記のようになっています

ItemEventLister.php

use App\Events\ItemEvent;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

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

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

イベントリスナークラスにはhandle()メソッドと__construct()の二つが用意されています
リスナーは処理をする役割があるので、処理を記述するのがhandle()メソッドになります
引数にはイベントクラスのインスタンスが渡されており、この引数からイベントで管理していた値にアクセスすることができます
また、このhandle()メソッドが、イベント発生時に呼び出されます

次にイベントを発行するにはどうすれば良いのかです

#イベントの発行
イベントを発行するのは簡単で下記のようにすることでイベントを発行できます

event(new ItemEvent(値));

ここまでで、イベントクラスとイベントリスナークラスの作成とイベントの発行方法など基本を説明しました
次にこれからを使って実際にイベント発行から値を受け取り、リスナーで処理を実行してみるサンプルを作成してみます

#サンプル機能の作成
前での説明で使用した際に作成したItemEventクラスとItemEventListerクラスを引き続き使っていきます
まずは今回のサンプルで使用するItemモデル、シーダ、マイグレーション、コントローラーを作成していきます

$ php artisan make:model Item --all

これでモデル、シーダ、マイグレーション、コントローラーが作成できました
最初にマイグレーションの記述を行います
下記のようにしてください

create_items_talbe.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateItemsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('items', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('items');
    }
}

マイグレーション実行します

$ php artisan migrate

次にシーダファイルを下記のように修正

ItemSeeder.php
<?php

use Illuminate\Database\Seeder;

class ItemSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $param = [
            'name' => 'りんご'
        ];

        DB::table('items')->insert($param);

        $param = [
            'name' => 'ばなな'
        ];

        DB::table('items')->insert($param);

        $param = [
            'name' => 'ぶどう'
        ];

        DB::table('items')->insert($param);
    }
}

シーダを実行します

$ php artisan db:seed

これでitemsテーブルに3件おダミーデータが用意できたかと思います

次にコントローラーを作成します
ここでイベントを使用します
ItemControllerが作成されていると思いますがリソースコントローラーなので今回は使わずに新たに作成します

$ php artisan make:controller MainController

MainControllerを修正していきます

MainController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Item;    //Itemモデルをuse
use App\Events\ItemEvent;    //ItemEventクラスをuse

class MainController extends Controller
{
    public function index()
    {
        return view('main.index');
    }

    public function item(Item $item)
    {
        event(new ItemEvent($item));    //イベント発行

        return redirect()->route('index');
    }
}

上記のコントローラーのitem()アクションでイベントを発行する処理をしています

次にルートの定義をしていきます

web.php
<?php

use Illuminate\Support\Facades\Route;

Route::get('/item}', 'MainController@item')->name('item');
Route::get('/', 'MainController@index')->name('index');

2つ追加できました

次にresourcesmainフォルダを作成しindex.blade.phpを作成してください
中身はこんな感じにしておきます

index.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>ユーザー表示</title>
</head>
<body>
    イベントとリスナー
</body>
</html>

ここまでで必要な準備が終わりです
イベントも発行してるのであとはそのイベントの処理を用意するだけになります

ItemEventを修正していきます

ItemEvent.php
<?php

namespace App\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 ItemEvent
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $item;

    public function __construct($item)
    {
        $this->item = $item;
    }

    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}

public $itemとしてItemのインスタンスを保管しておくプロパティを用意しています
__constructで引数で渡された$itemを利用してます
この引数の$itemMainControlleritem()アクションでイベント発行してる際に引数で渡されている値です
この部分ですevent(new ItemEvent($item))
ここで受け取ったItemの情報をイベントに渡してイベント側でそれを値として扱っています

次にイベントリスナークラスの修正をします

ItemEventLister.php
<?php

namespace App\Listeners;

use App\Events\ItemEvent;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Storage;

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

    /**
     * Handle the event.
     *
     * @param  ItemEvent  $event
     * @return void
     */
    public function handle(ItemEvent $event)
    {
        Storage::append('item_accesslog.txt', '[Item]' . now() . '' . $event->item->name);
    }
}

簡単に説明すると、item_accesslog.txtというファイルに[item]+ 現在の時間 + ユーザーの名前の形で
書き出すということを処理しているリスナーになります
ちなみに、item_accesslog.txtファイルは作ってませんがそのファイルがなければ自動的にstorage/appに作成されます

これでサンプルの実装は完了です
ブラウザから/1とURLを叩いてみてください
そうすると、storage/app/item_accesslog.txt[Item]現在の時間 りんごと書き出しされているかと思います

一連の流れを簡単に説明すると

  • URLで指定された番号のItemの情報がMainControlleritem()アクションの引数で渡される
  • item()アクションの中のイベント発行の際にその値を渡してあげる
  • その値を受け取ったイベントクラスであるItemEventがその値を__constructを使って保管している
  • そのイベント発行により呼び出されたイベントリスナーItemEventListerhandle()メソッドが処理を実行してファイルに書き出しを行っている

こんな感じです
これが一連のイベント作成からイベント発行しリスナーに処理をさせるまでになります

またイベントをキューに登録して実行させることもできます

#キューを利用する
発行したイベントをキューテーブルに登録し処理したい場合は
イベントリスナークラスにてインターフェースを実装するだけで利用ができます
今回の場合だとItemEventListerクラスになります

namespace App\Listner;

class ItemEventLister implements ShouldQueue
{
    //省略
}
15
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?