wemakecustom / menu-part-bundle
Symfony Bundle wrapping KnpMenuBundle to declare menus by small parts
Requires
- php: >=5.3.3
- knplabs/knp-menu-bundle: ~2.0
- symfony/framework-bundle: ^2.1|^3.0
README
Wrapper around knplabs/knp-menu-bundle
to easily create partial self contained menu providers.
The goal is to create global menus (main, top, sidebar, etc.) and have different services fill them when they see fit. An example would be a sidebar that offers actions (edit, delete, etc.) on the current resource.
This bundle really needs tests though…
WARNING: This bundles requries KnpMenuBundle ~2.0.
Installation
Download and install the bundle via composer
$ php composer.phar require wemakecustom/menu-part-bundle
Enable the Bundle (and its dependencies) in the Kernel:
<?php // app/AppKernel.php public function registerBundles() { $bundles = array( // ... new Knp\Bundle\MenuBundle\KnpMenuBundle(), new WMC\MenuPartBundle\WMCMenuPartBundle(), ); }
Creating your first menu
Using JMSDiExtraBundle
,
you can simply create a class that extends MenuPartInterface
:
<?php // src/Acme/DemoBundle/Menu/UserMenu.php namespace Acme\DemoBundle\Menu; use WMC\MenuPartBundle\Menu\MenuPartInterface; use JMS\DiExtraBundle\Annotation\Service; use JMS\DiExtraBundle\Annotation\Tag; use JMS\DiExtraBundle\Annotation\Inject; use JMS\DiExtraBundle\Annotation\InjectParams; use Knp\Menu\MenuItem; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; /** * @Service(public=false) * @Tag("wmc.menu_part", attributes={"menu" = "user"}) */ class UserMenu implements MenuPartInterface { protected $authorizationChecker; /** * @InjectParams({ * "authorizationChecker" = @Inject("security.authorization_checker") * }) */ public function __construct(AuthorizationCheckerInterface $authorizationChecker) { $this->authorizationChecker = $authorizationChecker; } public function addMenuParts(MenuItem $menu) { if ($this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED')) { $menu->addChild('Profile', array('route' => 'fos_user_profile_show')); } } } ?>
Notice the menu
attribute set to user
, this is mandatory.
You can create multiple MenuPartInterface
with the same menu name and they will
concatenante themselves. You can also use the priority
tag attribute to modify the order.
This is a service, so inject whatever you need: request_stack
, security.authorization_checker
, etc.
If you are not using JMSDiExtraBundle
, you can of course
use the traditional way. See HomeMenu.php
and menu.yml
Integration in template
Simply knp_menu_render
in your template with the name of your menu.
{{ knp_menu_render('user') }}
Configuration
Out of the box, the bundle does not require any configuration.
When you create MenuPartInterface
, a menu will automatically be created with default options.
You can however specify additional options in the general bundle configuration:
# app/config/config.yml wmc_menu_part: menus: # Applies to all menus, same options as below. _all: # Useful for Bootstrap menus, etc. class: "nav-menu" my_menu: # Services that will iterates through menu items and possibly hide or modify them. visitors: - wmc.menu_part.filter.security # ID of a Service implementing MenuVisitorInterface ## May also be specified with a priority. # the lowest the priority, the earliest the visitor will be run # wmc.menu_part.visitor.l10n: { priority: 99 } class: "my-awesome-menu" ## May also be specified as a list # - menu # - main-menu # Additionnal attributes # Use above for classes attributes: id: "my-menu"
Provided Visitors
Security filter
This filter (service name: wmc.menu_part.filter.security
) will hide items the
current user isn't allowed to access.
The current version of this filter relies only on the firewall and doesn't check
the @Security
annotations. (TODO)
Localization (L10n) visitor
You first need to enable the visitor for the menus you want to translate.
The following example enable the visitor for all menus:
wmc_menu_part: menus: _all: visitors: - wmc.menu_part.visitor.l10n
This visitor will call the translator
service on every menu item. The visitor
can be disabled for choosen items by setting the translation_parameters
extra to false
.
To specify a custom translation domain, you can use the translation_domain
extra.
If transChoice
is to be used, specify the translation_number
extra.
The item's label will be used as translation key.
Example:
// Assuming the L10n visitor is enabled for the current menu. // Translated with trans, using no parameters and the default translation domain $menu->addChild('home', ['route' => 'home']); // Translated with trans, using the %username% parameter // and the FOSUserBundle translation domain $menu->addChild('account', [ 'route' => 'my_account', 'extras' => [ 'translation_parameters' => ['%username%' => $user], 'translation_domain' => 'FOSUserBundle', ] ]); // Translated with transChoice $menu->addChild('notifications', [ 'route' => 'my_notifications', 'extras' => [ 'translation_number' => $user->getNotifications()->count(), ] ]); // Not translated $menu->addChild(':)', [ 'route' => 'happy', 'extras' => [ 'translation_parameters' => false, ] ]);
Provided Voters
Voters are used to detect the current item(s) in the menu.
See voters.yml
on how to use RequestVoter
and PrefixVoter
. The file can also be imported as-is in
app/config/config.yml
.