Если у тебя контроллер весит килобайт на пятьдесят строк, и половину из них занимают какие-то мутные вычисления, пора звать Service-классы. Они спасают от каши в коде, оставляя контроллеру только работу с HTTP-запросами. Всё, что про бизнес-логику — в сервис.

Я обычно называю это «диета для контроллеров»: выкидываешь всё жирное и тяжелое в отдельный класс, и жить сразу проще.

Шаг 1. Создаём Service-класс

В Laravel нет «официальных сервисов», но это не мешает нам сделать папку app/Services и закинуть туда, например, PostService.php.

namespace App\Services;

use App\Models\Post;

class PostService
{
    public function createPost($data)
    {
        $post = new Post($data);
        $post->save();

        return $post;
    }

    // Тут могут быть и другие методы
}

Да, можно наворачивать интерфейсы, DI и прочую теологию, но в реальной жизни чаще всего достаточно простого класса.

Шаг 2. Используем в контроллере

Теперь контроллер выглядит не как свалка. Внедряем сервис через конструктор и пользуемся:

namespace App\Http\Controllers;

use App\Services\PostService;
use Illuminate\Http\Request;

class PostController extends Controller
{
    protected $postService;

    public function __construct(PostService $postService)
    {
        $this->postService = $postService;
    }

    public function store(Request $request)
    {
        $post = $this->postService->createPost($request->all());

        return response()->json($post, 201);
    }
}

Всё, контроллер похудел и занимается тем, чем должен — запросами и ответами.

Плюсы такого подхода

  • Чистота кода. Контроллеры не превращаются в бог-объекты.
  • Модульность. Сервис можно дергать в нескольких местах.
  • Тестируемость. Тестить проще, чем если бы логика была размазана по контроллеру и модели.

Где не перегнуть палку

И вот тут часто косячат. В сервис начинают пихать всё подряд. Что туда точно не надо тащить:

  • логику, связанную с самим HTTP-запросом (Request, Response — это в контроллере);
  • доступ к сессиям и кукам напрямую;
  • прямые SQL-запросы (сервис работает через модель или репозиторий, а не как ещё один DAL);
  • авторизацию/аутентификацию (для этого есть middleware и policy);
  • файловую систему напрямую (есть Storage);
  • кэширование (для этого Cache).

Service-класс — это не помойка для всего подряд. Это именно слой бизнес-логики.

Что вообще значит «бизнес-логика»?

Тут у многих, особенно у менеджеров, часто возникает ступор. Слово «бизнес» они понимают как продажи и бюджеты, «логика» — как шахматы. И когда мы говорим «бизнес-логика в коде», для них это звучит как «программист полез в бухгалтерию».

На деле всё проще: бизнес-логика — это правила, по которым работает ваш продукт в реальном мире, только записанные в коде.

Пример:

  • «Скидка 10% по промокоду, но только до конца месяца и не на акционные товары».
  • «Если пользователь превысил лимит, блокируем операции до оплаты».
  • «Рассчитываем доставку по тарифу, зависящему от региона».

Это не про «бухгалтерию» и не про «маркетинг». Это про то, чтобы кнопка «Заказать» на сайте не превратила бизнес в минусовую кассу. Поэтому сервис-классы как раз и нужны — вынести эти правила отдельно, чтобы код был чище, тестируемее и проще менять, когда бизнес передумает (а он передумает всегда).

Итог

Service-классы в Laravel — это про порядок. Если у тебя контроллер напоминает сценарий к индийскому фильму с сотней событий за пять минут, то пора резать лишнее и выносить в сервис. Но не превращай сервисы в новый монолит — иначе будешь разгребать тот же бардак, только в другом месте.