Три ролі й одне питання без відповіді
У Laravel запит проходить знайомий шлях: маршрут з routes/web.php веде на метод , контролер бере дані з й повертає , тобто Blade-шаблон. У Symfony так само, тільки маршрут описано атрибутом #[Route] на методі, а шаблон це Twig, який рендерить render() з AbstractController.
MVC розводить вхід, дані й показ, але не відповідає, де мають жити правила на кшталт «відкликати відгук можна лише до рішення компанії». У Laravel-проєкті для них є два звичні місця. Перше: , у якому валідація, правило, запит до бази й лист живуть в одному методі. Друге: Eloquent-модель, у якій правила стоять поруч із $casts і звʼязками. Обидва варіанти привʼязують правило до HTTP або до таблиці.
У класичному MVC модель означає всю предметну область, дані разом із правилами. Eloquent-модель це : рядок таблиці з методами збереження. У PHP Ukraine модель із MVC розкладено на шари: сценарії в src/*/Application, правила в Domain, а Eloquent-моделі в Infrastructure, без бізнес-правил. Контролер лишається : перекладає запит на виклик сценарію чи query-сервісу й вибирає відповідь.
Шлях запиту до сторінки вакансії
- routes/web.php використовує JobController.
- JobController використовує JobPageQuery (find()).
- EloquentJobPageQuery реалізує JobPageQuery.
- EloquentJobPageQuery використовує JobModel.
- JobController використовує jobs/show.blade.php (view()).
- JobController не може змінювати JobModel напряму, лише через корінь.
- 1Контролер перекладає запит на виклик сценарію чи query-сервісу й результат на відповідь. Власних правил у ньому немає.
- 2Eloquent-модель зберігає й читає рядки. Бізнес-правила живуть у доменних класах.
- 3View отримує готові дані й нічого не дочитує з бази.
- 4Одна й та сама дія доступна з контролера, Livewire чи Artisan-команди, бо живе в сценарії.
Тонкий контролер відкликання відгуку
Маршрут POST /profile/applications/{id}/withdraw веде сюди. Контролер знаходить розробника, викликає сценарій WithdrawApplication і вибирає відповідь. Правило «відгук з рішенням не відкликати» живе в агрегаті Application, і контролер про нього не знає: він лише показує текст помилки. Файл резюме видаляє контролер, бо сховище не справа домену. Сам ProfileController при цьому великий: у ньому весь кабінет розробника, і така довжина вже підказує поділити його на кілька контролерів.
Куди зазвичай тікає логіка
Усе в контролері
Метод store() валідує форму, рахує вилку, пише в три таблиці й шле лист. Ту саму дію потрібно запустити з Artisan-команди, і код копіюють.
Натомість: правило в домені, дія в сценарії чи Action-класі. Контролер, Livewire-компонент і команда викликають той самий клас.
Товста Eloquent-модель
Модель на 1000 рядків: правила, scope, звʼязки, хук booted(), який шле листи. Перевірити правило без бази неможливо, а будь-який save() у сідері відправляє пошту.
Натомість: Eloquent лише зберігає й читає. Правила в простих PHP-класах, які тестуються без Laravel.
Запити з view
Шаблон звертається до $job->company->name у циклі, і сторінка робить сотню запитів. Логіку показу ніде не видно, крім Blade.
Натомість: контролер чи query-сервіс віддає готовий DTO, як JobPage у PHP Ukraine. View лише виводить його поля.
Чи час виносити логіку з контролера
- Контролер
- Клас, на який маршрут передає запит. Читає вхідні дані, викликає потрібний код і повертає відповідь: view, redirect чи JSON.
- Модель
- У MVC це дані й правила предметної області. У Laravel так часто називають лише Eloquent-клас, і звідси половина плутанини.
- View
- Шаблон, який показує готові дані: Blade у Laravel, Twig у Symfony. Нічого не вирішує й нічого не змінює.
- Товстий контролер
- Контролер, у якому живе бізнес-логіка. Її неможливо викликати з консолі чи черги й важко перевірити без HTTP.
- Active Record
- Патерн, у якому обʼєкт це рядок таблиці й сам себе зберігає: save(), delete(). Так влаштовано Eloquent.
- Тонкий контролер
- Контролер, який лише перекладає HTTP на виклик сценарію й результат на відповідь. Правил у ньому немає.
Питання зі співбесід
Прийняти запит, який передав маршрут, перевірити вхідні дані, викликати код, що виконує дію, і повернути відповідь: view, redirect чи JSON. Бізнес-правил у ньому бути не повинно.
Коли правил мало, у моделі чи Form Request це прийнятно. Коли їх багато, обидва місця погані: контролер відповідає за HTTP, Eloquent-модель за таблицю. Логіку виносять у сценарій чи Action-клас і доменні обʼєкти, які перевіряються без бази.
Ні. M у MVC означає всю предметну область, дані й правила. Eloquent-модель реалізує Active Record і повʼязана з однією таблицею. Якщо їх ототожнити, правила опиняються поруч зі схемою бази, а будь-яка зміна таблиці зачіпає бізнес-логіку.