iCheater Retaehci
iCheater Retaehci

Reputation: 89

Symfony : Route overrides other templates

The problem is in strange behavior of route @Route("/{cityId}"). When this route is upper, than other routes (for example @Route("/editcity_{id}")), it overrides template.

Look at screenshots:

When I try to go to the /editcity_2 route /2 handles request and city.html.twig show this error :

Here what i have:

CityController.php :

   <?php
   namespace AppBundle\Controller;
   use AppBundle\Entity\City;
   use AppBundle\Form\Type\CityType;
   use Symfony\Bundle\FrameworkBundle\Controller\Controller;
   use Symfony\Component\HttpFoundation\Request;
   use Symfony\Component\HttpFoundation\Response;
   use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
   class CityController extends Controller
   {
   /**
    * @Route("/addcity")
    * @param Request $request
    * @return Response
    */
   public function addCityAction(Request $request) {
    $city = new City();
    $form = $this->createForm(CityType::class, $city);
    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($city);
        $em->flush();
        return new Response('Created city id '.$city->getId());
    }
    return $this->render(':appviews:addCity.html.twig', array(
        'form' => $form->createView(),
    ));
}
/**
 * @Route("/cities")
 */
public function citiesAction(){
    $em = $this->getDoctrine()->getEntityManager();
    $cities = $em->getRepository('AppBundle:City')->findAll();
    return $this->render('appviews/citiesList.html.twig',array('cities'=>$cities));
}

/**
 * @Route("/{cityId}")
 */
public function cityAction($cityId) {
    $em = $this->getDoctrine()->getManager();
    $city = $em->getRepository('AppBundle:City')->find($cityId);
    return $this->render('appviews/city.html.twig',array(
        'city' => $city));
}

/**
 * @Route("/editcity_{id}")
 * @return Response
 */
public function editCityAction($id, Request $request) {
    $em = $this->getDoctrine()->getEntityManager();
    $city = $em->getRepository('AppBundle:City')->find($id);
    $form = $this->createForm(CityType::class, $city);
    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($city);
        $em->flush();
        return new Response('Created city id '.$city->getId());
    }

    return $this->render(':appviews:editCity.html.twig', array(
        'form' => $form->createView(),
    ));
}

Twig template, city.html.twig

{% extends "appviews/base.html.twig" %}
{% block title %}Cтраница города {% endblock %}
{% block body %}
{{ dump(city)}}
{{ city.link }}
{% endblock %}

Upvotes: 1

Views: 147

Answers (1)

akmozo
akmozo

Reputation: 9839

What you got is a normal behavior because

the Symfony router will always choose the first matching route it finds

and your /{cityId} route is equivalent to /* which is true for these URLs for example :

  • /123
  • /add-new-article
  • /edit-123
  • /article-123.html
  • /123-article.html

So your /editcity_{id} route will never be matched as it's a case of your /{cityId} one. But you can avoid that by adding route requirements or route conditions like this :

/**
 * @Route("/{cityId}", requirements={ "cityId": "\d+" })
 */

The \d+ requirement is a regular expression that says that the value of the {cityId} parameter must be a digit (i.e. a number).

and after that, an URL like /editcity_123 will never match the /{cityId} route but only the /editcity_{id} one.

So don't forget to add requirements to your routes to get a clear code and to avoid such problem, of course when you need that.

Réf. : http://symfony.com/doc/current/book/routing.html#adding-requirements

Hope that can help.

Upvotes: 1

Related Questions