KnpMenuBundle Corrspondance avec le menu en cours
Le problème que concerne cet article est encore lié au KnpMenuBundle et fait suite à un précédent article sur le KnpMenuBundle et les fils d’Ariane.
Le problème que nous sommes nombreux à rencontrer, est que ce bundle ne fait pas la correspondance de route avec paramètre(s).
une route en Symfony2 peut être associé à un nom.
Par exemple si l’on utilise les annotations dans les controller, on peux avoir quelque chose comme ça :
class amazingController extends Controller { /** * @Route("/a-funky-route" name="_a_funky_route") */ public function getHeadachesAction() { //... }</p> <p>/** * @Route("/say-my-name/{myName}" name="_say_my_name", defaults={"myName"="Arthur Dent"}) */ public function sayMyNameAction($myName) { echo $myName; // <- ça c'est pas bien, c'est juste pour l'exemple ;) }
Et si l’on configure notre Menu Builder comme ce-ci :
class Builder extends ContainerAware { //... public function menu(FactoryInterface $factory, array $options) {</p> <p>$menu = $factory->createItem('menu');</p> <p>$menu->addChild('Menu 1', array('route' => '_a_funky_route')); $menu->addChild('Menu 2', array('route' => '_say_my_name', 'routeParameters' => array('myName' => null)));</p> <p>return $menu; } }
Dans ce cas de configuration, KnpMenuBundle est incapable de faire correspondre une url http://site.fr/say-my-name/Pedro avec la route _say_my_name.
C’est là où l’on va ajouter un peu de magie dans tout ça !
En premier lieu, le code de @merk que l’on va un peux améliorer.
namespace WaldoMyFunTaStikBundleVoter;</p> <p>use KnpMenuItemInterface; use KnpMenuMatcherVoterVoterInterface; use SymfonyComponentDependencyInjectionContainerInterface;</p> <p>class RequestVoter implements VoterInterface { /** * @var SymfonyComponentDependencyInjectionContainerInterface */ private $container;</p> <p>public function __construct(ContainerInterface $container) { $this->container = $container; }</p> <p>/** * Checks whether an item is current. * * If the voter is not able to determine a result, * it should return null to let other voters do the job. * * @param ItemInterface $item * @return boolean|null */ public function matchItem(ItemInterface $item) {</p> <p>/* @var $request SymfonyComponentHttpFoundationRequest */ $request = $this->container->get('request');</p> <p>if ($item->getUri() === $request->getRequestUri()) { return true; }</p> <p>// C'est ici que l'on vérifie que la route en cours d'utilisation est bien la même // que celle contenu dans l'item que nous passe le KnpMenuBundle if ($item->getExtra('routes') !== null && in_array($request->attributes->get('_route'), $item->getExtra('routes'))) { return true; }</p> <p>return null; } }
Ce bout de code Xml est à placer dans config/service.xml
<service id="waldo.voter.request" class="WaldoMyFunTaStikBundleVoterRequestVoter"> <tag name="knp_menu.voter" /> <argument type="service" id="service_container" /> </service>
Besoin de comprendre ?
$item->getExtra('routes')
contient un tableau composé de route(s) définis dans le builder de menu : $menu->addChild('Menu 1', array('route' => '_a_funky_route'));
.
Et $request->attributes->get('_route')
donne le nom de la route qui correspond à l’url de la page que l’utilisateur a appelé.
On ne se base plus sur les URLs générés, comme le fait le KnpMenuBundle par défaut, mais sur le nom des routes qui ne change jamais, paramètres ou non.
Laisser un commentaire