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 次