Symfony 6.2+如何在#[Template]属性中不指定模板名加载模板?
实现Symfony #[Template]自动推断模板路径的方案
现状说明
Symfony原生的#[Template]属性(替代已停更的SensioFrameworkExtraBundle的@Template注解)默认要求显式指定模板路径,无法像旧注解那样自动推断。但有两种方式可以实现类似旧注解的自动加载功能:
方法一:利用Symfony原生约定(推荐)
Symfony控制器动作如果返回数组或直接返回void(无返回值),会自动按照以下规则推断模板路径:templates/[控制器名(去掉Controller后缀,小写)]/[动作名(小写)].html.twig
比如AdminController的index动作,会自动加载templates/admin/index.html.twig,完全不需要添加#[Template]属性:
#[Route('/admin', name: 'admin_login')] public function index(Request $request) { // 业务逻辑,返回模板所需变量数组 return [ 'someVariable' => $value ]; }
这是Symfony核心的默认行为,无需额外配置,完全匹配旧@Template()的效果。
方法二:自定义属性实现自动推断(适合必须用属性的场景)
如果一定要通过属性实现自动推断,可以自定义属性和事件订阅器来模拟旧注解的逻辑:
1. 创建自定义AutoTemplate属性
// src/Attribute/AutoTemplate.php namespace App\Attribute; #[\Attribute(\Attribute::TARGET_METHOD)] class AutoTemplate { }
2. 编写事件订阅器处理模板推断
// src/EventSubscriber/AutoTemplateSubscriber.php namespace App\EventSubscriber; use App\Attribute\AutoTemplate; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\ViewEvent; use Symfony\Component\HttpKernel\KernelEvents; use Twig\Environment; class AutoTemplateSubscriber implements EventSubscriberInterface { public function __construct(private Environment $twig) { } public static function getSubscribedEvents(): array { return [ KernelEvents::VIEW => 'onKernelView', ]; } public function onKernelView(ViewEvent $event): void { $controller = $event->getController(); if (!is_array($controller)) { return; } [$controllerInstance, $methodName] = $controller; $reflectionMethod = new \ReflectionMethod($controllerInstance::class, $methodName); $autoTemplateAttr = $reflectionMethod->getAttributes(AutoTemplate::class)[0] ?? null; if (!$autoTemplateAttr) { return; } // 提取控制器名(去掉Controller后缀)并转小写 $controllerClass = $controllerInstance::class; $controllerName = strtolower(preg_replace('/Controller$/', '', basename(str_replace('\\', '/', $controllerClass)))); // 拼接模板路径 $templatePath = sprintf('%s/%s.html.twig', $controllerName, $methodName); // 检查模板是否存在,避免抛出未找到异常 if (!$this->twig->getLoader()->exists($templatePath)) { throw new \RuntimeException(sprintf('模板 "%s" 不存在。', $templatePath)); } // 渲染模板并设置响应 $event->setResponse($this->twig->render($templatePath, $event->getControllerResult())); } }
3. 在控制器中使用自定义属性
#[Route('/admin', name: 'admin_login')] #[AutoTemplate] public function index(Request $request) { return [ 'someVariable' => $value ]; }
内容的提问来源于stack exchange,提问作者Armen
相关产品推荐
相关产品推荐

