Основным способом для обработки запросов в Symfony являются контроллеры. С возможностью описывать роутинг непосредственно в контроллерах (аннотациями) жизнь стала еще лучше. Но использование аннотаций при наследовании контроллеров вызывает проблемы — для каждого дочернего контроллера необходимо заново прописывать роутинг. А ведь в crud-приложения типична ситуация, когда есть базовый контроллер и множество дочерних, которые наследуют логику базового контроллера, и роуты для которых можно было бы генерировать автоматически.
Попыткой улучшить стандартные контроллеры Symfony стал DunglasActionBundle. Этот бандл предполагает, что у контроллера есть только один метод __invoke(), что позволяет использовать имя класса в качестве имени роута, что весьма удобно. Например, можно генерировать url следующим образом:
Но проблему с наследованием контроллеров этот бандл не решает. Поэтому был написан собственный бандл, который решает все эти задачи — PaEndpointBundle
Возможности бандла:
Основным понятием бандла является Endpoint — точка входа в приложение (в терминологии symfony — контроллер с единственным action). Пример простого Endpoint:
Этот endpoint обрабатывает запросы по адресу your.server/cool_message и возвращает ответ с текстом 'Hello, world'.
Чтобы endpoint заработал, достаточно зарегистрировать его как сервис в symfony. Больше ничего делать не нужно — бандл сам обнаружит endpoint и добавит его роуты в общий список роутов приложения.
При необходимости задать собственное имя роута это можно сделать следующим образом:
, после чего его можно использовать со стандартным роутером symfony, или в шаблонах.
Поскольку метод routes() в endpoint — обычный метод класса, то он может использовать любую логику для генерирования роутов, например, генерировать роуты в зависимости от каких-то настроек системы, включать или выключать роуты по необходимости, создавать коллекцию роутов.
Для генерации url-ов используется класс EndpointRouter. Пример использования:
Даже, если в TextEndpoint было задано собственное имя роута, $router->url(TextEndpoint::class) все равно будет работать. Это достигается за счет кэширования роутов. Конечно, если для endpoint было задано больше одного роута, сгенерировать url по имени класса не получится и придется использовать имя роута.
Примеры использования бандла можно посмотреть в демонстрационном приложении.
Надеюсь, что PaEndpointBundle или его идеи будут полезны symfony-разработчикам.
Попыткой улучшить стандартные контроллеры Symfony стал DunglasActionBundle. Этот бандл предполагает, что у контроллера есть только один метод __invoke(), что позволяет использовать имя класса в качестве имени роута, что весьма удобно. Например, можно генерировать url следующим образом:
$route->generate(MyController::class, ['paramName' => 'value']);
Но проблему с наследованием контроллеров этот бандл не решает. Поэтому был написан собственный бандл, который решает все эти задачи — PaEndpointBundle
Возможности бандла:
- Простой интерфейс контроллера — только один метод execute(Request $request): Response
- Удобная генерация url по имени класса — $router->url(SomeEndpoint::class)
- Удобство рефакторинга — при переименовании или перемещении контроллера не требуется дополнительных действий, например смена имени роута
- Не нужно задавать имя роута (но можно при необходимости)
Основным понятием бандла является Endpoint — точка входа в приложение (в терминологии symfony — контроллер с единственным action). Пример простого Endpoint:
use PaLabs\EndpointBundle\EndpointInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class TextEndpoint implements EndpointInterface {
public function routes()
{
return new Route('/cool_message');
}
public function execute(Request $request): Response
{
return new Response('Hello, world');
}
}
Этот endpoint обрабатывает запросы по адресу your.server/cool_message и возвращает ответ с текстом 'Hello, world'.
Чтобы endpoint заработал, достаточно зарегистрировать его как сервис в symfony. Больше ничего делать не нужно — бандл сам обнаружит endpoint и добавит его роуты в общий список роутов приложения.
При необходимости задать собственное имя роута это можно сделать следующим образом:
public function routes()
{
return new EndpointRoute('my_route_name', new Route('/cool_message'));
}
, после чего его можно использовать со стандартным роутером symfony, или в шаблонах.
Поскольку метод routes() в endpoint — обычный метод класса, то он может использовать любую логику для генерирования роутов, например, генерировать роуты в зависимости от каких-то настроек системы, включать или выключать роуты по необходимости, создавать коллекцию роутов.
Для генерации url-ов используется класс EndpointRouter. Пример использования:
class SomeService {
protected $router;
public function __construct(EndpointRouter $router) {
$this->router = $router;
}
public function doWork() {
// ...
$url = $endpointRouter->url(TextEndpoint::class);
}
}
Даже, если в TextEndpoint было задано собственное имя роута, $router->url(TextEndpoint::class) все равно будет работать. Это достигается за счет кэширования роутов. Конечно, если для endpoint было задано больше одного роута, сгенерировать url по имени класса не получится и придется использовать имя роута.
Примеры использования бандла можно посмотреть в демонстрационном приложении.
Надеюсь, что PaEndpointBundle или его идеи будут полезны symfony-разработчикам.