Symfony2 KnpMenuBundle: активировать элемент меню, даже если его нет в этом меню

Я создал свой конструктор меню, и он работает. Один из моих маршрутов

/database 

Но у этого есть детский маршрут:

 database/view/{id} 

Я не хочу помещать маршрут просмотра в элементы меню, потому что без ID он не будет работать.

Но я хочу, чтобы маршрут базы данных был активным, когда пользователь находится на виду.

Как я могу это сделать?

Удалось решить это с помощью этого маленького взлома:

в menuBuider после того, как вы добавите всех детей, но перед возвратом меню, которое я добавил

 $request = $this->container->get('request'); $routeName = $request->get('_route'); switch ($routeName) { case 'battlemamono_database_view_by_name': case 'battlemamono_database_view_by_id': $database->setCurrent(true); break; } 

это проверяет маршруты и устанавливает необходимое меню.

Это не задокументировано, но правильный способ сделать это сейчас (например):

  $menu->addChild('Category', [ 'route' => 'category_show', 'routeParameters' => ['slug' => $category->getSlug()], 'extras' => [ 'routes' => [ [ 'route' => 'thread_show', 'parameters' => ['categorySlug' => $category->getSlug()] ], ], ], ]); 

Вы можете пропустить параметры, если они вам не нужны.

Я уже несколько дней ломаю голову над этой проблемой, и я думаю, что придумал самое чистое решение для решения этой проблемы, используя конфигурацию маршрутизации и пользовательский избиратель. Поскольку речь идет о компоненте Symfony Routing, я предполагаю, что вы используете инфраструктуру Symfony или имеете достаточные знания Symfony, чтобы заставить ее работать самостоятельно.

Создание пользовательского избирателя

 <?php # src/AppBundle/Menu/RouteKeyVoter.php namespace AppBundle\Menu; use Knp\Menu\ItemInterface; use Knp\Menu\Matcher\Voter\VoterInterface; use Symfony\Component\HttpFoundation\Request; /** * Voter based on routing configuration */ class RouteKeyVoter implements VoterInterface { /** * @var Request */ private $request; public function __construct(Request $request = null) { $this->request = $request; } public function setRequest(Request $request) { $this->request = $request; } public function matchItem(ItemInterface $item) { if (null === $this->request) { return null; } $routeKeys = explode('|', $this->request->attributes->get('_menu_key')); foreach ($routeKeys as $key) { if (!is_string($key) || $key == '') { continue; } // Compare the key(s) defined in the routing configuration to the name of the menu item if ($key == $item->getName()) { return true; } } return null; } } 

Зарегистрировать избирателя в контейнере

 # app/config/services.yml services: # your other services... app.menu.route_key_voter: class: AppBundle\Menu\RouteKeyVoter scope: request tags: - { name: knp_menu.voter } 

 <!-- xml --> <service id="app.menu.route_key_voter" class="AppBundle\Menu\RouteKeyVoter"> <tag name="knp_menu.voter" request="true"/> </service> 

Обратите внимание, что они не были полностью протестированы. Оставьте комментарий, если я должен улучшить ситуацию.

Настройка клавиш меню

После того как вы создали пользовательский избиратель и добавили его в настроенный «Матчи», вы можете настроить текущие пункты меню, добавив по умолчанию параметр _menu_key . Ключи могут быть разделены с помощью | ,

 /** * @Route("/articles/{id}/comments", * defaults={ * "_menu_key": "article|other_menu_item" * } * ) */ public function commentsAction($id) { } 

 article_comments: path: /articles/{id}/comments defaults: _controller: AppBundle:Default:comments _menu_key: article|other_menu_item по article_comments: path: /articles/{id}/comments defaults: _controller: AppBundle:Default:comments _menu_key: article|other_menu_item 

 <route id="article_comments" path="/articles/{id}/comments"> <default key="_controller">AppBundle:Default:comments</default> <default key="_menu_key">article|other_menu_item</default> </route> 

Вышеупомянутые конфигурации будут соответствовать следующему пункту меню:

 $menu->addChild('article', [ // <-- matched name of the menu item 'label' => 'Articles', 'route' => 'article_index', ]);