Laravel领域服务放在哪层

wen PHP项目 1

本文目录导读:

Laravel领域服务放在哪层

  1. 传统 Laravel 分层架构(推荐入门/中小项目)
  2. DDD 风格架构(推荐大型/复杂项目)
  3. 使用 Laravel 包(推荐模块化开发)
  4. 关键原则
  5. 什么时候该用领域服务?
  6. 避免的常见错误

在 Laravel 架构中,领域服务(Domain Services) 的放置位置取决于你采用的是传统分层架构还是 DDD(领域驱动设计)风格,以下是两种主流实践方案:

传统 Laravel 分层架构(推荐入门/中小项目)

如果项目没有严格遵循 DDD,而是使用 Laravel 默认的 app/ 目录结构,领域服务可以放在:

app/Services/
└── Domain/
    ├── OrderService.php
    ├── PaymentService.php
    └── UserDomainService.php

实现示例:

// app/Services/Domain/OrderService.php
namespace App\Services\Domain;
use App\Models\Order;
use App\Repositories\OrderRepository;
use App\Exceptions\InsufficientStockException;
class OrderService
{
    public function __construct(
        private OrderRepository $repository
    ) {}
    public function placeOrder(array $items, string $userId): Order
    {
        // 领域逻辑:检查库存、计算总价、创建订单
        $this->validateStock($items);
        $total = $this->calculateTotal($items);
        return $this->repository->create([
            'user_id' => $userId,
            'items' => $items,
            'total' => $total,
            'status' => 'pending'
        ]);
    }
    private function validateStock(array $items): void
    {
        foreach ($items as $item) {
            if ($item['quantity'] > $item['product']->stock) {
                throw new InsufficientStockException($item['product']->name);
            }
        }
    }
}

DDD 风格架构(推荐大型/复杂项目)

对于严格遵循 DDD 的项目,使用 app/Domain/ 目录:

app/Domain/
├── Services/
│   ├── OrderPlacementService.php
│   ├── PaymentService.php
│   └── ShippingService.php
├── Models/
│   ├── Order.php
│   └── Payment.php
├── Repositories/
│   └── OrderRepository.php
└── Events/
    └── OrderPlaced.php

DDD 风格示例:

// app/Domain/Services/OrderPlacementService.php
namespace App\Domain\Services;
use App\Domain\Repositories\OrderRepository;
use App\Domain\Events\OrderPlaced;
use App\Domain\ValueObjects\Money;
use Illuminate\Support\Facades\Event;
class OrderPlacementService
{
    public function __construct(
        private OrderRepository $orderRepo,
        private InventoryService $inventory,
        private PricingService $pricing
    ) {}
    public function execute(OrderRequest $request): Order
    {
        // 1. 验证库存
        $this->inventory->reserveItems($request->items);
        // 2. 计算价格
        $total = $this->pricing->calculate($request->items);
        // 3. 创建订单实体
        $order = new Order(
            userId: $request->userId,
            items: $request->items,
            total: new Money($total)
        );
        // 4. 持久化
        $this->orderRepo->save($order);
        // 5. 触发事件
        Event::dispatch(new OrderPlaced($order));
        return $order;
    }
}

使用 Laravel 包(推荐模块化开发)

如果你使用 nWidart/laravel-modules 或类似包,按模块组织:

Modules/
└── Order/
    ├── Services/
    │   └── OrderService.php
    ├── Entities/
    │   └── Order.php
    └── Repositories/
        └── OrderRepository.php

关键原则

无论放在哪里,请遵循:

原则 说明 反例
业务逻辑 领域服务只包含业务规则,不处理 HTTP 请求 ❌ 在服务里调用 request()->all()
无状态 服务不应该持有状态(除了依赖注入) ❌ 在服务类里定义 public 属性
单一职责 每个服务只处理一个领域关注点 UserService 同时处理用户、订单、支付
依赖抽象 依赖接口而非具体实现 ❌ 直接实例化 Eloquent Model

什么时候该用领域服务?

场景 应该使用
多个实体协同工作(如订单+支付+库存) ✅ 必须
复杂事务性操作 ✅ 推荐
简单 CRUD ❌ 直接使用 Repository 或 Model
只有一个实体的简单规则 ❌ 放在实体方法里

避免的常见错误

// ❌ 错误:在 Controller 里写领域逻辑
class OrderController {
    public function store(Request $request) {
        // 检查库存、计算价格... 太多逻辑在控制器
    }
}
// ✅ 正确:控制器只负责编排
class OrderController {
    public function store(Request $request) {
        $order = app(OrderService::class)->placeOrder(
            $request->items,
            auth()->id()
        );
        return response()->json($order, 201);
    }
}
  • 传统 Laravelapp/Services/Domain/
  • DDDapp/Domain/Services/
  • 模块化Modules/{Module}/Services/

选择哪种取决于项目规模和团队规范,对于大多数 Laravel 项目,app/Services/Domain/ 是最平衡的选择。

抱歉,评论功能暂时关闭!