В Laravel-сообществе часто спорят: использовать Action-классы или Service-классы? На практике это не взаимоисключающие подходы — они решают разные задачи и отлично работают вместе.

Что такое Action
Action — это класс с одним публичным методом execute, который выполняет одно конкретное действие. Названия Action-классов обычно начинаются с глагола: CreateOrder, SendInvoice, ApproveComment.
class CreateOrderAction
{
public function execute(OrderDTO $dto): Order
{
$order = Order::create([
'user_id' => $dto->userId,
'total' => $dto->total,
'status' => OrderStatus::Pending,
]);
event(new OrderCreated($order));
return $order;
}
}
Ключевые признаки Action:
- Один публичный метод (
execute,handleили__invoke) - Одна ответственность — одно бизнес-действие
- Легко вызывается из контроллера, очереди, CLI, теста
Что такое Service
Service — это класс, который группирует несколько связанных операций в рамках одного домена. Например, PaymentService может содержать методы charge, refund, getHistory.
class PaymentService
{
public function charge(Order $order): Payment
{
// логика списания
}
public function refund(Payment $payment): void
{
// логика возврата
}
public function getHistory(User $user): Collection
{
// история платежей
}
}
Ключевые признаки Service:
- Несколько публичных методов, объединённых одним доменом
- Инкапсулирует логику работы с внешним сервисом или сложной подсистемой
- Может использоваться внутри Action-классов
Сравнение
| Критерий | Action | Service |
|---|---|---|
| Публичные методы | Один | Несколько |
| Ответственность | Одно действие | Группа операций одного домена |
| Именование | Глагол: CreateOrder | Существительное: OrderService |
| Вызывается из | Контроллер, очередь, CLI | Action, другой Service |
| Типичный размер | 20–60 строк | 50–200 строк |
Как они работают вместе
Action выступает как точка входа и оркестратор — он вызывает нужные сервисы в правильном порядке. Контроллер при этом остаётся тонким.
class CreateOrderAction
{
public function __construct(
private OrderService $orderService,
private PaymentService $paymentService,
private NotificationService $notificationService,
) {}
public function execute(OrderDTO $dto): Order
{
$order = $this->orderService->create($dto);
$this->paymentService->charge($order);
$this->notificationService->orderCreated($order);
return $order;
}
}
Контроллер вызывает только Action:
class OrderController extends Controller
{
public function store(StoreOrderRequest $request)
{
$dto = OrderDTO::fromRequest($request);
$order = app(CreateOrderAction::class)->execute($dto);
return new OrderResource($order);
}
}
Когда что выбирать
Используй Action, когда есть конкретное бизнес-действие, которое может вызываться из разных мест: контроллер, Artisan-команда, очередь, другой Action.
Используй Service, когда нужно сгруппировать несколько связанных операций: работа с платёжным шлюзом, отправка уведомлений через разные каналы, сложные выборки данных.
Используй оба вместе, когда Action оркестрирует вызовы нескольких сервисов для выполнения одной бизнес-операции.
Полная цепочка в контроллере
Итоговый паттерн тонкого контроллера выглядит так:
Form Request → валидация
DTO → типизированный объект из validated-данных
Action → оркестрация бизнес-логики
Service → переиспользуемые операции внутри Action
Resource → форматирование ответа
// Контроллер — максимум 5 строк
public function store(StoreOrderRequest $request)
{
$dto = OrderDTO::fromRequest($request);
$order = app(CreateOrderAction::class)->execute($dto);
return new OrderResource($order);
}
Жёстких правил нет — главное консистентность в проекте. Если Action содержит одну строку без оркестрации, возможно, сервиса достаточно. Если сервис разрастается и методы не связаны — пора разбивать на Action-классы.