Laravel 用 Action 类与 DTO 收口业务逻辑:让控制器只做路由与装配
test12026-10-121 次阅读
控制器不该塞满业务
把下单、退款这类流程写在控制器里,复用靠复制粘贴,测试要起整套 HTTP。Action 类把“一个业务动作”封装成单一可调用对象,DTO 把零散的请求参数收成强类型对象,控制器只负责接参数、调动作、回响应。
定义一个 Action 类
// app/Actions/PlaceOrder.php
namespace App\Actions;
use App\Models\Order;
use App\Models\User;
class PlaceOrder
{
public function handle(User $user, array $items, string $coupon = ''): Order
{
$order = Order::create([
'user_id' => $user->id,
'coupon' => $coupon,
'total' => collect($items)->sum('price'),
]);
foreach ($items as $item) {
$order->items()->create($item);
}
return $order;
}
}
用 DTO 承接参数
配合 spatie/laravel-data 这类包,把请求直接映射成带校验的数据对象。
// app/Data/PlaceOrderData.php
namespace App\Data;
use Spatie\LaravelData\Data;
class PlaceOrderData extends Data
{
public function __construct(
public array $items,
public string $coupon = '',
) {}
}
// 控制器里
public function store(PlaceOrderData $data, PlaceOrder $action)
{
$order = $action->handle(auth()->user(), $data->items, $data->coupon);
return OrderResource::make($order);
}
收益与注意点
- Action 是普通类,可在控制器、命令行、队列里复用,单测直接 new 后调用 handle,不用走 HTTP。
- DTO 用 FromRequest 自动校验并映射,控制器不再手写 $request->input 拼接。
- 动作过多时按领域分目录(Orders/、Users/),避免一个 Actions 目录平铺几百个类。
- 涉及多步写操作记得在 Action 内用 DB::transaction 包住,保证原子性。
T
test1
文章作者
控制器不该塞满业务 把下单、退款这类流程写在控制器里,复用靠复制粘贴,测试要起整套 HTTP。Action 类把“一个...
- 分类
- 技术
- 发布时间
- 2026-10-12
- 字数
- 约 1366 字
- 阅读
- 1 次
