Symfony2 KnpMenuBundle: activate a menu item even if it is not in this menu

I created my menu constructor and it works. One of my routes is

/database

      

But this has a child route:

database/view/{id}

      

I don't want to put the view route on the menu items because without an ID it won't work.

But I want the database route to be active when the user is in the view.

How can i do this?

+3


source to share


3 answers


Managed to solve the problem with this little hack:

in the menuBuider after you add all the children, but before returning the menu, I added



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

      

this checks the routes and sets the required menu.

+9


source


This is not documented, but the correct way to do it is now (ex):

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

      



You can skip the parameters if you don't need them.

+5


source


I've been trying for a couple of days to solve this problem and I think I came up with the cleanest solution to solve this problem using routing configuration and custom voter. Since this is a Symfony Routing component, I am assuming that you are using the Symfony framework or have sufficient Symfony knowledge to make it work for you.

Create custom voter

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

      

Register a voter in a container

# 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>

      

Please note that these have not been fully tested. Leave a comment if I need to improve the situation.

Customizing Menu Keys

Once you have created a custom voter and added it to the configured Matcher, you can customize the current menu items by adding _menu_key

defaults to the route. The keys can be separated with |

.

/**
 * @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>

      

The above configurations will correspond to the following menu item:

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

      

-1


source







All Articles