Eloquentのイベント関数について

Laravelベストプラクティスの[この部分](https://github.com/alexeymezenin/laravel-best-practices/blob/master/japanese.md#:~:text=Eloquent%E3%81%AB%E3%81%AF%E8%AB%96%E7%90%86%E5%89%8A%E9%99%A4%E3%80%81%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%80%81%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%97%E3%81%AA%E3%81%A9%E3%81%AE%E5%84%AA%E3%82%8C%E3%81%9F%E7%B5%84%E3%81%BF%E8%BE%BC%E3%81%BF%E3%83%84%E3%83%BC%E3%83%AB%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82)が気になった
コレってなんだろう？使ったことないなと思って調べてみました

## Eloquentにおけるイベントの概念
Eloquentモデルは、ライフサイクルの特定のポイントでイベントを発生させることができます
これにより、モデルの状態に応じて自動的に特定の処理を実行することが可能です
一般的なEloquentイベントには、
- `creating`
- `create`
- `updating`
- `updated`
- `deleting`
- `deleted`
- `saving`
- `saved`

などがあります

## メリット、デメリット
### メリット
- コードの整理
    - モデルのライフサイクルに関連するロジックをモデル内にまとめることで、コードの処理ができます
- 自動処理
    - データベース操作の前後で自動的に特定の処理を実行できます
- 再利用性
    - 一度定義したイベントロジックを複数の箇所で再利用できます
- デメリット
    - 複雑さの増加
        - 多くのイベントを使用すると、モデルのロジックが複雑になり、理解しにくくなることがあります
            - 初見で見た時はわからなくなりそうです
    - パフォーマンスへの影響
        - 上にイベントを使用すると、パフォーマンスに悪影響を与える可能性があります

## イベントを使う場面
- データの検証や加工
    - データの保存前に特定の検証や加工を行いたい場合
        - creatingとかsavingとかで実現できます
    - ログの記録
        - データの変更履歴を記録したい場合
    - 通知の送信
        - データの変更に応じて通知を送信したい場合

## イベントを使う場面において実際に使う場合と使わない場合の違い
### 使う場合
```php
class User extends Model
{
    protected static function booted()
    {
        static::created(function ($user) {
            // ユーザー作成時にメール送信
            Mail::to($user->email)->send(new WelcomeMail($user));
        });
    }
}
```
`created`イベントが成功した場合に、関数内の処理（この場合はメール送信）が実行されます

### 使わない場合
```php
class UserController extends Controller
{
    public function store(Request $request)
    {
        $user = User::create($request->all());
        // ユーザー作成後にメール送信
        Mail::to($user->email)->send(new WelcomeMail($user));
    }
}
```

## イベントの実装方法
### イベントの作成
まず、イベントを作成します
例えば、ユーザーが作成されたときのイベントを作成するには、以下のコマンドを実行します

```bash
php artisan make:event UserCreated
```
### イベントの内容を設定
生成されたイベントファイル（`app/Events/UserCreated.php`)を編集します

```php
<?php

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UserCreated
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    // ユーザーを保持するプロパティを追加
    public $user;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct(User $user)
    {
        // プロパティにユーザー情報を代入
        $this->user = $user;
    }
}
```

### イベントリスナーの作成
イベントリスナーを作成するには、以下のコマンドを使用します

```bash
php artisan make:listener SendWelcomeEmail
```

### イベントリスナーの内容を設定
生成されたリスナーファイル（`app/Listeners/SendWelcomeEmail.php`）を編集します
以下のコードでは、`handle`メソッド内でメールを送信する処理を追加しています

```php
<?php

namespace App\Listeners;

use App\Events\UserCreated;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Mail;
use App\Mail\WelcomeMail;

class SendWelcomeEmail
{
    /**
     * Handle the event.
     *
     * @param  UserCreated  $event
     * @return void
     */
    public function handle(UserCreated $event)
    {
        // メール送信処理を追加
        Mail::to($event->user->email)->send(new WelcomeMail($event->user)); ここを編集
    }
}
```

### イベントリスナーの登録
`EventServiceProvider`にイベントリスナーを登録します
`app/Providers/EventServiceProvider.php`を編集します

```php
protected $listen = [
    'App\Events\UserCreated' => [
        'App\Listeners\SendWelcomeEmail', // 登録したイベントを追加
    ],
];
```


### モデルにイベントを定義
モデルでイベントを定義します
`app/Models/User.php`を編集します

```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Events\UserCreated;

class User extends Model
{
    protected $dispatchesEvents = [
        'created' => UserCreated::class, ここに登録したイベントを追加
    ];
}

```

### コントローラでイベントを発火
モデルで定義したイベントをコントローラで発火させます

```php
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function store(Request $request)
    {
        // ユーザーを作成すると、`created`イベントが自動的に発火します。
        $user = User::create($request->all());

        return response()->json(['message' => 'User created successfully', 'user' => $user]);
    }
}
```
上記では、`User::create`メソッドが呼ばれると、`created`イベントが自動的に発火し、関連するリスナー（`SendWelComeEmail`)が実行されます

## 実際の現場ではどのような場面で使っているのか
- 通知の送信
    - ユーザー登録後のウェルカムメール送信
- データの監査
    - データベースの変更履歴をログに記録

## まとめ
Eloquentのイベントは、モデルのライフサイクルに応じた処理を簡潔に実装するための強力なツールです
適切に使用することで、コードの整理、再利用性の向上、自動化された処理の実現が可能になります
ただし、過度な使用は複雑さやパフォーマンスへの影響を引き起こす可能性があるため、適切なバランスを保つことが重要になるかと思います