Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Symfony2 KnpMenu TwitterBootstrap switch user menu
<?php
namespace Ormigo\Bundle\BackofficeBundle\Menu;
use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAware;
use Ormigo\Bundle\UserBundle\Model\User\UserQuery;
use Symfony\Component\Security\Core\Role\SwitchUserRole;
class Builder extends ContainerAware
{
public function mainMenu(FactoryInterface $factory)
{
$menu = $factory->createItem('root');
$menu->setCurrentUri($this->container->get('request')->getRequestUri());
$menu->addChild('Dashboard', array(
'uri' => '#',
));
$menu->addChild('Demo View', array(
'route' => 'demo',
));
return $menu;
}
public function switchUserMenu(FactoryInterface $factory)
{
$menu = $factory->createItem('root');
$menu->setAttributes(array(
'class' => 'pull-right',
'dropdown' => true,
'divider_append' => true,
));
$menu->setLabel('Switch User');
$securityContext = $this->container->get('security.context');
if ($securityContext->isGranted('ROLE_ALLOWED_TO_SWITCH') or $securityContext->isGranted('ROLE_PREVIOUS_ADMIN')) {
// The current (may be switched) username.
$username = $securityContext->getToken()->getUser()->getUsername();
// The actual user, if switched, retrieve the correct one.
$actualUser = $securityContext->getToken()->getUser();
foreach ($securityContext->getToken()->getRoles() as $role) {
if ($role instanceof SwitchUserRole) {
$actualUser = $role->getSource();
break;
}
}
foreach (UserQuery::create()->find() as $eachUser) {
// only show links to different users
if ($username !== $eachUser->getUsername()) {
$menu->addChild($eachUser->getUsername(), array('uri' => '?_switch_user='.$eachUser->getUsername()));
}
}
$menu->addChild($actualUser->getUsername(), array('uri' => '?_switch_user=_exit'));
}
return $menu;
}
}
{% extends "knp_menu.html.twig" %}
{% block list %}
{% import "knp_menu.html.twig" as macros %}
{% set is_dropdown = listAttributes.dropdown|default(false) %}
{% set divider_prepend = listAttributes.divider_prepend|default(false) %}
{% set divider_append = listAttributes.divider_append|default(false) %}
{# unset bootstrap specific attributes #}
{% set listAttributes = listAttributes|merge({'dropdown': null, 'divider_prepend': null, 'divider_append': null }) %}
{% if item.hasChildren and options.depth is not sameas(0) and item.displayChildren %}
{% if is_dropdown %}
<ul{{ macros.attributes(listAttributes)}}>
{% if divider_prepend %}
<li class="divider-vertical"></li>
{% endif %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ item.label }} <b class="caret"></b></a>
<ul class="dropdown-menu">
{{ block('children') }}
</ul>
</li>
{% if divider_append %}
<li class="divider-vertical"></li>
{% endif %}
</ul>
{% else %}
{{ parent() }}
{% endif %}
{% endif %}
{% endblock %}
services:
twitter_bootstrap.menu_renderer:
class: Ormigo\Bundle\BackofficeBundle\Menu\TwitterBootstrapRenderer
arguments:
- @twig
- 'BackofficeBundle:Menu:menu_bootstrap.html.twig'
tags:
- { name: knp_menu.renderer, alias: bootstrap }
<?php
namespace Ormigo\Bundle\BackofficeBundle\Menu;
use Knp\Menu\ItemInterface;
use Knp\Menu\Renderer\TwigRenderer;
class TwitterBootstrapRenderer extends TwigRenderer
{
public function render(ItemInterface $item, array $options = array())
{
$options = array_merge(
array('currentClass' => 'active'),
$options
);
if ('root' === $item->getName()) {
$item->setAttribute('class', trim('nav '.$item->getAttribute('class')));
}
return parent::render($item, $options);
}
}
@fralex
Copy link

fralex commented Mar 28, 2013

Hello,

Thanks for the great code.
If I register my service, I get the following error:

Catchable Fatal Error: Argument 4 passed to Knp\Menu\Renderer\TwigRenderer::__construct() must be of the type array, null given, called in /home/fralex/dev/projects/.../app/cache/dev/appDevDebugProjectContainer.php on line 1622 and defined in /home/fralex/dev/projects/.../vendor/knplabs/knp-menu/src/Knp/Menu/Renderer/TwigRenderer.php line 23

What is wrong?
What KnpMenuBundle version you use?

fralex

@gondo
Copy link

gondo commented Apr 25, 2014

last missing bit is the example how to actually render the menu.
{{ knp_menu_render('main', {}, 'bootstrap') }}
more info in documentation:
https://github.com/KnpLabs/KnpMenuBundle/blob/master/Resources/doc/custom_renderer.md

@gondo
Copy link

gondo commented Apr 25, 2014

@fralex:
services.yml should have one more argument, @knp_menu.matcher

services:
    twitter_bootstrap.menu_renderer:
        class: Ormigo\Bundle\BackofficeBundle\Menu\TwitterBootstrapRenderer
        arguments:
            - @twig
            - 'BackofficeBundle:Menu:menu_bootstrap.html.twig'
            - @knp_menu.matcher
        tags:
            - { name: knp_menu.renderer, alias: bootstrap }

@gondo
Copy link

gondo commented Apr 28, 2014

in fact, you don't need custom renderer at all. you can achieve this just in menu builder:

$sub = $menu->addChild('Sub', array(
    'uri' => '#',
    'linkAttributes' => array(
        'class' => 'dropdown-toggle',
        'data-toggle' => 'dropdown',
    ),
    'childrenAttributes' => array(
        'class' => 'dropdown-menu',
    ),
    'attributes' => array(
        'class' => 'dropdown',
    ),
));
foreach ($subMenuItems as $item) {
    $sub->addChild($item['name'], array(
        'route' => $item['route'],
    ));
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment