Маршруты
Маршрут связывает адрес с методом контроллера. В Symfony его записывают атрибутом прямо над методом — адрес и код, который его обрабатывает, всегда рядом.
Простой маршрут
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class BlogController
{
#[Route('/blog', name: 'blog_index')]
public function index(): Response
{
return new Response('Список статей');
}
}name — имя маршрута. По нему создают ссылки, поэтому имя задают всегда.
Параметры
Часть адреса в фигурных скобках попадает в одноимённый аргумент метода:
#[Route('/blog/{slug}', name: 'blog_show')]
public function show(string $slug): Response
{
return new Response("Статья: $slug");
}Адрес /blog/first-post передаст в метод строку first-post.
Ограничения и значения по умолчанию
Регулярное выражение в угловых скобках ограничивает параметр, а значение по умолчанию у аргумента делает его необязательным:
#[Route('/blog/page/{page<\d+>}', name: 'blog_page')]
public function page(int $page = 1): Response
{
return new Response("Страница $page");
}Адрес /blog/page/abc этому маршруту не подойдёт — Symfony вернёт ошибку 404.
Методы HTTP
#[Route('/blog/{id}', name: 'blog_update', methods: ['PUT', 'PATCH'])]
public function update(int $id): Response
{
// …
}Без methods маршрут отвечает на любой метод.
Общая часть адреса
Атрибут над классом добавляет начало адреса и имени ко всем маршрутам внутри:
#[Route('/admin', name: 'admin_')]
class AdminController
{
#[Route('/users', name: 'users')] // /admin/users, имя admin_users
public function users(): Response
{
// …
}
}Создание ссылок
Адреса не пишут вручную — их строят по имени маршрута. В контроллере:
$url = $this->generateUrl('blog_show', ['slug' => 'first-post']);
// /blog/first-postВ шаблоне:
<a href="{{ path('blog_show', {slug: post.slug}) }}">{{ post.title }}</a>Если адрес маршрута изменится, все ссылки обновятся сами.
Список маршрутов
php bin/console debug:router
php bin/console router:match /blog/first-postВторая команда показывает, какой маршрут сработает для адреса.
Частая ошибка
Маршруты проверяются по порядку, и первый подходящий побеждает. Если /blog/{slug} объявлен раньше /blog/new, то адрес /blog/new попадёт в первый — со slug, равным new. Объявляйте точные адреса выше или задайте порядок явно: #[Route('/blog/new', priority: 2)].