(jp) =
私の作品や Spatie の作品をフォローしている人は、私たちがいくつかのプロジェクトで使用しているパターンに出くわしたかもしれません。 これらを「アクション」と呼び、簡単に言えば、ビジネス ロジックをカプセル化するためのクラスです。
ドメインとアクションによってプロジェクトを構成する方法については、こちらを参照してください。また、集計プロジェクトのコードでアクションの例を見つけることができます。
アクションを使用した例を 1 つ挙げてみましょう: コントラクトの作成です。 契約を作成すると、モデルがデータベースに保存されるだけでなく、その契約の PDF も生成されます。
このアクションをプログラムする方法は次のとおりです。
class CreateContractAction
public function __construct(
GeneratePdfAction $generatePdfAction
)
public function execute(
ContractData $contractData
): Contract
$contract = Contract::createFromDTO($contractData);
$this->generatePdfAction->execute($contract);
return $contract->refresh();
DDD を知っている場合、アクションはコマンドとそのハンドラーを組み合わせたものと考えることができます。 このアプローチでは不十分なプロジェクトもありますが、非常に役立つ場合もあります。
このパターンには次の 3 つの利点があるため、このパターンをよく使用します。
- 個々のアクション クラスの単体テストは非常に簡単です。
- アクションは、依存関係コンテナーを介して他のアクションから構成できます。
- アクションにより、明確に定義されたコンテキストで考えることができ、認知負荷が軽減され、メンテナンス コストが削減されます。
詳細: アクションを非同期で実行したい場合があります。
この例の場合: コントラクトをすぐに作成したいのですが、PDF が生成されるまでユーザーを待たせたくありません。 これは非同期で行う必要があります。
以前は、アクションをジョブにラップしていました。 次のようになります。
class GeneratePdfJob implements ShouldQueue
use Dispatchable,
InteractsWithQueue,
Queueable,
SerializesModels;
public function __construct(
Contract $contract
)
public function handle(
GeneratePdfAction $generatePdfAction
)
$generatePdfAction
->execute($this->contract);
別のアクション内でアクションを直接呼び出す代わりに、新しいジョブをディスパッチします。
class CreateContractAction
public function execute(
ContractData $contractData
): Contract
dispatch(new GeneratePdfJob($contract));
これは問題なく動作しますが、アクションを手動でジョブにラップすることは、大規模なプロジェクトでは面倒なことになり始めました。
そのため、これを自動化する方法を検討し始めました。 そして確かなこと:私たちはできます!
これが GeneratePdfAction
パッケージを使用すると、次のようになります。
use Spatie\QueueableAction\QueueableAction;
class GeneratePdfAction
use QueueableAction;
public function __construct(
Renderer $renderer,
Browsershot $browsershot
)
public function execute(Pdfable $pdfable): void
$html = $this->renderer->render($pdfable);
$this->browsershot
->html($html)
->save($pdfable->getPath());
使用することで QueueableAction
、このアクションは非同期で実行できるようになりました。 使用方法は次のとおりです。
class CreateContractAction
public function execute(
ContractData $contractData
): Contract
$this->generatePdfAction
->onQueue()
->execute($contract);
上記には引き続き自動補完があることに注意することが重要です execute
メソッド、および DI サポート。 通常のアクションと同じように:
#ジョブズとの違いは?!?
アクションはコンストラクター注入を可能にします。つまり、アクション内のアクション内でアクションを使用できます。
一方、ジョブはコンテナ インジェクションを取得します。 handle
方法。 これは、依存関係コンテナーを介して他のジョブのジョブを構成できないことを意味します。
Laravel がジョブでコンストラクター注入を提供できない理由は明らかです。コントラクトなどのジョブ固有のデータは、ジョブをキューに入れるためにシリアル化する必要があり、コンストラクターはジョブに有効なデータがあることを確認する必要があります。
アクションの概念を導入することで、クラス間の責任をより適切に分離することができます。ジョブは、データのシリアル化とタスクの非同期実行に使用されます。 しかし、彼らはもうビジネス ロジックには関心がありません。
アクションがキューに入っているときにアクションをデバッグするのが難しい場合は、安心してください。
ActionJob
Horizon などにディスパッチされるクラスは、ラップするアクション クラスに名前が変更されます。
アクションをキュー可能にする基本的な詳細は、それらを使用する開発者には隠されているため、非同期コンテキストでも非常に簡単に操作できます。
私が言ったように、私たちはこれを小さなパッケージにしました. 単純な特性と ActionJob
. 試してみたい場合は、spatie/laravel-queueable-action で確認できます。