#イベントとは
プログラムから何らかの操作があった際などに処理を実行する仕組です
イベントを発行することでイベントクラスを呼び出すことができ
イベント自体に処理はなく、イベントでは主に値を扱いその値をリスナーへと受け渡します
#リスナーとは
発生したイベントを受け取りイベントの発生を監視しているのがリスナー
リスナーで実際に処理が行われ
リスナーはイベント毎に作成し登録する必要があります
#イベントを利用する方法
イベントを利用するには、イベントクラスとそれに対応するリスナークラスを作成すし登録する必要があり
そして、必要に応じてイベントを発行すればそのイベントを受け取るイベントリスナーの処理が実行される仕組みになります
#イベントとリスナーを作成する
イベントクラスとイベントリスナークラスを作成するには
providers
のEventServiceProvider
を利用します
EventServiceProvider.php
には$listen
とboot()
メソッドが用意されています
イベントクラスとイベントリスナークラスの作成には$listen
を使用します
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
'App\Events\ItemEvent' => [
'App\Listeners\ItemEventLister'
]
];
今回はこのように記述しておきます
次に、下記コマンドを実行します
$ php artisan event:generate
このコマンドの実行により、$linten
に登録したイベントクラスとイベントリスナークラスが自動的に作成されます
イベントクラスはapp/Events
ファオルだに作成され
イベントリスナークラスはapp\Listners
フォルダに作成されます
それでは実際に作成された2つのファイルの構成を見ていきます
#イベントクラスの構成
ItemEvent
クラスは下記のようになっています
<?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
クラスは下記のようになっています
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
これでモデル、シーダ、マイグレーション、コントローラーが作成できました
最初にマイグレーションの記述を行います
下記のようにしてください
<?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
次にシーダファイルを下記のように修正
<?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
を修正していきます
<?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()
アクションでイベントを発行する処理をしています
次にルートの定義をしていきます
<?php
use Illuminate\Support\Facades\Route;
Route::get('/item}', 'MainController@item')->name('item');
Route::get('/', 'MainController@index')->name('index');
2つ追加できました
次にresources
にmain
フォルダを作成し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
を修正していきます
<?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を利用してます
この引数の$item
はMainController
のitem()
アクションでイベント発行してる際に引数で渡されている値です
この部分ですevent(new ItemEvent($item))
ここで受け取ったItemの情報をイベントに渡してイベント側でそれを値として扱っています
次にイベントリスナークラスの修正をします
<?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の情報が
MainController
のitem()
アクションの引数で渡される -
item()
アクションの中のイベント発行の際にその値を渡してあげる - その値を受け取ったイベントクラスである
ItemEvent
がその値を__construct
を使って保管している - そのイベント発行により呼び出されたイベントリスナー
ItemEventLister
のhandle()
メソッドが処理を実行してファイルに書き出しを行っている
こんな感じです
これが一連のイベント作成からイベント発行しリスナーに処理をさせるまでになります
またイベントをキューに登録して実行させることもできます
#キューを利用する
発行したイベントをキューテーブルに登録し処理したい場合は
イベントリスナークラスにてインターフェースを実装するだけで利用ができます
今回の場合だとItemEventLister
クラスになります
namespace App\Listner;
class ItemEventLister implements ShouldQueue
{
//省略
}