Каждый пакет экстранета является независимым приложением. В моем меню перечислены все приложения, и мне нравится отмечать текущее в зависимости от фактического префикса маршрута.
Сначала код веточки в base.html.twig:
{{ knp_menu_render('AppBundle:Builder:mainMenu', { 'currentClass': 'active'}) }}
Функция строителя:
public function mainMenu(FactoryInterface $factory, array $options){
$main = $factory->createItem('root');
foreach($this->getExtranetBundles() as $bundle){
$main->addChild($bundle->getAcronym(), array('route' => $bundle->getRoute()));
}
// Current Element
$matcher = new Matcher();
$matcher->addVoter(new BundleVoter($this->getCurrentBundle()));
$renderer = new ListRenderer($matcher);
$renderer->render($main);
return $main;
}
Мой класс BundleVoter работает правильно и возвращает true, если найдено текущее меню. Но в HTML текущий элемент никогда не содержит «активный» класс.
Я прочитал немного больше в KnpMenuBundle и добавил некоторый отладочный код в класс Knp \ Menu \ Matcher:
public function addVoter(VoterInterface $voter)
{
echo "add voter: " . get_class($voter);
$this->voters[] = $voter;
}
И получил этот вывод:
add voter: AppBundle\Menu\BundleVoter
add voter: Knp\Menu\Matcher\Voter\RouteVoter
Откуда появился таинственный RouteVoter? Перезаписывает ли мой выбор BundleVoter текущих элементов? И как я могу деактивировать / перезаписать это?
Нашел способ изменить стандартный класс knp_menu. Я отредактировал файл services.yml следующим образом:
parameters:
knp_menu.voter.router.class: AppBundle\Menu\BundleVoter
services:
appbundle.menu.voter.request:
class: AppBundle\Menu\BundleVoter
arguments: [@service_container]
tags:
- { name: knp_menu.voter }
Класс по-прежнему создается два раза, к сожалению, я должен проверить, является ли переданный параметр пустым или нет. И параметр $ container должен быть необязательным …
class BundleVoter implements VoterInterface
{
private $container;
public function __construct($container = null)
{
if($container != null)
$this->container = $container;
}
public function matchItem(ItemInterface $item)
{
if($this->container != null){
$bundle = $this->container->get('menubundles')->getCurrentBundle();
if (null === $bundle || null === $item->getName()) {
return null;
}
if ($item->getName() == $bundle->getAcronym()) {
return true;
}
}
return null;
}
}
Пожалуйста, напишите, если вы нашли лучшее решение 🙂 Thx
Других решений пока нет …