【发布时间】:2013-02-03 16:54:07
【问题描述】:
我创建了我的菜单生成器,它可以工作。 我的一条路线是
/database
但这有一个子路由:
database/view/{id}
我不想将视图路由放入菜单项,因为没有 ID 它将无法工作。
但我希望当用户在视图上时数据库路由处于活动状态。
我该怎么做?
【问题讨论】:
标签: php symfony symfony-2.1 knpmenubundle
我创建了我的菜单生成器,它可以工作。 我的一条路线是
/database
但这有一个子路由:
database/view/{id}
我不想将视图路由放入菜单项,因为没有 ID 它将无法工作。
但我希望当用户在视图上时数据库路由处于活动状态。
我该怎么做?
【问题讨论】:
标签: php symfony symfony-2.1 knpmenubundle
通过这个小技巧设法解决了这个问题:
在添加所有子项之后但在返回我添加的菜单之前在 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()]
],
],
],
]);
不需要的参数可以跳过。
【讨论】:
$category 变量是什么?
'routes' => ['thread_show', 'other_route_here']
$menu->addChild('Item name', ['route' => 'item_route']) 时,会将值['extras']['routes'][0] = 'item_route' 添加到当前子级。
所以你需要将['extra']['routes'] = []数组的路由添加到child。
这很简单。有三种方法可以做到这一点:
我推荐这种方式。 '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',
],
],
]);
->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',
]
);
->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',
]
]);
【讨论】:
我已经为这个问题绞尽脑汁好几天了,我想我想出了通过使用我的路由配置和自定义 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',
]);
【讨论】: