Как работают маршруты в PHP фреймворке Symfony

Раздел: -> Фреймворки PHP

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

Как создать контроллер с маршрутом с помощью атрибутов?

// src/Controller/ProductController.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
class ProductController
{
    #[Route('/api/products', name: 'api_products', methods: ['GET'])]
    public function list(): JsonResponse
    {
        return new JsonResponse(['products' => []]);
    }
}

Это современный способ определения маршрутов, доступный с Symfony 5.3 и PHP 8. Атрибут #[Route] позволяет задать путь, имя и ограничения. Метод возвращает JSON-ответ.

Типичная ошибка: маршрут не находится. Решение: очистить кэш командой php bin/console cache:clear или php bin/console cache:warmup. Также необходимо проверить, что используется PHP 8.

Как определить маршруты в YAML файле?

# config/routes.yaml
api_products:
    path: /api/products
    controller: App\Controller\ProductController::list
    methods: GET

Внешняя конфигурация маршрутов в YAML удобна для централизованного управления. Путь задается в path, контроллер указывает на метод. Ограничения по HTTP-методу задаются ключом methods.

Ошибки: неверный синтаксис YAML, несовпадение имени контроллера. После изменений необходимо перезагрузить кэш маршрутов.

Как использовать аннотации для маршрутов (устаревший способ)?

// src/Controller/ProductController.php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

class ProductController
{
    /**
     * @Route('/api/products', name='api_products', methods={'GET'})
     */
    public function list(): JsonResponse
    {
        return new JsonResponse([]);
    }
}

Этот вариант работал в Symfony до 5.3, теперь рекомендуется переходить на атрибуты. Требуется установка sensio/framework-extra-bundle.

В Symfony 7 аннотации удалены, при обновлении возникнут ошибки. Рекомендуется мигрировать на атрибуты с помощью инструментов обновления.

Как зарегистрировать контроллер как сервис и задать маршрут?

# config/services.yaml
services:
    App\Controller\ProductController:
        tags: ['controller.service_arguments']

# config/routes.yaml
api_products:
    path: /api/products
    controller: App\Controller\ProductController::list
    methods: GET

Контроллер регистрируется как сервис с тегом controller.service_arguments. Это дает возможность внедрять зависимости напрямую в конструктор. Однако в современных версиях это делается автоматически.

Если не указать тег, маршрут не сработает. Также возможна путаница с именем сервиса.

Расширенные примеры маршрутизации

Параметры маршрута и их ограничения

Пример
// src/Controller/ProductController.php
#[Route('/api/products/{id}', name: 'api_product_show', requirements: ['id' => '\d+'])]
public function show(int $id): JsonResponse
{
    return new JsonResponse(['id' => $id]);
}
GET /api/products/42 -> 200 OK, тело: {'id':42}

Параметр {id} передаётся в аргумент метода. Ограничение requirements проверяет, что id состоит только из цифр.

Групповые маршруты через атрибут на классе

Пример
#[Route('/admin', name: 'admin_')]
class AdminController
{
    #[Route('/dashboard', name: 'dashboard')]
    public function dashboard(): Response { ... }

    #[Route('/users', name: 'users')]
    public function users(): Response { ... }
}
Маршрут admin_dashboard ведет на /admin/dashboard
Маршрут admin_users ведет на /admin/users

Префикс /admin добавляется ко всем маршрутам класса, а имя маршрута получает префикс admin_.

Ограничение HTTP-методов

Пример
#[Route('/api/products', name: 'api_products', methods: ['GET', 'POST'])]
public function collection(): JsonResponse { ... }
GET /api/products - работает
POST /api/products - работает
DELETE /api/products - 405 Method Not Allowed

Методы задаются массивом. Можно также использовать отдельные атрибуты #[Get] и #[Post] (в Symfony 6+).

Значения по умолчанию для параметров

Пример
#[Route('/page/{page}', name: 'page', defaults: ['page' => 1])]
public function page(int $page): Response
{
    // $page = 1, если не указан /page
}

Если параметр не передан, используется значение из defaults.

Отладка маршрутов

Пример
=> php bin/console debug:router
 ------------------ -------- -------- ------ -----------------------------------
  Name               Method   Scheme   Host   Path
 ------------------ -------- -------- ------ -----------------------------------
  api_products       GET      ANY      ANY    /api/products
  api_product_show   GET      ANY      ANY    /api/products/{id}
  admin_dashboard    GET      ANY      ANY    /admin/dashboard
  admin_users        GET      ANY      ANY    /admin/users
 ------------------ -------- -------- ------ -----------------------------------

Команда debug:router выводит все зарегистрированные маршруты. Полезна для проверки имён и путей.

Фреймворк Symfony на PHP - comments

En
Php symfony (php)