-
Notifications
You must be signed in to change notification settings - Fork 202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Matching current MenuItem #122
Comments
@phiamo currently, the voters are not registered in the bundle itself (so only the current flag on the item is used to decide). You need to register a voter for the matching (thanks to the |
no prob, i will have a lot of time to wait :) So you planned to add some default voters like the uri and the route voter? i didnt yet get the clue how this is done, need to review the code,when having a bit more time ... |
In an effort to ease other peoples issues here until a PR lands, here is the voter I've written to do matching: <?php
// src/merk/Voter/RequestVoter.php
namespace merk\Voter;
use Knp\Menu\ItemInterface;
use Knp\Menu\Matcher\Voter\VoterInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Voter based on the uri
*/
class RequestVoter implements VoterInterface
{
/**
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* 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)
{
if ($item->getUri() === $this->container->get('request')->getRequestUri()) {
return true;
}
return null;
}
} And its service definition in config.yml merk.voter.request:
class: merk\Voter\RequestVoter
arguments:
- @service_container
tags:
- { name: knp_menu.voter } I'm waiting on some feedback from @stof if this is appropriate given the Matcher is not request scoped, and once blessed I will prepare a PR. |
@merk thanks a lot :o |
I follow this new matchers ans made the RouteVoter working for my SF 2.1 app. For that i extended the RouteVoter class with my implementation of RouteVoter: <?php
namespace Artack\QSDNSBundle\Menu;
use Knp\Menu\Silex\Voter\RouteVoter as BaseRouteVoter;
class RouteVoter extends BaseRouteVoter
{
public function __construct($container)
{
$this->setRequest($container->get('request'));
}
} next i made the service configuration: services:
artack.qsdns.menu.voter.request:
class: Artack\QSDNSBundle\Menu\RouteVoter
arguments:
- @service_container
tags:
- { name: knp_menu.voter } And my Builder looks like that: <?php
namespace Artack\QSDNSBundle\Menu;
use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAware;
class Builder extends ContainerAware
{
public function mainMenu(FactoryInterface $factory, array $options)
{
$menu = $factory->createItem('root');
$menu->addChild('dashboard', array(
'label' => 'Dashboard',
'route' => 'dashboard'
));
$menu->addChild('dns', array(
'label' => 'Manage DNS',
'route' => 'dns'
));
$menu->addChild('aboutqsdns', array(
'label' => 'About QS DNS',
'route' => 'aboutqsdns'
));
foreach($menu as $key => $item)
{
$item->setExtra('routes', array(
'routes' => $key
));
}
return $menu;
}
} I am pretty sure there are better implementation or there will follow an implementation from stof. |
I am using the code proposed by merk and it works for me. |
Hi! before update I used this code in template: {% set currentMenuItem = knp_menu_get('MySiteBundle:Builder:mainMenu').currentItem %} to get current item. Now I'm stuck, since all getters and setters for current item removed, new Iterators introduced, but seems like no documentation exists on how to use this new functionality. To clarify I need to get current menu item to for example get it's label, some meta and build breadcrumbs on it. Can you please help? Thanks! |
|
I'm using the implementation suggested by @scuben (passing the container then setting the request manually), I think it's the best solution, there is no scope issue for not being sure to have the fresh response each time, because if you do a subrequest you'll still want to match against the real request, how would you do with the internal request? Edit: maybe we could have this service configured in the knp bundle? instead of having to create it ourselves. But if you don't access the service on the main request, you'll have the subrequest if you access it from a subrequest, not sure what would be the best implementation then... |
The RouteVoter is now enabled by default and uses against the master request (which is more sensible as it is the one coming from the client) |
To use the code snippet from @zender there needs the knp_menu.voter.router to be used instead
|
Have any solutions been merged into the master branch for this bundle? I have run ./bin/vendors update and .current is still not being applied to the menu item |
the RouterVoter is registered by default |
@stof is there any way to register invisible items to the menu tree for edit/delete actions which have a route which is based upon the object like /1/show/ or so? I want to see them in the breadcrumb but not in the default menu. What would be your suggestion? |
@peterrehm items have a |
@stof I dont think this actually helps me. I have the following route:
So when addidng the child to the menu tree it looks like that:
The issue is that I am just using this for the breadcrumb functionality. So the id needs to be flexible as well, building the menu as above is useless. How could I try to still recognize such items from the menu tree with a routeParameter? Since you have removed the currentItem functionality I now have a function for building the menu which returns the menu and an additional breadcrumMenu function which is taking the output from mainMenu and parsing it as follows:
The disadvantage I am seeing is that the menu has to be rendered twice, with is a performance disadvantage which is negotiable because I am just having a small menu tree. What is your recommendation? Thank you in advance |
@stof Can you give me any recommendations on that? By the way, what would you think about an entry in the docs about that? I guess breadcrumb is an important topic. I could help out with this if you are interested. |
Hi @peterrehm I've the same issue like as your. For fix that problem I have had a new condition in the @merk Voter class RequestVoter implements VoterInterface {
//...
public function matchItem(ItemInterface $item) {
/* @var $request \Symfony\Component\HttpFoundation\Request */
$request = $this->container->get('request');
if ($item->getUri() === $request->getRequestUri()) {
return true;
}
if ($item->getExtra('routes') !== null && in_array($request->attributes->get('_route'), $item->getExtra('routes'))) {
return true;
}
return null;
} In the condition I search if the current route exist in the item. In my menu builder I use this type of code class Builder extends ContainerAware {
//...
public function menu(FactoryInterface $factory, array $options) {
$menu = $factory->createItem('menu');
$menu->addChild('Menu Level 1', array('route' => '_an_amazing_route'));
$menu['Menu Level 1']->addChild('Menu Level 2.1', array('route' => '_route_for_edit_something', 'routeParameters' => array('something' => null)))
->setDisplay(false);
$menu['Menu Level 1']->addChild('Menu Level 2.2', array('route' => '_route_for_add_something'))
->setDisplay(false);
return $menu;
}
} I hope that will help you. |
@waldo2188 I just found time to look at it and found a solution based on yours. /**
* Voter based on the route with optional parameters
*/
class RouteVoter implements VoterInterface
{
/**
* @var Request
*/
private $request;
public function setRequest(Request $request)
{
$this->request = $request;
}
public function matchItem(ItemInterface $item)
{
if (null === $this->request) {
return null;
}
$route = $this->request->attributes->get('_route');
if (null === $route) {
return null;
}
$routes = (array) $item->getExtra('routes', array());
$parameters = (array) $item->getExtra('routesParameters', array());
foreach ($routes as $testedRoute) {
if ($route !== $testedRoute) {
continue;
}
if (isset($parameters[$route])) {
foreach ($parameters[$route] as $name => $value) {
if ($this->request->attributes->get($name) != $value) {
/* if value is set to 0 in the builder it is the wildcard for any parameter */
if($value !== 0) {
return null;
}
}
}
}
return true;
}
return null;
}
} The only disadvantage is that I cant go with null as parameter, I had to use 0 instead to avoid the error $menu['Tools']
->addChild(
'ItemShow',
array('route' => 'item_show', 'routeParameters' => array('id' => 0))
)->setDisplay(false); If I use null as you do, I am getting the error:
@stof I really think somehow such behaviour should get into the KnpMenu Core. A loto of people seem to need that. I would be willing to work on this and create the docs If you want to support and give me guidance. |
@peterrehm If you want to allow any parameter, there is no need to set it to |
@stof Is is a required parameter in the route. I am talking about the typical usecase of creating a breadcrumb tree. You always have routes to edit objects. like /article/{id}/show where I want to show the breadcrumb navigation based on any {id}. so that I still see > Article > EditArticle. If I omit the parameter get the following exception:
I think this is a generic requirement. To make this happen I need to have a way of setting a route with a dynamic parameter like
And I need to use the above in my comment #122 (comment) mentioned breadCrumb function with a voter which allows the dynamic parameter. What do you think about finding a generic solution to make the currentItem accessible and to support such dynamic routes as well as provide the documentation for this? I think this would be very helpful for a lot of users. |
Just for reference as i just spend a couple of hours on breadcrumbs and had the same problems as @peterrehm I ended up taking a different approach which is described here: Obviously this doesnt work if you want to use the same Menu Class for your Navigation and breadcrumbs, but in my case it wasnt required. If youd want that, i guess you could still build some kind of mixture of both approaches. |
Hi, |
Hi, I am able to get current item using
Is there a way to get previous and next item of menu ? This is very commonly needed like on blogs to navigate to previous and next posts. |
remove locales config (fixes KnpLabs#120)
Hi folks,
nice work!
I just updated to dev-master and dont get menu items matched anymore ...
is there any further change i have to implement, except for removing setCurrentURI calls?
cheers phil
The text was updated successfully, but these errors were encountered: