Ответ
Принцип единственной ответственности (SRP) гласит, что класс должен иметь только одну причину для изменения. В Laravel это часто нарушается, когда контроллеры берут на себя слишком много. Рассмотрим пример с обработкой заказа.
Проблемный код (нарушение SRP):
// app/Http/Controllers/OrderController.php
class OrderController extends Controller
{
public function store(Request $request)
{
// Валидация
$validated = $request->validate([...]);
// Создание заказа (бизнес-логика)
$order = Order::create($validated);
// Отправка email (логика уведомлений)
Mail::to($order->user)->send(new OrderCreated($order));
// Генерация PDF-счета (логика отчетности)
$pdf = PDF::loadView('invoices.order', ['order' => $order]);
$pdf->save(storage_path('app/invoices/' . $order->id . '.pdf'));
return redirect()->route('orders.show', $order);
}
}
Здесь контроллер отвечает за HTTP-запрос, бизнес-логику, отправку почты и генерацию файлов.
Решение с SRP:
// 1. Контроллер отвечает только за HTTP
// app/Http/Controllers/OrderController.php
class OrderController extends Controller
{
public function __construct(private CreateOrderAction $createOrder) {}
public function store(StoreOrderRequest $request)
{
$order = $this->createOrder->execute($request->validated());
return redirect()->route('orders.show', $order);
}
}
// 2. Отдельный класс для бизнес-логики создания заказа (Action/Service)
// app/Actions/CreateOrderAction.php
class CreateOrderAction
{
public function __construct(
private SendOrderCreatedNotification $sendNotification,
private GenerateOrderInvoice $generateInvoice
) {}
public function execute(array $data): Order
{
$order = Order::create($data);
$this->sendNotification->handle($order);
$this->generateInvoice->handle($order);
return $order;
}
}
// 3. Отдельный класс для отправки уведомлений
// app/Actions/SendOrderCreatedNotification.php
class SendOrderCreatedNotification
{
public function handle(Order $order): void
{
Mail::to($order->user)->send(new OrderCreated($order));
}
}
// 4. Отдельный класс для генерации счета
// app/Actions/GenerateOrderInvoice.php
class GenerateOrderInvoice
{
public function handle(Order $order): void
{
$pdf = PDF::loadView('invoices.order', ['order' => $order]);
$pdf->save(storage_path('app/invoices/' . $order->id . '.pdf'));
}
}
Теперь каждый класс имеет одну четкую ответственность, что упрощает тестирование, поддержку и повторное использование кода.
Ответ 18+ 🔞
Ёпта, смотри, какой прикол. Есть такая штука — принцип единственной ответственности. По-русски это звучит как «не пытайся впихнуть невпихуемое в один класс». А в Laravel, блядь, это нарушают так часто, что уже волнение ебать. Особенно эти контроллеры, которые начинают делать всё на свете, как последние распиздяи.
Вот смотри на этот пиздопроебибный код. Чувак взял и запихнул в контроллер валидацию, создание заказа, отправку мыла и ещё генерацию PDF-счёта. Ну ты представляешь? Это же манда с ушами получается!
class OrderController extends Controller
{
public function store(Request $request)
{
// Валидация
$validated = $request->validate([...]);
// Создание заказа
$order = Order::create($validated);
// Отправка email
Mail::to($order->user)->send(new OrderCreated($order));
// Генерация PDF-счета
$pdf = PDF::loadView('invoices.order', ['order' => $order]);
$pdf->save(storage_path('app/invoices/' . $order->id . '.pdf'));
return redirect()->route('orders.show', $order);
}
}
Сам посуди, этот контроллер теперь отвечает за HTTP, за бизнес, за почту и за файлы. Доверия ебать ноль к такому коду. Захотел поменять логику отправки уведомлений — придётся лезть в контроллер и рисковать всё сломать. Это же хитрая жопа, которая тебя потом обязательно подставит.
А теперь смотри, как надо делать по-человечески. Разделяем всё на отдельные сущности, чтобы у каждой была одна чёткая задача.
Сначала делаем контроллер, который только за HTTP отвечает. Его дело — принять запрос, отдать данные в бизнес-логику и вернуть ответ. Всё, да похуй на остальное.
class OrderController extends Controller
{
public function __construct(private CreateOrderAction $createOrder) {}
public function store(StoreOrderRequest $request)
{
$order = $this->createOrder->execute($request->validated());
return redirect()->route('orders.show', $order);
}
}
Потом создаём отдельный класс для самой операции создания заказа. Пусть он рулит процессом, но не делает всё сам, а делегирует.
class CreateOrderAction
{
public function __construct(
private SendOrderCreatedNotification $sendNotification,
private GenerateOrderInvoice $generateInvoice
) {}
public function execute(array $data): Order
{
$order = Order::create($data);
$this->sendNotification->handle($order);
$this->generateInvoice->handle($order);
return $order;
}
}
А дальше — ёперный театр — создаём два маленьких и понятных класса. Один только письма шлёт, другой только PDF-ки генерит.
class SendOrderCreatedNotification
{
public function handle(Order $order): void
{
Mail::to($order->user)->send(new OrderCreated($order));
}
}
class GenerateOrderInvoice
{
public function handle(Order $order): void
{
$pdf = PDF::loadView('invoices.order', ['order' => $order]);
$pdf->save(storage_path('app/invoices/' . $order->id . '.pdf'));
}
}
И что получается? Каждый класс теперь — сам от себя охуел от своей простоты. Тестировать их — одно удовольствие. Менять что-то — не страшно. Поддерживать — легко. Это же ебушки-воробушки по сравнению с той свалкой, что была в начале.
Запомни, чувак: если твой класс делает больше одной вещи, он уже полупидор. Дели ответственности, и будет тебе счастье.