3

I have following method in Controller:

/**
 * @Route("/add", name="item_add")
 * @Route("/edit/{id}", name="item_edit")
 * @Template
 */
public function editAction(Request $request, Item $item = null)

This method loads edit.html.twig template because of action name.

Is it possible to force using add.html.twig template if item_add route is matched and edit.html.twig if item_edit is matched ?

hsz
  • 148,279
  • 62
  • 259
  • 315
  • Why would you combine two different behaviors `("GET", "PUT")` in a single route? If you want to reuse your templating, what's wrong with [`extending`](http://twig.sensiolabs.org/doc/tags/extends.html) your views? – Touki May 22 '14 at 14:28
  • @Touki Because the logic of get and put actions is the same. – hsz May 22 '14 at 14:36
  • If they are the same, then you can create a second route `public function editAction(Request $request) { return $this->addAction($request); }` and keep your annotations – Touki May 22 '14 at 14:41
  • @Touki You're right, however I was thikink about maximal simplicity of the controllers. – hsz May 22 '14 at 14:45

2 Answers2

3

The answer provided by jperovic seems correct however, IMHO, using the route name doesn't feel right.
Relying on the route name can be avoided with ease.

Here's an example

/**
 * @Route("/add", name="item_add")
 * @Method({"GET"})
 * @Template
 */
public function addAction(Request $request, Item $item = null)
{
    if (null === $item) {
        $item = new Item;
    }

    $form = $this->createForm(new ItemType, $item, [
        'action' => $this->generateUrl('item_update'), // In your view?
        'method' => 'POST'
    ]);

    return [
        'form' => $form->createView()
    ];
}

/**
 * @Route("/edit/{id}", name="item_edit")
 * @Method({"GET"})
 * @Template
 */
public function editAction(Request $request, Item $item)
{
    return $this->addAction($request, $item);
}

With this, you will have two routes doing almost same thing, and sending the same parameters

/edit/{id} => edit.html.twig
/add       => add.html.twig
Touki
  • 7,465
  • 3
  • 41
  • 63
2

Of course it is. tuxedo25 explained it how here: How to get current route in Symfony 2?

Basically:

$routeName = $request->get('_route');
if ( $routeName == "item_add"){
    // render template "add.html.twig"
}else{
    // render template "edit.html.twig"
}

Hope this helps...


Idea #1:

If you want to use @Template you could still keep the annotation as usual but you would:

return array(
            'route_name' => $routeName,
            // some other data
            );

Then:

item.html.twig

{% include routeName == 'item_add' ? 'item_add.html.twig' : 'item_edit.html.twig' %}

Nevertheless, while this solves the issue, I feel like it's very cumbersome. Personally I would never go this way.


Idea #2:

This idea takes whole different angle. While it does not use @Template it minimizes the possibility of error:

/**
 * @Route("/add", name="item_add")
 * @Route("/edit/{id}", name="item_edit")
 */
public function editAction(Request $request, Item $item = null){
    $routeName = $request->get('_route');

    # Your controller's logic here

    return $this->renderView(sprintf('VendorNamespaceBundle:ControllerClass:%s.html.twig', $routeName), aray(... your data here ... ));
}
Community
  • 1
  • 1
Jovan Perovic
  • 19,846
  • 5
  • 44
  • 85
  • Is it possible to do it without manually rendering template - just stil using `@Template` annotation ? – hsz May 22 '14 at 13:09
  • No, I don't think that's possible. I have an idea on how to overcome this... updating the answer now... – Jovan Perovic May 22 '14 at 13:50