Маршруты в Symfony: с чего начать новичку
Как связать URL с методом контроллера в Symfony 7.x: настройка первого маршрута через атрибуты, параметры в пути, проверка через bin/console и типичные ошибки первых дней.

К концу этой инструкции у вас будет работающий маршрут в Symfony 7.x: вы откроете в браузере /hello/Ivan и увидите ответ от вашего контроллера. Займёт это минут двадцать, если проект уже развёрнут. Разбираем самый частый способ — атрибуты #[Route] прямо над методом контроллера.
Что нужно иметь до начала
Прежде чем писать маршруты, убедитесь, что на месте всё необходимое. Проверять на пятом шаге, что не хватает пакета, — потеря времени.
- PHP 8.2 или новее — Symfony 7.x требует минимум 8.2. Проверьте командой
php -v. - Composer — менеджер зависимостей. Команда
composer --versionдолжна что-то вывести. - Развёрнутый проект Symfony 7.x с установленным пакетом
symfony/framework-bundle. Если проекта нет, создайте его:composer create-project symfony/skeleton my_app. - Пакет для атрибутов маршрутов. В skeleton-проекте его может не быть. Установите:
composer require symfony/routing doctrine/annotations— для атрибутов PHP 8 достаточноsymfony/routing, аннотации Doctrine нужны только для старого синтаксиса комментариев. - Локальный сервер. Проще всего Symfony CLI: команда
symfony server:startподнимет сайт наhttps://127.0.0.1:8000.
Дальше все примеры — под Symfony 7.x. В версиях 5.x и 6.x синтаксис атрибутов такой же, но там мог использоваться и старый формат аннотаций в комментариях /** @Route */, который в 7.x уже не поддерживается.
Что такое маршрут на пальцах
Маршрут — это правило: «когда пользователь запросил такой-то URL, вызови такой-то метод». В Symfony это правило чаще всего пишут атрибутом прямо над методом контроллера1. Никаких отдельных огромных файлов с таблицей адресов — правило живёт рядом с кодом, который его обрабатывает.
Шаг за шагом: первый маршрут
-
Создайте контроллер. В папке
src/Controllerсоздайте файлHelloController.php:<?php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; class HelloController extends AbstractController { // Маршрут: этот метод отвечает на GET /hello #[Route('/hello', name: 'app_hello')] public function index(): Response { return new Response('Привет из контроллера'); } }Проверка: откройте
https://127.0.0.1:8000/hello. В браузере должна появиться строка «Привет из контроллера». -
Убедитесь, что Symfony видит маршрут. Выполните в корне проекта:
php bin/console debug:routerПроверка: в таблице должна появиться строка с именем
app_helloи путём/hello. Если её нет — маршрут не подхватился, смотрите раздел про ошибки ниже. -
Добавьте параметр в путь. Пусть URL принимает имя. Замените метод на такой:
#[Route('/hello/{name}', name: 'app_hello')] public function index(string $name): Response { // Значение из {name} попадает в аргумент $name автоматически return new Response('Привет, ' . $name); }Имя параметра в фигурных скобках должно совпадать с именем аргумента метода — так Symfony понимает, что куда передавать.
Проверка: откройте
/hello/Ivan— увидите «Привет, Ivan». А вот просто/helloтеперь вернёт ошибку 404, потому что параметр обязателен. -
Сделайте параметр необязательным. Задайте значение по умолчанию через аргумент метода:
#[Route('/hello/{name}', name: 'app_hello')] public function index(string $name = 'гость'): Response { return new Response('Привет, ' . $name); }Проверка: теперь
/helloвернёт «Привет, гость», а/hello/Ivan— «Привет, Ivan». -
Ограничьте, какие значения принимает параметр. Допустим, нужен только числовой ID. Добавьте требование регулярным выражением через ключ
requirements:#[Route('/user/{id}', name: 'app_user', requirements: ['id' => '\d+'])] public function show(int $id): Response { return new Response('Пользователь № ' . $id); }Проверка:
/user/42сработает, а/user/abcвернёт 404 — буквы не проходят проверку\d+. -
Ограничьте HTTP-метод. По умолчанию маршрут отвечает на любые методы. Чтобы принимать только POST:
#[Route('/hello', name: 'app_hello', methods: ['POST'])]Проверка: запрос GET на этот адрес вернёт код 405 (Method Not Allowed), POST пройдёт.
Как построить ссылку на маршрут по имени
Имя маршрута (name: 'app_hello') нужно не для красоты. По нему генерируют URL, чтобы не хардкодить адреса. Внутри контроллера:
// Вернёт /hello/Ivan
$url = $this->generateUrl('app_hello', ['name' => 'Ivan']);
Если завтра вы поменяете путь с /hello на /greet, все ссылки, построенные по имени, обновятся сами. Захардкоженные строки — нет.
Правило, которое экономит часы: URL меняется в одном месте — в атрибуте маршрута. Всё остальное ссылается на маршрут по имени, а не по строке пути.
Порядок маршрутов имеет значение
Symfony проверяет маршруты сверху вниз и берёт первый подходящий. Если у вас есть /hello/{name} и /hello/admin, а более общий объявлен первым, запрос /hello/admin уйдёт в него, а не в конкретный. Более конкретные маршруты объявляйте раньше более общих.
Если не получилось
- Страница 404, маршрут не в списке
debug:router. Скорее всего, Symfony не сканирует папку с контроллером. Проверьте файлconfig/routes.yaml— там должен быть блок, указывающий на../src/Controller/с типомattribute. Если блока нет, атрибуты не читаются. - Ошибка
Attribute class "Route" not found. Неверныйuse. В Symfony 7.x правильный импорт —Symfony\Component\Routing\Attribute\Route. В более старых версиях путь былSymfony\Component\Routing\Annotation\Route. Скопировали пример под старую версию — получите эту ошибку. - Изменили маршрут, а браузер показывает старое. В окружении
prodмаршруты кешируются. Сбросьте кеш:php bin/console cache:clear. Вdevкеш обычно пересобирается сам, но при странном поведении команда не повредит. Controller ... requires that you provide a value for the "$name" argument. В пути нет параметра{name}, а метод его требует и без значения по умолчанию. Либо добавьте параметр в путь, либо задайте значение по умолчанию в аргументе.- Два маршрута с одинаковым именем. Symfony молча возьмёт последний, и генерация URL сломается неожиданно. Имена маршрутов должны быть уникальны по всему проекту —
debug:routerпокажет дубли.
Что делать дальше
Когда базовые маршруты работают, посмотрите на группировку: атрибут #[Route] можно повесить не только над методом, но и над всем классом контроллера — тогда его путь станет префиксом для всех методов. Это удобно, когда все адреса контроллера начинаются с /admin или /api. Следующий шаг после маршрутов — шаблоны Twig и работа с формами; генерацию URL в них делают функцией path(). Инвалидация и структура больших конфигов маршрутов — отдельная тема, здесь мы разобрали только первые шаги.
1 Атрибут — конструкция PHP 8 вида #[...], которую пишут прямо перед объявлением класса, метода или свойства. Symfony читает её и получает метаданные, не запуская сам код метода.
Проверка рекламы на риски: Что в макете вызовет вопросы ФАС: превосходные степени, сравнения, обещания результата, маркировка.
Спросить за 40 ₽Источники: Symfony Documentation — Routing
Частые вопросы
У меня Symfony 6.x, а не 7.x — примеры подойдут?
Маршрут не появляется в debug:router, хотя атрибут на месте. Что делать?
Можно ли обойтись без атрибутов и писать маршруты в отдельном файле?
Почему запрос вернул 405 вместо 404?
Как передать в контроллер сразу несколько параметров из URL?
Изменил путь маршрута, а в бою по-прежнему открывается старая страница.
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.