Комментарии 18
Возможности бандла:
Простой интерфейс контроллера — только один метод execute(Request $request): Response
Удобная генерация url по имени класса — $router->url(SomeEndpoint::class)
Удобство рефакторинга — при переименовании или перемещении контроллера не требуется дополнительных действий, например смена имени роута
Не нужно задавать имя роута (но можно при необходимости)
1. Давно есть в нативном symfony через `__invoke()` и controller as a service symfony.com/doc/current/controller/service.html
2. Как вы ниже пишете по тексту работает не всегда. Чаще всего это не работает, когда один и тот же контроллер доступен по нескольим роутам с разными дефолтными значениями, такие ситуации далеко не редкость. Мне кажется весьма неприятным попасть в ситуацию, когда придется полноситью переделать роутинг контроллера ради того, чтобы навесить на него еще один роут
3. Опять же, не всегда работает, т.к. не всегда работает п. 2
4. И снова не всегда работает.
Какие преимущества данного подхода над controller as a service?
Недостаток я вижу один и довольно существенный — вы привязываете контроллер не только к http-kernel, но и к кастомному роутингу и бандлу, что снижает возможность его переиспользования, особенно если вы пишите компонент, предоставляющий контроллеры, типа админок и всяких вьюеров
Основное преимущество — программная генерация роутов. Это важно, в частности, для наследования контроллеров. Но также полезно, если есть сложная логика генерации. В сторонних библиотеках этот бандо лучше не использовать.
У меня есть подозрение, что функцию `routes` можно объявить как static, иначе создается иллюзия, что `routes` может возвращать разные значения в зависимости от runtime. Но это далеко не так из-за кэширования
вам не кажется это нарушением SRP и избыточной сцепленностью ради знания имени класса? вы передаете в класс отдельный набор зависимостей для того чтобы вызвать отдельный метод только на этапе компиляции контейнера и в рантайме этот метод абсолютно бесполезен, т.к актуальные данные есть в кэше роутинга
напрашивается закономерный вопрос о декомпозиции этой логики в отдельный сервис и построении загрузчика роутов вокруг нее
Основное преимущество — программная генерация роутов
оставлю это здесь: https://symfony.com/doc/master/bundles/FOSRestBundle/5-automatic-route-generation_single-restful-controller.html
Чтобы endpoint заработал, достаточно зарегистрировать его как сервис в symfony. Больше ничего делать не нужно — бандл сам обнаружит endpoint и добавит его роуты в общий список роутов приложения.
На этапе генерации кеша или в рантайме?
<?php
use Doctrine\ORM\EntityManagerInterface;
use PaLabs\EndpointBundle\EndpointInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Route;
abstract class BaseEntityListController implements EndpointInterface {
protected $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
protected abstract function className(): string;
public function routes()
{
return new Route(sprintf("/rest/%s/list", $this->sectionName()));
}
public function execute(Request $request): Response
{
// do work
$this->em->getRepository($this->className())->findAll();
}
protected function sectionName(): string {
$reflection = new \ReflectionClass($this->className());
return $reflection->getShortName();
}
}
class SomeEntityController extends BaseEntityListController {
protected function className(): string
{
return MyEntity::class;
}
}
PaEndpointBundle — альтернатива контроллерам Symfony