Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Події
Інше
Про нас

Чим сервіс відрізняється від контролера і навіщо його виділяти?

Контролер - це шар HTTP: він приймає запит, дістає з нього дані, викликає бізнес-логіку й формує відповідь. Сервіс - це сама бізнес-логіка, яка про HTTP нічого не знає.

Як виглядає змішування:

public function store(Request $request)
{
    $order = Order::create($request->validated());
    $order->items()->createMany($request->input('items'));

    $total = collect($request->input('items'))->sum(fn ($i) => $i['price'] * $i['qty']);
    $order->update(['total' => $total]);

    Mail::to($order->email)->send(new OrderPlaced($order));
    Http::post('https://warehouse.example/orders', $order->toArray());

    return redirect()->route('orders.show', $order);
}

Тут порахунок суми, лист і виклик складу існують лише всередині HTTP-запиту.

Те саме з сервісом:

class PlaceOrder
{
    public function handle(array $data): Order
    {
        return DB::transaction(function () use ($data) {
            $order = Order::create($data);
            $order->items()->createMany($data['items']);
            $order->update(['total' => $this->total($data['items'])]);

            OrderPlaced::dispatch($order);

            return $order;
        });
    }
}

public function store(StoreOrderRequest $request, PlaceOrder $placeOrder)
{
    $order = $placeOrder->handle($request->validated());

    return redirect()->route('orders.show', $order);
}

Що це дає:

  • Ту саму логіку можна викликати з Artisan-команди, черги чи імпорту - не тільки з форми.
  • Тестувати можна без HTTP-запиту: створили масив, викликали handle(), перевірили результат.
  • Транзакція охоплює всю операцію цілком.
  • Контролер знову читається за кілька секунд.

Не поспішайте. Для Post::create($request->validated()) окремий сервіс - зайвий шар. Виносити варто тоді, коли з'являється щось із трьох: кілька моделей в одній операції, потреба викликати логіку не з HTTP, або контролер перестав вміщатися на екран.

Докладніше в документації: Контролери

3

Схожі питання