Опиши путь HTTP-запроса от ввода URL до вызова метода контроллера в Symfony.

Ответ

Путь запроса в Symfony строго определён и централизован через фронт-контроллер public/index.php.

  1. Браузер отправляет HTTP-запрос (например, GET /blog/42).
  2. Веб-сервер (Nginx/Apache) перенаправляет все запросы на public/index.php (через конфигурацию, например, try_files $uri /index.php$is_args$args).
  3. Фронт-контроллер (index.php):
    • Загружает автозагрузчик Composer.
    • Создаёт экземпляр ядра приложения (Kernel).
    • Вызывает Kernel::handle($request), передавая объект Request, сформированный из глобальных переменных ($_GET, $_POST, etc.).
  4. Ядро (Kernel):
    • Инициализирует контейнер служб (Service Container), загружая конфигурацию из config/.
    • Запускает HttpKernel — основной компонент, обрабатывающий запрос по событийной модели.
  5. Маршрутизатор (Router):
    • HttpKernel через RouterListener (подписчик на событие kernel.request) передаёт Request в Router.
    • Router сопоставляет путь (/blog/42) с объявленными маршрутами (из config/routes/, атрибутов #[Route] или аннотаций).
    • Находит совпадение и возвращает параметры маршрута: _controller (например, AppControllerBlogController::show) и id: 42.
  6. Контроллер (Controller):
    • HttpKernel через ControllerResolver создаёт или извлекает из контейнера экземпляр BlogController.
    • Вызывает метод show($id), автоматически подставляя 42 в аргумент.

Пример контроллера с атрибутом:

// src/Controller/BlogController.php
namespace AppController;

use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentRoutingAttributeRoute;

class BlogController extends AbstractController
{
    #[Route('/blog/{id}', name: 'blog_show')]
    public function show(int $id): Response
    {
        // Логика получения статьи по $id
        $article = ...;
        return $this->render('blog/show.html.twig', ['article' => $article]);
    }
}

После выполнения метода контроллера HttpKernel продолжает работу, обрабатывая результат (например, рендеринг шаблона) и отправляя финальный Response.

Ответ 18+ 🔞

Давай разберём, как этот ваш запрос по Symfony шатается, чтобы ты не думал, что там магия какая-то. Представь, что это как доставка пиццы, только вместо курьера — куча компонентов, которые друг другу мозги ебут.

Вот смотри, как всё происходит, по шагам.

  1. Браузер тупо стучится на твой сайт, типа GET /blog/42. Ждёт, сука, ответа.
  2. Веб-сервер (Nginx или этот старый пердун Apache) получает запрос. Его конфиг настроен так, что всё, что не статичный файл, он пихает в одну точку — public/index.php. Типа "разбирайтесь там сами, мне похуй".
  3. Точка входа (index.php) — это как швейцар в строгом подъезде. Его работа:
    • Поднять автозагрузчик Composer (чтобы классы сами находились, ёпта).
    • Создать ядро приложения (Kernel).
    • Засунуть в это ядро сформированный запрос (Request) и крикнуть: Kernel::handle($request), мол, держи, разгребай!
  4. Ядро (Kernel) — тут начинается мясо. Оно:
    • Поднимает контейнер служб — это такая большая умная тумбочка, где лежат все нужные сервисы (роутер, база данных, почта и прочая хуйня). Конфиги из папки config/ как раз говорят, что в каком ящике лежит.
    • Передаёт управление главному мозгу — HttpKernel. Этот товарищ работает на событиях, как параноик на прослушке.
  5. Маршрутизатор (Router) — самый важный этап. HttpKernel кричит событие "я получил запрос!". Его подслушивает RouterListener и суёт запрос в Router.
    • Router — это такой дохуя умный картограф. Он берёт путь (/blog/42) и начинает листать все объявленные маршруты. Ищет где? Да везде: в файликах config/routes/, в атрибутах #[Route] над методами контроллеров (раньше в аннотациях).
    • Находит совпадение и выдаёт на-гора: "Так, контроллер — AppControllerBlogController::show, а id у них там равен 42". Всё, его работа сделана.
  6. Контроллер (Controller) — звезда вечера. HttpKernel через своего помощника (ControllerResolver) либо создаёт этот контроллер, либо достаёт его готовеньким из той самой умной тумбочки (контейнера).
    • И просто вызывает метод show($id), автоматом подсовывая ему 42 в аргумент. Вот и вся магия, ёпта.

А вот как этот самый контроллер может выглядеть. Смотри, ничего сложного:

// src/Controller/BlogController.php
namespace AppController;

use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentRoutingAttributeRoute;

class BlogController extends AbstractController
{
    #[Route('/blog/{id}', name: 'blog_show')]
    public function show(int $id): Response
    {
        // Тут твоя логика: достаёшь статью из базы по этому id
        $article = ...; // Найди её, блядь!
        // И рендеришь шаблон, отдавая ему статью
        return $this->render('blog/show.html.twig', ['article' => $article]);
    }
}

Контроллер отработал, вернул ответ. HttpKernel это подхватывает, может ещё какие-то события по пути обработать (например, шаблон отрендерить), и в конце концов плюёт готовый Response обратно в браузер. Всё, довольный пользователь видит статью, даже не подозревая, какой пиздец только что произошёл у него под капотом.