Урок 2: Основы маршрутизации в Symfony

Мы продолжаем изучать Symfony. В первом уроке мы разобрались с установкой и структурой проекта. Сегодня погрузимся в одну из ключевых тем, в маршрутизацию. Без неё ваш сайт не сможет обрабатывать запросы пользователей. Давайте начнём.

Что такое маршрутизация (Routing)?

Маршрутизация это процесс, который связывает URL-адреса с конкретными методами в вашем приложении. Представьте, что пользователь вводит https://ваш-сайт.ru/about. Задача маршрутизатора это определить, какой контроллер и метод отвечают за генерацию страницы «О нас».

Зачем это нужно?

  1. Чистая структура URL: Вы можете создавать понятные адреса вроде /blog/post-123 вместо /index.php?page=blog&id=123.
  2. Гибкость: Легко менять логику обработки URL без переписывания кода.
  3. Безопасность: Можно валидировать параметры запроса на уровне маршрутов.

В Symfony маршруты можно создавать тремя способами: через YAML-файлы, аннотации или атрибуты. Но обо всём по порядку.

Создание простых маршрутов в config/routes.yaml

Начнём с классического подхода YAML. Откройте файл config/routes.yaml. Здесь вы будете описывать маршруты в формате YAML.

Пример 1: Статический маршрут

Допустим, мы хотим создать страницу приветствия по адресу /hello. Добавьте в routes.yaml следующий код:

yaml
hello_page:
    path: /hello
    controller: App\Controller\DefaultController::hello

Что здесь происходит?

  • hello_page — уникальное имя маршрута (пригодится для генерации URL в шаблонах).
  • path — URL-адрес, который будет обрабатываться.
  • controller — метод контроллера, вызываемый при переходе по этому адресу.

Теперь создайте контроллер DefaultController:

php
// src/Controller/DefaultController.php
namespace App\Controller;

use Symfony\Component\HttpFoundation\Response;

class DefaultController
{
    public function hello(): Response
    {
        return new Response('Привет, Symfony!');
    }
}

Перейдите по адресу http://localhost:8000/hello — вы увидите ваше приветствие!

Пример 2: Маршрут с динамическим URL

Допустим, мы хотим отображать статьи по их ID: /blog/5. Добавим в routes.yaml:

yaml
blog_show:
    path: /blog/{id}
    controller: App\Controller\BlogController::show

А в контроллере:

php
// src/Controller/BlogController.php
namespace App\Controller;

use Symfony\Component\HttpFoundation\Response;

class BlogController
{
    public function show(int $id): Response
    {
        return new Response("Статья №{$id}");
    }
}

Теперь при переходе на /blog/42 вы увидите: «Статья №42».

Аннотации, YAML, атрибуты

Symfony поддерживает три способа определения маршрутов. Давайте сравним их.

1. YAML

Плюсы:

  • Отделение конфигурации от кода.
  • Удобно для больших проектов с множеством маршрутов.

Минусы:

  • Нужно переключаться между файлами при редактировании.

2. Аннотации (устаревший способ)

Раньше маршруты описывались через PHP-докблоки:

php
// src/Controller/LegacyController.php
use Symfony\Component\Routing\Annotation\Route;

class LegacyController
{
    /**
     * @Route("/old", name="old_route")
     */
    public function oldMethod(): Response
    {
        // ...
    }
}

Аннотации это комментарии, которые парсятся в runtime. Это замедляет работу и не поддерживается в PHP 8.1+.

3. Атрибуты (рекомендуется!)

В PHP 8+ появились атрибуты, встроенная возможность языка. Symfony перешла на них:

php
// src/Controller/NewController.php
use Symfony\Component\Routing\Attribute\Route;

class NewController
{
    #[Route('/new', name: 'new_route')]
    public function newMethod(): Response
    {
        // ...
    }
}

Преимущества:

  • Код и маршруты находятся в одном месте.
  • Автодополнение в IDE.
  • Лучшая производительность.

Используйте атрибуты, если работаете с Symfony 5.3+ и PHP 8+.

Передача параметров в маршруты

Часто нужно передавать данные через URL. Например, ID статьи или фильтры. Разберёмся, как это сделать.

1. Обязательные параметры

Допустим, мы хотим отображать профиль пользователя по его имени: /user/maxim.

yaml
# config/routes.yaml
user_profile:
    path: /user/{username}
    controller: App\Controller\UserController::profile

В контроллере:

php
public function profile(string $username): Response
{
    return new Response("Профиль: {$username}");
}

2. Необязательные параметры

Что если сделать параметр необязательным? Например, /blog показывает все статьи, а /blog/5 — конкретную.

yaml
blog_list:
    path: /blog/{page}
    controller: App\Controller\BlogController::list
    defaults:
        page: 1

Теперь page по умолчанию равен 1.

3. Валидация параметров

Чтобы URL /blog/abc не ломал приложение, добавим проверку типа:

yaml
blog_show:
    path: /blog/{id}
    controller: App\Controller\BlogController::show
    requirements:
        id: '\d+'

Теперь id должен быть числом. Иначе Symfony вернёт ошибку 404.

Через атрибуты это выглядит так:

php
#[Route('/blog/{id}', name: 'blog_show', requirements: ['id' => '\d+'])]
public function show(int $id): Response
{
    // ...
}

Практические задачи

Закрепим знания на практике.

Задача 1: Создайте маршрут для страницы контактов

  • URL: /contact
  • Контроллер: ContactController::index()
  • Вывод: «Наши контакты: example@mail.ru».

Решение:

  1. Добавьте в routes.yaml:
yaml
contact_page:
    path: /contact
    controller: App\Controller\ContactController::index
  1. Создайте контроллер ContactController.

Задача 2: Динамическая страница товара

Создайте маршрут /product/{slug}, где slug — строка из букв и дефисов (например, /product/iphone-15).

Решение:

yaml
product_show:
    path: /product/{slug}
    controller: App\Controller\ProductController::show
    requirements:
        slug: '[a-zA-Z-]+'

Итого 2-го урока

Сегодня мы разобрали основы маршрутизации в Symfony. Вы научились:

  1. Создавать статические и динамические маршруты.
  2. Работать с YAML и атрибутами.
  3. Передавать и валидировать параметры.

В следующих уроках будем изучать контроллеры и шаблоны Twig. Полный курс Symfony для начинающих