ホームページ >バックエンド開発 >PHPチュートリアル >Laravelのモデルイベントのガイド
Laravelのモデルイベントは、雄弁なモデルで特定の操作を実行するときにロジックを自動的に実行するのに役立つ非常に便利な機能です。ただし、不適切に使用すると、奇妙な副作用につながることがあります。
この記事では、モデルイベントとLaravelアプリケーションで使用する方法を調べます。また、モデルイベントを使用する際に注意するために、モデルイベントをテストする方法といくつかの問題を調べます。最後に、使用を検討できるモデルイベントの代替案について説明します。
「イベント」と「リスナー」を聞いたことがあるかもしれません。しかし、あなたがそれを聞いたことがないなら、それらの簡単な概要を次に示します:
これらは、行動するアプリで起こることです。たとえば、ユーザーはウェブサイトでサインアップしたり、ユーザーのログインなどです。
通常、Laravelでは、イベントはPHPクラスです。フレームワークまたはサードパーティパッケージによって提供されるイベントに加えて、通常、app/Events
ディレクトリに保存されます。
以下は、ユーザーがWebサイトに登録するときにスケジュールしたい単純なイベントクラスの例です。
上記の基本的な例では、コンストラクターのモデルインスタンスを受け入れるdeclare(strict_types=1); namespace App\Events; use App\Models\User; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; final class UserRegistered { use Dispatchable; use InteractsWithSockets; use SerializesModels; public function __construct(public User $user) { // } }イベントクラスがあります。このイベントクラスは、登録されたユーザーインスタンスを保存するためのシンプルなコンテナです。
派遣されると、イベントはそれを聞いているリスナーをトリガーします。 AppEventsUserRegistered
User
以下は、ユーザーが登録したときにイベントをスケジュールする方法の簡単な例です。
イベントをスケジュールしています。リスナーが正しく登録されていると仮定すると、これにより、
イベントで聞いているリスナーがトリガーされます。#listener
use App\Events\UserRegistered; use App\Models\User; $user = User::create([ 'name' => 'Eric Barnes', 'email' => 'eric@example.com', ]); UserRegistered::dispatch($user);
リスナーは、特定のイベントが発生したときに実行するコードのブロックです。 AppEventsUserRegistered
AppEventsUserRegistered
たとえば、ユーザー登録の例に固執する場合、ユーザーが登録されたときにユーザーにウェルカムメールを送信することができます。リスナーのイベントを作成して、ウェルカムメールを送信できます。
リスナーがユーザーのレジスタが次のようになる場合にウェルカムメールをユーザーに送信する例:
AppEventsUserRegistered
上記のコード例で見たように、
イベントインスタンスを受け入れるapp/Listeners
メソッドがあります。この方法は、ウェルカムメールをユーザーに送信する責任があります。
https://www.php.cn/link/d9a8c56824cfbe66f28f85edbbe83e09 モデルイベントとは何ですか?
ただし、LaravelでEloquentモデルを使用する場合、一部のイベントが自動的にスケジュールされるため、手動でスケジュールする必要はありません。イベントが発生したときに操作を実行したい場合は、リスナーを定義するだけです。
declare(strict_types=1); namespace App\Events; use App\Models\User; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; final class UserRegistered { use Dispatchable; use InteractsWithSockets; use SerializesModels; public function __construct(public User $user) { // } }次のリストには、雄弁さモデルによって自動的にスケジュールされたイベントとトリガーが表示されます。
取得 - データベースから取得。
作成 - モデルの作成。
creating
Laravelアプリケーションでこれらのモデルイベントを使用する方法を見てみましょう。 created
ing
ed
モデルイベントを聞いてください
モデルイベントをリッスンする1つの方法は、モデル上の
dispatchesEvents
より多くのコンテキストを提供するには、例を見てみましょう。 dispatchesEvents
と
。両方のモデルがソフト削除をサポートしていると言えます。新しいを保存するとき、コンテンツの長さに基づいて記事の読み取り時間を計算します。著者をそっと削除するとき、著者にすべての記事をそっと削除してもらいたいです。
#モデルをセットAppModelsPost
AppModelsAuthor
以下に示すようにAppModelsPost
モデルがある場合があります:
があります
dispatchesEvents
モデルイベントをdeleted
イベントクラスにマッピングするAppEventsAuthorDeleted
プロパティを追加しました。これは、モデルが削除された場合、新しいAppEventsAuthorDeleted
イベントがスケジュールされることを意味します。このイベントクラスを後で作成します。 posts
関係を定義します。 IlluminateDatabaseEloquentSoftDeletes
機能を使用して、モデルでソフト削除が有効になっています。 AppModelsPost
モデル:
declare(strict_types=1); namespace App\Events; use App\Models\User; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; final class UserRegistered { use Dispatchable; use InteractsWithSockets; use SerializesModels; public function __construct(public User $user) { // } }上記のモデルには、
AppModelsPost
dispatchesEvents
プロパティを追加しました。これは、モデルが作成または更新されたときに、新しいsaving
イベントがスケジュールされることを意味します。このイベントクラスを後で作成します。 AppEventsPostSaving
AppEventsPostSaving
author
IlluminateDatabaseEloquentSoftDeletes
イベントクラスを作成しましょう。 AppEventsAuthorDeleted
AppEventsPostSaving
#createイベントクラス
上記のコードでは、コンストラクターのモデルインスタンスを受け入れるAppEventsPostSaving
イベントクラスを見ることができます。このイベントクラスは、保存されている記事インスタンスを保存するためのシンプルなコンテナです。
use App\Events\UserRegistered; use App\Models\User; $user = User::create([ 'name' => 'Eric Barnes', 'email' => 'eric@example.com', ]); UserRegistered::dispatch($user);上記のクラスでは、コンストラクターが
モデルインスタンスを受け入れることがわかります。 AppEventsPostSaving
AppModelsPost
今では、リスナーを作成し続けることができます。
#createリスナーAppEventsAuthorDeleted
declare(strict_types=1); namespace App\Listeners; use App\Events\UserRegistered; use App\Notifications\WelcomeNotification; use Illuminate\Support\Facades\Mail; final readonly class SendWelcomeEmail { public function handle(UserRegistered $event): void { $event->user->notify(new WelcomeNotification()); } }
新しいAppEventsAuthorDeleted
リスナークラスを作成します:AppModelsAuthor
1つのメソッドのみがあります。これは、
イベントをスケジュールするときに自動的に呼び出されるメソッドです。保存されている記事を含む 属性を設定します。 モデルイベントがトリガーされたときに呼び出されるため、これは、作成または更新する前に記事がデータベースに持続するたびに
リスナークラスを作成できます: イベントクラスのインスタンスを受け入れます。このイベントクラスには、削除されている著者が含まれています。次に、 これを達成するために、より強力で再利用可能なソリューションを使用したいと思うかもしれないことは注目に値します。しかし、この記事の目的のために、私たちはそれをシンプルに保ちます。
モデルを更新することができます。
上記のモデルでは、モデルの などを使用できます。
上記の例で見たように、 関数で閉鎖を包みます。
ディレクトリに存在するクラスであり、聴きたいモデルイベントに対応するメソッドがあります。たとえば、 モデルイベントをリスニングするモデルのモデルオブザーバーを作成する方法を見てみましょう。
関係を使用して、著者の記事を削除します。 メソッドを実行するには、Laravelに使用するように指示する必要があります。これを行うには、 私は、リスナーロジックを定義するこの方法が本当に好きです。モデルクラスを開くときにオブザーバーを登録するかどうかをすぐに確認できるからです。したがって、ロジックはまだ別のファイルに「非表示」されていますが、モデルの少なくとも1つのイベントについてリスナーを登録していることがわかります。 上記の例で作成したモデルイベントをテストする方法を見てみましょう。 上記のテストでは、その著者の新しい著者と記事を作成しています。その後、著者をそっと削除し、著者と記事の両方がそっと削除されていると主張しました。 これは非常にシンプルだが効果的なテストであり、ロジックが期待どおりに機能することを確認するために使用できます。このテストの利点は、この記事で説明する各方法で動作することです。したがって、この記事で説明した方法のいずれかを切り替えた場合、テストに合格するはずです。 同様に、いくつかのテストを作成して、記事の読み取り時間が作成または更新時に計算されるようにすることができます。テストは次のようになるかもしれません: 2つのテストがあります: モデルイベントは、雄弁さモデルのみからスケジュールされます。これは、
たとえば、
上記のコードを実行すると、予想どおりデータベースから作成者が削除されます。ただし、 、
たとえば、 モデルイベントはその著者にはスケジュールされていません。 を考慮する代替方法
モデルが工場を介して作成されたときに、これら3つの操作もトリガーされます。もちろん、読み取り時間の計算は二次的なタスクであるため、それほど重要ではありません。ただし、テスト中にAPI呼び出しや通知を送信しようとはしません。これらは予期しない副作用です。テストを書いている開発者がこれらの副作用を認識していない場合、これらの操作が発生する理由を追跡することは困難かもしれません。 これは、自動モデルイベントに依存するのではなく、より明確なアプローチを検討したい場合の1つです。 1つの方法は、
ただし、このようなロジックにイベントやリスナーを使用したい場合は、より明確なアプローチを使用することを検討する場合があります。たとえば、サービスクラスからイベントをスケジュールして、リスナーをトリガーできます。このようにして、イベントやリスナーのデカップリングの利点を引き続き使用できますが、イベントがスケジュールされる時期をよりよく制御できます。 メソッドを更新できます。
上記の方法を使用することにより、APIリクエストを行い、Twitterに通知を送信するために別のリスナーを使用することができます。しかし、これらの操作がいつ実行されるかをより適切に制御できるため、モデルファクトリを使用してテストするときは実行されません。 これらの方法のいずれかを使用することを決定したときに黄金律はありません。それはすべて、あなた、あなたのチーム、そしてあなたが構築している機能に依存します。しかし、私は次の親指の規則に従う傾向があります:
AppListenersCalculateReadTime
このリスナーは、saving
属性が計算されることを意味します。 read_time_in_seconds
AppListenersSoftDeleteAuthorRelationships
declare(strict_types=1);
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
final class UserRegistered
{
use Dispatchable;
use InteractsWithSockets;
use SerializesModels;
public function __construct(public User $user)
{
//
}
}
メソッドはhandle
関係を使用して、著者の記事を削除します。 AppEventsAuthorDeleted
したがって、posts
delete
モデルがそっと削除されると、すべての著者の記事もゆっくりと削除されます。 AppModelsAuthor
使用できるもう1つの方法は、リスナーをモデル自体の閉鎖として定義することです。
著者を柔らかく削除したときに、ソフト削除記事の例を見てみましょう。モデルのモデルをリストに供給するようにAppModelsAuthor
メソッドでリスナーを定義していることがわかります。 deleted
モデルイベントを聴きたいので、use App\Events\UserRegistered;
use App\Models\User;
$user = User::create([
'name' => 'Eric Barnes',
'email' => 'eric@example.com',
]);
UserRegistered::dispatch($user);
モデルイベントのリスナーを作成したい場合は、booted
メソッドは、削除されているdeleted
を受信する閉鎖を受け入れます。この閉鎖は、モデルが削除されたときに実行されるため、すべての著者記事が削除されます。 self::deleted
created
モデルクラスを開くときにオブザーバーを登録するかどうかをすぐに確認できるため、リスナーロジックを定義するこの方法が本当に好きです。したがって、ロジックはまだ別のファイルに「非表示」されていますが、モデルの少なくとも1つのイベントについてリスナーを登録していることがわかります。ただし、これらの閉鎖のコードがより複雑になると、ロジックを別のリスナークラスに抽出する価値があります。 self::created
self::deleted
便利なトリックは、AppModelsAuthor
関数を使用してクロージャーをキューにすることもできることです。これは、リスナーのコードがキューに押し込まれ、同じリクエストライフサイクルではなく、バックグラウンドで実行されることを意味します。次のように、リスナーをqueuableに更新できます:IlluminateEventsqueueable
オブザーバーを使用してモデルイベントをリッスンします
モデルイベントを聞くために取ることができるもう1つの方法は、モデルオブザーバーを使用することです。モデルオブザーバーを使用すると、1つのクラスでモデルのすべてのリスナーを定義できます。 app/Observers
モデルイベントを聞きたい場合は、オブザーバークラスでdeleted
メソッドを定義します。 deleted
モデルイベントを聞きたい場合は、オブザーバークラスなどでcreated
メソッドを定義します。 created
AppModelsAuthor
上記のコードでわかるように、deleted
declare(strict_types=1);
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
final class UserRegistered
{
use Dispatchable;
use InteractsWithSockets;
use SerializesModels;
public function __construct(public User $user)
{
//
}
}
モデルのインスタンスを受け入れます。次に、deleted
たとえば、AppModelsAuthor
モデルイベントのリスナーも定義する必要があるとします。このようなオブザーバーを更新することができます:posts
delete
created
属性を使用できます。これにより、オブザーバーをモデルに関連付けることができます。これは、updated
属性を使用してグローバルクエリスコープを登録する方法と同様に(Laravelでクエリスコープをマスターする方法を理解することに示されています)。このようなuse App\Events\UserRegistered;
use App\Models\User;
$user = User::create([
'name' => 'Eric Barnes',
'email' => 'eric@example.com',
]);
UserRegistered::dispatch($user);
AppObserversAuthorObserver
#[IlluminateDatabaseEloquentAttributesObservedBy]
モデルイベントをテストします#[ScopedBy]
AppModelsAuthor
declare(strict_types=1);
namespace App\Listeners;
use App\Events\UserRegistered;
use App\Notifications\WelcomeNotification;
use Illuminate\Support\Facades\Mail;
final readonly class SendWelcomeEmail
{
public function handle(UserRegistered $event): void
{
$event->user->notify(new WelcomeNotification());
}
}
最初にテストを書き、著者が柔らかく削除されたときに著者の記事が柔らかく削除されるようにします。テストは次のようになるかもしれません:
declare(strict_types=1);
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
final class UserRegistered
{
use Dispatchable;
use InteractsWithSockets;
use SerializesModels;
public function __construct(public User $user)
{
//
}
}
モデルイベントを使用する場合の予防策
モデルイベントは非常に便利ですが、使用する際に注意すべき問題がいくつかあります。
IlluminateSupportFacadesDB
簡単な例を見てみましょう。IlluminateSupportFacadesDB
およびuse App\Events\UserRegistered;
use App\Models\User;
$user = User::create([
'name' => 'Eric Barnes',
'email' => 'eric@example.com',
]);
UserRegistered::dispatch($user);
同様に、モデルの更新または削除にEloquentを使用して使用する場合、影響を受けるモデルのためにdeleting
、deleted
、およびsaved
次のコードを使用して著者を削除するとします。
updated
deleting
deleted
メソッドはクエリビルダーで直接呼び出されるため、declare(strict_types=1);
namespace App\Listeners;
use App\Events\UserRegistered;
use App\Notifications\WelcomeNotification;
use Illuminate\Support\Facades\Mail;
final readonly class SendWelcomeEmail
{
public function handle(UserRegistered $event): void
{
$event->user->notify(new WelcomeNotification());
}
}
delete
deleting
プロジェクトでモデルイベントを使用するのが好きです。モデルに影響を与えるコードをあまり制御できないときに、コードを切り離し、ロジックを自動的に実行できるようにする良い方法として機能します。たとえば、Laravel Novaで著者を削除した場合、著者を削除するときにロジックを実行できます。 deleted
これを説明するために、モデルイベントの使用を避けたい基本的な例を見てみましょう。新しい投稿を作成するときに以下を実行したいと仮定して、以前の簡単なブログアプリケーションの例を拡張します。
記事の読み取り時間を計算します。 したがって、新しい
declare(strict_types=1);
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
final class UserRegistered
{
use Dispatchable;
use InteractsWithSockets;
use SerializesModels;
public function __construct(public User $user)
{
//
}
}
上記のテストを実行すると、AppModelsPost
また、リスナーにテスト固有のロジックを作成することを避けたいと考えています。これにより、これらの操作がテスト中に実行されないようにします。これにより、アプリケーションコードがより複雑で維持が難しくなります。 AppModelsPost
上記のクラスでは、読み取り時間を計算し、通知を送信し、Twitterに投稿するコードを手動で呼び出しています。これは、これらの操作がいつ実行されるかをより適切に制御できることを意味します。また、これらの方法をテストで簡単にock笑して、実行しないようにすることもできます。必要に応じて、これらの操作をキューすることができます(この場合、おそらくそうするでしょう)。 use App\Events\UserRegistered;
use App\Models\User;
$user = User::create([
'name' => 'Eric Barnes',
'email' => 'eric@example.com',
]);
UserRegistered::dispatch($user);
クラスを使用し、テストコードでモデルファクトリを安全に使用できることを意味します。 AppServicesPostService
たとえば、AppServicesPostService
モデルイベントを使用することの長所と短所
この記事で紹介したものをすばやく要約するために、モデルイベントを使用することの利点と短所のいくつかを次に示します。
#prosコードを切り離すことをお勧めします。
モデルの作成/更新/削除の場所に関係なく、アクションを自動的にトリガーできます。たとえば、モデルがLaravel Novaで作成された場合、ビジネスロジックをトリガーできます。
予期しない副作用を引き起こす可能性があります。リスナーをトリガーすることなく、モデルを作成/更新/削除することもできますが、これは予期しない動作につながる可能性があります。これは、テストを書くときに特に問題があります。
ビジネスロジックは、追跡が難しい予期しない場所に隠されている場合があります。これにより、コードの流れがより困難になります。
この記事が、モデルイベントが何であるか、それらを使用するさまざまな方法の概要を提供することを願っています。また、モデルイベントコードをテストする方法と、使用する際に注意するいくつかの問題を示す必要があります。
Laravelアプリケーションでモデルイベントを使用するのに十分な自信があるはずです。
以上がLaravelのモデルイベントのガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。