繁体   English   中英

Symfony2 KnpMenuBundle:设置一个菜单项,即使它不在该菜单上

[英]Symfony2 KnpMenuBundle: set active a menu item even when its not on that menu

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

/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;
        }

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

它没有记录,但正确的方法是现在(ex):

        $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

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

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

所以你需要将路径添加到['extra']['routes'] = []数组到子节点

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM