Symfony 2: Autogenerated navigation menus

2019-02-07 15:29发布

问题:

Anyone know a good principle or maybe a bundle for dealing with navigation menus in symfony2?

I've tried the Knp bundle, but it's just setters and getters. I though of a functionality where controllers will match my main menu, actions will match the submenu and additional parameters could be mapped to a sub-sub menu.

I thought that I could make my application that each entry in my main menu will relate to a XController.php and each entry in the submenu under it will relate to an xAction in the same controller. Knp is quite flexible, but (as far as I understand) does not support such mapping.

The main navigation entry should be active when we are in the related Controller no matter of the action or any other parameters. And here's the problem. In symfony's config you have _controller: ABBundle:NameController:nameAction, extracting the controller and action name from which is quite heavy, and not a good idea to run on every page load. If I match the whole _controller string then my main menu entries wont be active independant of the action..

Also I thought even breadcrumbs could be generated by this schema, the first link would be a copy of the active link from the main navigation, the second could be the active entry of the sub navigation menu and the rest could be set via the controller according to logic.

Any ideas?

回答1:

I did it this way. I've registered the KnpMenu as a service and passed the entityManager to the class.

stex_site_main.menu_builder:
    class: Stex\SiteBundle\Menu\MenuBuilder
    arguments: ["@knp_menu.factory", "@doctrine.orm.entity_manager"]

stex_site_main.menu.main:
    class: Knp\Menu\MenuItem
    factory_service: stex_site_main.menu_builder
    factory_method: createMainMenu
    arguments: ["@request"]
    scope: request
    tags:
        - { name: knp_menu.menu, alias: main }

With EM in hand I open an Entity MyMenu and generate menu entries written in the db.

private $factory;
private $em;
public function __construct(FactoryInterface $factory, \Doctrine\ORM\EntityManager $em)
{
    $this->factory = $factory;
    $this->em = $em;
}
public function createMainMenu(\Symfony\Component\HttpFoundation\Request $request)
{
    $menu = $this->factory->createItem('root');
    $menu->setChildrenAttribute('class', 'menu');
    $menu->addChild(' ', array('route' => 'stex_site_home_home', 'attributes' => array('class' => 'home')));
    $menu->setCurrentUri($request->getRequestUri());
    $em = $this->em;
    $q = $em->createQuery('
        SELECT m
        FROM StexAdminBundle:MyMenu m
        WHERE m.status=1
        ORDER BY menu.position');
    $r = $q->getResult();
    foreach($r as $menu) {
        $menu->addChild($menu->getName(), array('route' => $menu->getRoute(), 'routeParameters' => array(json_decode($menu->getParams())));
    }
    return $menu;
}

Mapping controllers to menu entries (and sub sub sub etc.) is very rare case in real world app (according to me) and will not be very usable (thought you will have to code mostly 'exceptions' which controller not to include, etc.).

Having DB menu is the solution for me. Very flexible, users can edit it with nice interface etc.