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; // &lt;- ç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-&gt;createItem('menu');</p>

<p>$menu-&gt;addChild('Menu 1', array('route' =&gt; '_a_funky_route'));
$menu-&gt;addChild('Menu 2', array('route' =&gt; '_say_my_name', 'routeParameters' =&gt; array('myName' =&gt; 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-&gt;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-&gt;container-&gt;get('request');</p>

<p>if ($item-&gt;getUri() === $request-&gt;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-&gt;getExtra('routes') !== null &amp;&amp; in_array($request-&gt;attributes-&gt;get('_route'), $item-&gt;getExtra('routes'))) {
return true;
}</p>

<p>return null;
}
}

Ce bout de code Xml est à placer dans config/service.xml

&lt;service id="waldo.voter.request" class="WaldoMyFunTaStikBundleVoterRequestVoter"&gt;
&lt;tag name="knp_menu.voter" /&gt;
&lt;argument type="service" id="service_container" /&gt;
&lt;/service&gt;

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.

Tagués avec :

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.