例として
会員情報の更新時に、条件に応じてメール送信する。
まずはこんな実装を考えてみましょう。
- コントローラー内でメール送信に該当するか判定する。
- 該当する場合は、メール送信用のサービスクラスを呼ぶ。
class UpdateMyInfoController extends Controller
{
/**
* 会員情報を更新
*/
public function __invoke(
UpdateMyInfoRequestData $requestData,
UpdateMyInfoService $updateMyInfo,
UpdateMyInfoMailService $updateMyInfoMail,
) {
// 会員情報を更新
$updateMyInfo->execute(
$requestData,
);
// 条件に応じてメール送信
if ($requestData->acceptMailMagazine) { // 👈 ここの条件分岐に注目
$updateMyInfoMail->execute(
$requestData,
);
}
// レスポンス
return response()->json();
}
}
コントローラー内に条件分岐が実装されていることに注目してください。
設計思想は多々ありますし、そんなに悪くないです。メール送信条件も明確です。
私なりの工夫
一方で「メール送信の条件に該当するかどうかを判別するのは、コントローラーの役割りではない。」という視点で実装すると下記のようになります。
class UpdateMyInfoController extends Controller
{
/**
* 会員情報の更新
*/
public function __invoke(
UpdateMyInfoRequestData $requestData,
UpdateMyInfoService $updateMyInfo,
UpdateMyInfoMailService $updateMyInfoMail,
) {
// 会員情報を更新
$updateMyInfo->execute(
$requestData,
);
// メール送信
$updateMyInfoMail->execute(
$requestData,
);
// レスポンス
return response()->json();
}
}
コントローラーは無条件にメール送信用のサービスクラスを実行します。
詳細なことは、メール送信用のサービスクラスに任せます。
将来の機能追加で、メール送信の条件がもっと複雑になるかも?
やはりそれは、コントローラーで判断することではなく、メール送信用のサービスクラスの役割りになります。
コントローラーからは尋ねない、(メールを送れと) 命じるだけです。
class UpdateMyInfoMailService
{
public function execute(UpdateMyInfoRequestData $requestData): void
{
// 送信条件に一致しなければ何もしない
if (! $requestData->acceptMailMagazine) {
return;
}
Mail::to($requestData->email)
->send(new UpdateMyInfoMail);
}
}
わずかなことですが、これによりコントローラーの責任がひとつ減り、適切な役割分担ができました。