【问题标题】:How could @Template refer to route instead of action name@Template 如何引用路由而不是操作名称
【发布时间】:2014-03-06 03:34:43
【问题描述】:

我想更改 @Template 注释的默认行为,它会自动呈现名为控制器操作的模板。

所以在ArticleController.php

/**
 * @Route("/new", name="article_new")
 * @Method("GET")
 * @Template()
 */
public function newAction()
{
    // ...
    return array();
}

将呈现Article/new.html.twig

我想将其更改为引用调用该操作的路由的名称,这样您就可以为一个操作有多个路由,每个路由都呈现不同的模板。

这是我目前的做法(没有@Template):

/**
 * @Route("/new", name="article_new")
 * @Route("/new_ajax", name="article_new_ajax")
 * @Method("GET")
 */
public function newAction()
{
    // ...
    $request = $this->getRequest();
    $route = $request->attributes->get('_route');
    $template = 'AcmeDemoBundle:' . $route . '.html.twig';

    return $this->render($template, array(
        // ...
    ));
}

我现在想知道是否有办法改变@Template 的行为来做到这一点。有没有办法自定义注释,或者只是一些让它更自动化的方法? 有什么想法吗?

【问题讨论】:

    标签: symfony annotations routes templating


    【解决方案1】:

    FOSRestBundle 包含与 @Template 类似的功能,但在类级别,因为 my pull request 如果您在类级别使用 @View 注释。

    如果希望您的模板文件名反映 action-names 而不是路由名(与问题中要求的相反),这可能很有用。

    渲染的模板将是...

    <controller-name>/<action-name>.html.twig
    

    ... 用于 HTML 视图。

    示例:AcmeBundle\Controller\PersonController::create() 将呈现

     AcmeBundle/Resources/views/Person/create.html.twig 
    

    在 PR 之前,您必须注释每个方法。

    注解一个方法仍然可以覆盖模板、模板变量和状态码。

    示例:

    /**
     * @FOSRest\View(templateVar="testdata", statusCode=201)
     */
    class PersonController implements ClassResourceInterface
    {
        public function newAction()
        {
            return $this->formHandler->createForm();
    
            // template: Person/new.html.twig 
            // template variable is 'form'
            // http status: 201
        }
    
        public function helloAction()
        {
            return "hello";
    
            // template: Person/hello.html.twig
            // template variable 'testdata' 
            // http status: 201
        }
    
        /**
         * @FOSRest\View("AnotherBundle:Person:get", templatevar="person")
         */
        public function getAction(Person $person)
        {
            return $person;
    
            // template: AnotherBundle:Person:get 
            // template variable is 'person' 
            // http status: 201
        }
    
        /**
         * @FOSRest\View("AnotherBundle:Person:overview", templatevar="persons", statusCode=200)
         */
        public function cgetAction()
        {
            return $this->personManager->findAll();
    
            // template: AnotherBundle:Person:overview 
            // template variable is 'persons'
            // http status: 200
        }
    
        // ...
    

    【讨论】:

    • 我真的不明白这与我的问题有什么关系。我希望它不基于访问操作的路径而不定义其他任何内容。我现在正在研究基于 kernelView 事件的解决方案。
    • 猜我误解了这个问题 - 读得太快了。答案可能仍然对其他人有帮助。您希望 route-name 而不是 action-name 作为模板文件名,对吗?
    【解决方案2】:

    我现在找到了使用 kernelView 事件的解决方案。这与 @Template 注释无关。只要控制器操作未返回响应对象,就会触发 kernelView 事件。

    (此方案基于 Symfony 2.4)

    事件监听服务:

    services:
        kernel.listener.route_view:
            class: Acme\DemoBundle\Templating\RouteView
            arguments: ["@request_stack", "@templating"]
            tags:
                - { name: kernel.event_listener, event: kernel.view }
    

    事件监听类:

    namespace Acme\DemoBundle\Templating;
    
    use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
    use Symfony\Component\HttpFoundation\RequestStack;
    use Symfony\Component\HttpFoundation\Response;
    
    class RouteView
    {
        protected $controller;
        protected $route;
        protected $templating;
    
        function __construct(RequestStack $requestStack, $templating)
        {
            $this->controller = $requestStack->getCurrentRequest()->attributes->get('_controller');
            $this->route      = $requestStack->getCurrentRequest()->attributes->get('_route');
            $this->templating = $templating;
        }
    
        public function onKernelView(GetResponseForControllerResultEvent $event)
        {
            $controllerAction = substr($this->controller, strrpos($this->controller, '\\') + 1);
            $controller = str_replace('Controller', '', substr($controllerAction, 0, strpos($controllerAction, '::')));
            $template = 'AcmeDemoBundle:' . $controller . ':' . str_replace(strtolower($controller) . '_', '', $this->route) . '.html.twig';
    
            $response = $this->templating->renderResponse($template, $event->getControllerResult());
    
            $event->setResponse($response);
        }
    }
    

    现在控制器的行为如下:

    /**
     * @Route("/new", name="article_new")           -> Article:new.html.twig
     * @Route("/new_ajax", name="article_new_ajax") -> Article:new_ajax.html.twig
     * @Method("GET")
     */
    public function newAction()
    {
        // ...
    
        return array();
    }
    

    【讨论】:

    • 感谢分享:)
    猜你喜欢
    • 2017-09-23
    • 2013-09-10
    • 1970-01-01
    • 1970-01-01
    • 2017-09-05
    • 1970-01-01
    • 2018-01-04
    • 2011-03-18
    • 1970-01-01
    相关资源
    最近更新 更多