Loading...
Loading...
Compare original and translation side by side
references/domain-building-blocks.mdreferences/application-layer.mdreferences/domain-building-blocks.mdreferences/application-layer.mdapp/app/Domain/app/app/
├── Domain/ # Business logic (the "what")
│ ├── Invoice/
│ ├── Customer/
│ ├── Payment/
│ └── Shared/
├── Http/ # Standard Laravel HTTP layer
│ ├── Controllers/
│ │ ├── Api/
│ │ └── Web/
│ ├── Requests/
│ ├── Resources/
│ ├── Queries/
│ ├── ViewModels/
│ └── Middleware/
├── Jobs/
├── Listeners/
├── Notifications/
├── Providers/
└── Console/app/Domain/app/
├── Domain/ # 业务逻辑(「做什么」)
│ ├── Invoice/
│ ├── Customer/
│ ├── Payment/
│ └── Shared/
├── Http/ # Laravel标准HTTP层
│ ├── Controllers/
│ │ ├── Api/
│ │ └── Web/
│ ├── Requests/
│ ├── Resources/
│ ├── Queries/
│ ├── ViewModels/
│ └── Middleware/
├── Jobs/
├── Listeners/
├── Notifications/
├── Providers/
└── Console/app/Domain/Invoice/
├── Invoice.php # Model
├── InvoiceLine.php # Model
├── InvoiceStatus.php # Enum
├── InvoiceData.php # DTO (only when justified)
├── CreateInvoiceAction.php # Action
├── MarkInvoiceAsPaidAction.php # Action
├── CancelInvoiceAction.php # Action
├── InvoiceQueryBuilder.php # Custom QueryBuilder
├── InvoiceLineCollection.php # Custom Collection
├── InvoiceCreatedEvent.php # Event
└── InvalidTransitionException.php # Exceptionapp/Domain/Invoice/
├── Actions/
│ ├── CreateInvoiceAction.php
│ ├── MarkInvoiceAsPaidAction.php
│ └── CancelInvoiceAction.php
├── Models/
│ ├── Invoice.php
│ └── InvoiceLine.php
├── Enums/
│ └── InvoiceStatus.php
├── Data/
│ └── InvoiceData.php
└── ...references/domain-building-blocks.mdapp/Domain/Invoice/
├── Invoice.php # 模型
├── InvoiceLine.php # 模型
├── InvoiceStatus.php # 枚举
├── InvoiceData.php # DTO(仅在必要时使用)
├── CreateInvoiceAction.php # Action
├── MarkInvoiceAsPaidAction.php # Action
├── CancelInvoiceAction.php # Action
├── InvoiceQueryBuilder.php # 自定义QueryBuilder
├── InvoiceLineCollection.php # 自定义集合
├── InvoiceCreatedEvent.php # 事件
└── InvalidTransitionException.php # 异常app/Domain/Invoice/
├── Actions/
│ ├── CreateInvoiceAction.php
│ ├── MarkInvoiceAsPaidAction.php
│ └── CancelInvoiceAction.php
├── Models/
│ ├── Invoice.php
│ └── InvoiceLine.php
├── Enums/
│ └── InvoiceStatus.php
├── Data/
│ └── InvoiceData.php
└── ...references/domain-building-blocks.mdapp/Http/Controllers/Api/
├── InvoiceController.php # Fine when there are few controllers
├── CustomerController.php
└── PaymentController.phpapp/Http/Controllers/Api/
├── Invoice/
│ ├── InvoiceController.php
│ └── InvoiceStatusController.php
├── Customer/
│ └── CustomerController.php
└── Payment/
└── PaymentController.phpapp/Http/Controllers/Api/
├── InvoiceController.php # 控制器数量较少时的合理结构
├── CustomerController.php
└── PaymentController.phpapp/Http/Controllers/Api/
├── Invoice/
│ ├── InvoiceController.php
│ └── InvoiceStatusController.php
├── Customer/
│ └── CustomerController.php
└── Payment/
└── PaymentController.phpapp/Http/Controllers/Api/InvoiceController.php # Single version — no prefixapp/Http/Controllers/Api/
├── V1/
│ └── InvoiceController.php # Move here only when V2 exists
└── V2/
└── InvoiceController.phproutes/api_v1.phproutes/api_v2.phpreferences/application-layer.mdapp/Http/Controllers/Api/InvoiceController.php # 单版本——无需前缀app/Http/Controllers/Api/
├── V1/
│ └── InvoiceController.php # 仅当V2存在时,才迁移到此处
└── V2/
└── InvoiceController.phproutes/api_v1.phproutes/api_v2.phpreferences/application-layer.md| Type | Suffix | Example |
|---|---|---|
| Action | | |
| Data Object | | |
| Model | — | |
| QueryBuilder | | |
| Collection | | |
| Enum | | |
| Event | | |
| Exception | | |
| Controller | | |
| HTTP Query | | |
| Resource | | |
| Request | | |
| Job | | |
| 类型 | 后缀 | 示例 |
|---|---|---|
| Action | | |
| 数据对象 | | |
| 模型 | — | |
| QueryBuilder | | |
| 集合 | | |
| 枚举 | | |
| 事件 | | |
| 异常 | | |
| 控制器 | | |
| HTTP查询 | | |
| 资源 | | |
| 请求 | | |
| 任务 | | |
execute()readonlycolor()label()canTransitionTo()handle()app/Domain/execute()readonlycolor()label()canTransitionTo()handle()app/Domain/| Situation | Approach |
|---|---|
| Read a model/enum from another domain | Direct import |
| Validate a precondition from another domain | Direct call |
| Orchestrate actions atomically (transaction) | Direct call |
| Side effect (notify, log, sync) | Event |
| Async reaction (can fail without affecting the flow) | Event |
| Multiple domains react to the same fact | Event |
| 场景 | 实现方式 |
|---|---|
| 读取其他领域的模型/枚举 | 直接引入 |
| 验证其他领域的前置条件 | 直接调用 |
| 原子化编排多个Action(事务) | 直接调用 |
| 副作用操作(通知、日志、同步) | 事件 |
| 异步响应(失败不影响主流程) | 事件 |
| 多个领域响应同一事实 | 事件 |
namespace App\Domain\Invoice;
use App\Domain\Customer\Customer;
class CreateInvoiceAction
{
public function execute(InvoiceData $data, Customer $customer): Invoice
{
if (! $customer->isActive()) {
throw new \App\Domain\Customer\InactiveCustomerException();
}
return Invoice::create([
'customer_id' => $customer->id,
'number' => $data->number,
]);
}
}namespace App\Domain\Invoice;
use App\Domain\Customer\Customer;
class CreateInvoiceAction
{
public function execute(InvoiceData $data, Customer $customer): Invoice
{
if (! $customer->isActive()) {
throw new \App\Domain\Customer\InactiveCustomerException();
}
return Invoice::create([
'customer_id' => $customer->id,
'number' => $data->number,
]);
}
}class CheckoutController
{
public function store(CheckoutRequest $request)
{
return DB::transaction(function () use ($request) {
$invoice = app(CreateInvoiceAction::class)->execute($invoiceData);
$payment = app(ProcessPaymentAction::class)->execute($invoice, $paymentData);
return new CheckoutResource($invoice, $payment);
});
}
}class CheckoutController
{
public function store(CheckoutRequest $request)
{
return DB::transaction(function () use ($request) {
$invoice = app(CreateInvoiceAction::class)->execute($invoiceData);
$payment = app(ProcessPaymentAction::class)->execute($invoice, $paymentData);
return new CheckoutResource($invoice, $payment);
});
}
}class CreateInvoiceAction
{
public function execute(InvoiceData $data): Invoice
{
$invoice = Invoice::create([...]);
event(new InvoiceCreatedEvent($invoice));
return $invoice;
}
}
// Another domain reacts via listener — no direct coupling
class ReconcilePaymentListener
{
public function handle(InvoiceCreatedEvent $event): void
{
app(ReconcilePaymentAction::class)->execute($event->invoice);
}
}class CreateInvoiceAction
{
public function execute(InvoiceData $data): Invoice
{
$invoice = Invoice::create([...]);
event(new InvoiceCreatedEvent($invoice));
return $invoice;
}
}
// 其他领域通过监听器响应——无直接耦合
class ReconcilePaymentListener
{
public function handle(InvoiceCreatedEvent $event): void
{
app(ReconcilePaymentAction::class)->execute($event->invoice);
}
}Domain/Shared/Domain/Shared/app/Providers/
├── InvoiceServiceProvider.php
└── CustomerServiceProvider.phpapp/Providers/
├── InvoiceServiceProvider.php
└── CustomerServiceProvider.phpProcessInvoiceActionCreateInvoiceActionMarkInvoiceAsPaidActionShared/ProcessInvoiceActionCreateInvoiceActionMarkInvoiceAsPaidActionShared/references/domain-building-blocks.mdreferences/domain-building-blocks.mdreferences/domain-building-blocks.mdreferences/application-layer.mdreferences/domain-building-blocks.mdreferences/application-layer.md