1
votes

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
Can't really help you out on your main question but I will say that all of the config stuff ends up being complied into fairly efficient php code. Check the files under cache to see the results. So don't worry about most stuff being too heavy.Cerad
Yes, I decided to go and write my own service for the navigation. I think using caching will really speed things up :)Tony Bogdanov
is it possible to look at that code? I've just hit same problem to solve menus generated depending on current route parameters.Paweł Madej

1 Answers

4
votes

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.