【问题标题】:Symfony2 KnpMenuBundle: set active a menu item even when its not on that menuSymfony2 KnpMenuBundle:设置激活一个菜单项,即使它不在该菜单上
【发布时间】:2013-02-03 16:54:07
【问题描述】:

我创建了我的菜单生成器,它可以工作。 我的一条路线是

/database

但这有一个子路由:

database/view/{id}

我不想将视图路由放入菜单项,因为没有 ID 它将无法工作。

但我希望当用户在视图上时数据库路由处于活动状态。

我该怎么做?

【问题讨论】:

    标签: php symfony symfony-2.1 knpmenubundle


    【解决方案1】:

    通过这个小技巧设法解决了这个问题:

    在添加所有子项之后但在返回我添加的菜单之前在 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;
            }
    

    这会检查路线并将所需的菜单设置为活动状态。

    【讨论】:

    • 感谢您发布此信息!
    【解决方案2】:

    没有记录,但现在正确的做法是(例如):

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

    不需要的参数可以跳过。

    【讨论】:

    • 感谢您发布此内容,就像一个魅力,但如果您必须定义多个路线,我发现它非常冗长,例如一个链接下的删除、添加、编辑、信息 url,是否可以在 yml 文件中定义它们?
    • @m453h,我不知道,但我认为您不必太担心冗长。一切都不属于 yml 文件。 :)
    • MenuBuilder 类中的$category 变量是什么?
    • @Trix,你想要什么,这只是一个例子,在我的例子中,我有一个带有 slug 的 Category 实体。
    • @m453h 如果您的路线没有参数,您可以将路线数组代码减少为:'routes' => ['thread_show', 'other_route_here']
    【解决方案3】:

    $menu->addChild('Item name', ['route' => 'item_route']) 时,会将值['extras']['routes'][0] = 'item_route' 添加到当前子级。

    所以你需要将['extra']['routes'] = []数组的路由添加到child

    这很简单。有三种方法可以做到这一点:

    1. 我推荐这种方式。 'extras' 数组将被合并(无需在'routes' 中复制当前的'route'):

      $menu->addChild('Item name', [
          'route' => 'item_route', // The item link in the menu
          'extras' => [
              // Set current (active) if route matches one of the set (including route from key 'route')
              'routes' => [ 
                  'item_route_inner_1',
                  'item_route_inner_2',
                  'item_route_outside_1',
              ],
          ],
      ]);
      
    2. ->setExtra(key, value)'extras' 数组中,整个值将被键替换(当由于某种原因您不需要获取路由中指定的路由路径时,它可能很有用):

      $menu->addChild('Point name', [
          'route' => 'point_route', // route point (on click)
      ])
      // In the 'extras' array, the entire value will be replaced by the 'routes' key
      ->setExtra(
          'routes', [ // Set current (active) if route matches one of the set
              'point_route', // Can be removed, if necessary
              'point_route_inner_1',
              'point_route_inner_2',
              'point_route_outside_1',
          ]
      );
      
    3. ->setExtras(['routes'] => value) 'extras' 数组将被完全替换。 请谨慎使用!

      $menu->addChild('Point name', [
          'route' => 'point_route', // route point (on click)
      ])
      // The 'extras' array will be completely replaced
      ->setExtras([
          'routes' => [
              'point_route', // Can be removed, if necessary
              'point_route_inner_1',
              'point_route_inner_2',
              'point_route_outside_1',
          ]
      ]);
      

    【讨论】:

      【解决方案4】:

      我已经为这个问题绞尽脑汁好几天了,我想我想出了通过使用我的路由配置和自定义 Voter 来解决这个问题的最简洁的解决方案。由于这是关于 Symfony 路由组件的,我假设您正在使用 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>
      

      请注意,这些尚未经过全面测试。如果我需要改进,请发表评论。

      配置菜单键

      创建自定义 Voter 并将其添加到配置的 Matcher 后,您可以通过将 _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
      

      <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',
      ]);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-24
        • 1970-01-01
        • 2010-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-17
        • 1970-01-01
        相关资源
        最近更新 更多