This commit is contained in:
Xes
2025-08-14 22:41:49 +02:00
parent 2de81ccc46
commit 8ce45119b6
39774 changed files with 4309466 additions and 0 deletions

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="knp_menu.factory.class">Knp\Menu\MenuFactory</parameter>
<parameter key="knp_menu.factory_extension.routing.class">Knp\Menu\Integration\Symfony\RoutingExtension</parameter>
<parameter key="knp_menu.helper.class">Knp\Menu\Twig\Helper</parameter>
<parameter key="knp_menu.matcher.class">Knp\Menu\Matcher\Matcher</parameter>
<parameter key="knp_menu.menu_provider.chain.class">Knp\Menu\Provider\ChainProvider</parameter>
<parameter key="knp_menu.menu_provider.container_aware.class">Knp\Bundle\MenuBundle\Provider\ContainerAwareProvider</parameter>
<parameter key="knp_menu.menu_provider.builder_alias.class">Knp\Bundle\MenuBundle\Provider\BuilderAliasProvider</parameter>
<parameter key="knp_menu.renderer_provider.class">Knp\Bundle\MenuBundle\Renderer\ContainerAwareProvider</parameter>
<parameter key="knp_menu.renderer.list.class">Knp\Menu\Renderer\ListRenderer</parameter>
<parameter key="knp_menu.renderer.list.options" type="collection"></parameter>
<parameter key="knp_menu.listener.voters.class">Knp\Bundle\MenuBundle\EventListener\VoterInitializerListener</parameter>
<parameter key="knp_menu.voter.router.class">Knp\Menu\Matcher\Voter\RouteVoter</parameter>
</parameters>
<services>
<service id="knp_menu.factory" class="%knp_menu.factory.class%" public="true" />
<service id="knp_menu.factory_extension.routing" class="%knp_menu.factory_extension.routing.class%" public="false">
<argument type="service" id="router" />
<tag name="knp_menu.factory_extension" />
</service>
<service id="knp_menu.helper" class="%knp_menu.helper.class%" public="false">
<argument type="service" id="knp_menu.renderer_provider" />
<argument type="service" id="knp_menu.menu_provider" />
<argument type="service" id="knp_menu.manipulator" />
<argument type="service" id="knp_menu.matcher" />
</service>
<service id="knp_menu.matcher" class="%knp_menu.matcher.class%" public="true">
<argument type="collection" />
</service>
<service id="Knp\Menu\Provider\MenuProviderInterface" alias="knp_menu.menu_provider" public="false"/>
<service id="knp_menu.menu_provider.chain" class="%knp_menu.menu_provider.chain.class%" public="false">
<argument type="collection" />
</service>
<service id="knp_menu.menu_provider.lazy" class="Knp\Menu\Provider\LazyProvider" public="false">
<argument type="collection" />
<tag name="knp_menu.provider" />
</service>
<service id="knp_menu.menu_provider.container_aware" class="%knp_menu.menu_provider.container_aware.class%" public="false">
<argument type="service" id="service_container" />
<argument type="collection" />
</service>
<service id="knp_menu.menu_provider.builder_service" class="Knp\Bundle\MenuBundle\Provider\BuilderServiceProvider" public="false">
<argument type="service" id="service_container" />
<argument type="collection" />
</service>
<service id="knp_menu.menu_provider.builder_alias" class="%knp_menu.menu_provider.builder_alias.class%" public="false">
<argument type="service" id="kernel" />
<argument type="service" id="service_container" />
<argument type="service" id="knp_menu.factory" />
</service>
<service id="knp_menu.renderer_provider" class="%knp_menu.renderer_provider.class%">
<argument type="service" id="service_container" />
<argument>%knp_menu.default_renderer%</argument>
<argument type="collection" />
<argument>false</argument>
</service>
<service id="knp_menu.renderer.list" class="%knp_menu.renderer.list.class%">
<tag name="knp_menu.renderer" alias="list" />
<argument type="service" id="knp_menu.matcher" />
<argument>%knp_menu.renderer.list.options%</argument>
<argument>%kernel.charset%</argument>
</service>
<service id="knp_menu.listener.voters" class="%knp_menu.listener.voters.class%">
<tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" />
</service>
<service id="knp_menu.voter.router" class="%knp_menu.voter.router.class%">
<argument type="service" id="request_stack" />
<tag name="knp_menu.voter" />
</service>
<service id="knp_menu.manipulator" class="Knp\Menu\Util\MenuManipulator" public="false" />
<!-- autowiring aliases -->
<service id="Knp\Menu\FactoryInterface" alias="knp_menu.factory" public="false" />
<service id="Knp\Menu\Matcher\MatcherInterface" alias="knp_menu.matcher" public="false" />
<service id="Knp\Menu\Util\MenuManipulator" alias="knp_menu.manipulator" public="false" />
</services>
</container>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://knplabs.com/schema/dic/menu"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://knplabs.com/schema/dic/menu"
elementFormDefault="qualified">
<xsd:element name="config" type="config"/>
<xsd:complexType name="config">
<xsd:all>
<xsd:element name="providers" type="providers" minOccurs="0"/>
<xsd:element name="twig" type="twig" minOccurs="0"/>
</xsd:all>
<xsd:attribute name="templating" type="xsd:boolean" default="false"/>
<xsd:attribute name="default-renderer" type="xsd:string" default="twig"/>
</xsd:complexType>
<xsd:complexType name="providers">
<xsd:attribute name="builder-alias" type="xsd:boolean" default="true"/>
<xsd:attribute name="container-aware" type="xsd:boolean" default="true"/>
<xsd:attribute name="builder-service" type="xsd:boolean" default="true"/>
</xsd:complexType>
<xsd:complexType name="twig">
<xsd:attribute name="template" type="xsd:string" default="knp_menu.html.twig"/>
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="knp_menu.templating.helper.class">Knp\Bundle\MenuBundle\Templating\Helper\MenuHelper</parameter>
</parameters>
<services>
<service id="knp_menu.templating.helper" class="%knp_menu.templating.helper.class%">
<tag name="templating.helper" alias="knp_menu" />
<argument type="service" id="knp_menu.helper" />
<argument type="service" id="knp_menu.matcher" />
<argument type="service" id="knp_menu.manipulator" />
</service>
</services>
</container>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="knp_menu.twig.extension.class">Knp\Menu\Twig\MenuExtension</parameter>
<parameter key="knp_menu.renderer.twig.class">Knp\Menu\Renderer\TwigRenderer</parameter>
<parameter key="knp_menu.renderer.twig.options" type="collection"></parameter>
</parameters>
<services>
<service id="knp_menu.twig.extension" class="%knp_menu.twig.extension.class%" public="false">
<tag name="twig.extension" />
<argument type="service" id="knp_menu.helper" />
<argument type="service" id="knp_menu.matcher" />
<argument type="service" id="knp_menu.manipulator" />
</service>
<service id="knp_menu.renderer.twig" class="%knp_menu.renderer.twig.class%">
<tag name="knp_menu.renderer" alias="twig" />
<argument type="service" id="twig" />
<argument>%knp_menu.renderer.twig.template%</argument>
<argument type="service" id="knp_menu.matcher" />
<argument>%knp_menu.renderer.twig.options%</argument>
</service>
</services>
</container>

View File

@@ -0,0 +1,99 @@
Registering your own provider
=============================
Registering your own menu provider allows you to feed your menu with your own
data, accessed by your code. It can for example go through a PHPCR repository
and create the corresponding menu elements.
Create first your Provider class, in the Provider directory of your bundle:
.. code-block:: php
namespace AppBundle\Provider;
use Knp\Menu\FactoryInterface;
use Knp\Menu\Provider\MenuProviderInterface;
class CustomMenuProvider implements MenuProviderInterface
{
/**
* @var FactoryInterface
*/
protected $factory = null;
/**
* @param FactoryInterface $factory the menu factory used to create the menu item
*/
public function __construct(FactoryInterface $factory)
{
$this->factory = $factory;
}
/**
* Retrieves a menu by its name
*
* @param string $name
* @param array $options
* @return \Knp\Menu\ItemInterface
* @throws \InvalidArgumentException if the menu does not exists
*/
public function get($name, array $options = [])
{
if ('demo' == $name) { //several menu could call this provider
$menu = /* construct / get a \Knp\Menu\NodeInterface */;
if ($menu === null) {
throw new \InvalidArgumentException(sprintf('The menu "%s" is not defined.', $name));
}
/*
* Populate your menu here
*/
$menuItem = $this->factory->createFromNode($menu);
return $menuItem;
}
}
/**
* Checks whether a menu exists in this provider
*
* @param string $name
* @param array $options
* @return bool
*/
public function has($name, array $options = [])
{
$menu = /* find the menu called $name */;
return $menu !== null;
}
}
Then, configure the services linked to this new provider.
.. code-block:: yaml
# app/config/services.yml
services:
app.menu_provider:
class: AppBundle\Provider\CustomMenuProvider
arguments:
- @knp_menu.factory
tags:
- { name: knp_menu.provider }
# ...
Finally, to generate the menu, for example inside a twig template type:
.. code-block:: html+jinja
{{ knp_menu_render('demo') }}
The `Symfony CMF MenuBundle`_ provides a complete working example.
.. _`Symfony CMF MenuBundle`: https://github.com/symfony-cmf/MenuBundle

View File

@@ -0,0 +1,57 @@
Registering your own renderer
=============================
Registering your own renderer in the renderer provider is simply a matter
of creating a service tagged with ``knp_menu.renderer``:
.. code-block:: yaml
# app/config/services.yml
services:
app.menu_renderer:
# The class implements Knp\Menu\Renderer\RendererInterface
class: AppBundle\Menu\CustomRenderer
arguments: ["%kernel.charset%"] # set your own dependencies here
tags:
# The alias is what is used to retrieve the menu
- { name: knp_menu.renderer, alias: custom }
# ...
If your renderer extends ``ListRenderer``, you need to provide a ``Matcher`` instance.
The configuration is then the following:
.. code-block:: yaml
# app/config/services.yml
services:
app.menu_renderer:
# The class implements Knp\Menu\Renderer\RendererInterface
class: AppBundle\Menu\CustomRenderer
arguments:
- @knp_menu.matcher
- "%knp_menu.renderer.list.options%"
- "%kernel.charset%"
# add your own dependencies here
tags:
# The alias is what is used to retrieve the menu
- { name: knp_menu.renderer, alias: custom }
# ...
.. note::
The renderer service must be public as it will be retrieved at runtime to
keep it lazy-loaded.
You can now use your renderer to render your menu:
.. code-block:: html+jinja
{{ knp_menu_render('main', {}, 'custom') }}
.. note::
As the renderer is responsible to render some HTML code, the ``knp_menu_render``
function is marked as safe. Take care to handle escaping data in your renderer
to avoid XSS if you use some user input in the menu.

View File

@@ -0,0 +1,22 @@
Disabling the Core Menu Providers
=================================
To be able to use different menu providers together (the builder-service-based
one, the container-based one and the convention-based one for instance),
a chain provider is used. However, it is not used when only one provider
is enabled to increase performance by getting rid of the wrapping. If you
don't want to use the built-in providers, you can disable them through the
configuration:
.. code-block:: yaml
#app/config/config.yml
knp_menu:
providers:
builder_alias: false # disable the builder-alias-based provider
builder_service: false
container_aware: true # keep this one enabled. Can be omitted as it is the default
.. note::
All providers are enabled by default.

View File

@@ -0,0 +1,147 @@
Using events to allow a menu to be extended
===========================================
If you want to let different parts of your system hook into the building of your
menu, a good way is to use an approach based on the Symfony EventDispatcher
component.
Create the menu builder
-----------------------
Your menu builder will create the base menu item and then dispatch an event
to allow other parts of your application to add more stuff to it.
.. code-block:: php
// src/AppBundle/Menu/MainBuilder.php
namespace AppBundle\Menu;
use AppBundle\Event\ConfigureMenuEvent;
use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
class MainBuilder implements ContainerAwareInterface
{
use ContainerAwareTrait;
public function build(FactoryInterface $factory)
{
$menu = $factory->createItem('root');
$menu->addChild('Dashboard', ['route' => '_acp_dashboard']);
$this->container->get('event_dispatcher')->dispatch(
ConfigureMenuEvent::CONFIGURE,
new ConfigureMenuEvent($factory, $menu)
);
return $menu;
}
}
.. note::
This implementation assumes you use the ``BuilderAliasProvider`` (getting
your menu as ``AppBundle:MainBuilder:build``) but you could also define
it as a service and inject the ``event_dispatcher`` service as a dependency.
Create the Event object
-----------------------
The event object allows to pass some data to the listener. In this case,
it will hold the menu being created and the factory.
.. code-block:: php
// src/AppBundle/Event/ConfigureMenuEvent.php
namespace AppBundle\Event;
use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
use Symfony\Component\EventDispatcher\Event;
class ConfigureMenuEvent extends Event
{
const CONFIGURE = 'app.menu_configure';
private $factory;
private $menu;
/**
* @param \Knp\Menu\FactoryInterface $factory
* @param \Knp\Menu\ItemInterface $menu
*/
public function __construct(FactoryInterface $factory, ItemInterface $menu)
{
$this->factory = $factory;
$this->menu = $menu;
}
/**
* @return \Knp\Menu\FactoryInterface
*/
public function getFactory()
{
return $this->factory;
}
/**
* @return \Knp\Menu\ItemInterface
*/
public function getMenu()
{
return $this->menu;
}
}
.. note::
Following the Symfony best practices, the first segment of the event name will
be the alias of the bundle, which allows avoiding conflicts.
That's it. Your builder now provides a hook. Let's see how you can use it!
Create a listener
-----------------
You can register as many listeners as you want for the event. Let's add one.
.. code-block:: php
// src/Acme/AdminBundle/EventListener/ConfigureMenuListener.php
namespace Acme\AdminBundle\EventListener;
use AppBundle\Event\ConfigureMenuEvent;
class ConfigureMenuListener
{
/**
* @param \AppBundle\Event\ConfigureMenuEvent $event
*/
public function onMenuConfigure(ConfigureMenuEvent $event)
{
$menu = $event->getMenu();
$menu->addChild('Matches', ['route' => 'versus_rankedmatch_acp_matches_index']);
$menu->addChild('Participants', ['route' => 'versus_rankedmatch_acp_participants_index']);
}
}
You can now register the listener.
.. code-block:: yaml
# app/config/services.yml
services:
app.admin_configure_menu_listener:
class: Acme\AdminBundle\EventListener\ConfigureMenuListener
tags:
- { name: kernel.event_listener, event: app.menu_configure, method: onMenuConfigure }
You could also create your listener as a subscriber and use the ``kernel.event_subscriber``
tag, which does not have any additional attributes.

View File

@@ -0,0 +1,64 @@
I18n for your Menu Labels
=========================
The KnpMenuBundle translates all menu items by default. Assume you've built a menu
like this::
$menu = $factory->createItem('root');
$menu->addChild('Home', ['route' => 'homepage']);
$menu->addChild('Login', ['route' => 'login']);
The items "Home" and "Login" can now be translated in the message domain:
.. configuration-block::
.. code-block:: yaml
# app/Resources/translations/messages.fr.yml
Home: Accueil
Login: Connexion
.. code-block:: xml
<!-- app/Resources/translations/messages.fr.xlf -->
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" datatype="plaintext" original="file.ext">
<body>
<trans-unit id="menu.home">
<source>Home</source>
<target>Accueil</target>
</trans-unit>
<trans-unit id="menu.login">
<source>Login</source>
<target>Connexion</target>
</trans-unit>
</body>
</file>
</xliff>
.. code-block:: php
// app/Resources/translations/messages.fr.php
return [
'Home' => 'Accueil',
'Login' => 'Connexion',
];
Configure the Translation Domain
--------------------------------
You can configure the translation domain that's used in the extras of the menu
item::
// ...
$menu->addChild('Home', ['route' => 'homepage'])
->setExtra('translation_domain', 'AcmeAdminBundle');
Disabling Translation
---------------------
You can disable translation of the menu item by setting ``translation_domain``
to ``false``.

View File

@@ -0,0 +1,331 @@
Using KnpMenuBundle
===================
Welcome to KnpMenuBundle - creating menus is fun again!
Installation
------------
Step 1: Download the Bundle
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Open a command console, enter your project directory and execute the
following command to download the latest stable version of this bundle:
.. code-block:: bash
$ composer require knplabs/knp-menu-bundle "^2.0"
This command requires you to have Composer installed globally, as explained
in the `installation chapter`_ of the Composer documentation.
Step 2: Enable the Bundle
~~~~~~~~~~~~~~~~~~~~~~~~~
Then, enable the bundle by adding the following line in the ``app/AppKernel.php``
file of your project:
.. code-block:: php
// app/AppKernel.php
// ...
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = [
// ...
new Knp\Bundle\MenuBundle\KnpMenuBundle(),
];
// ...
}
// ...
}
Step 3: (optional) Configure the bundle
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The bundle comes with a sensible default configuration, which is listed below.
You can define these options if you need to change them:
.. configuration-block::
.. code-block:: yaml
# app/config/config.yml
knp_menu:
# use "twig: false" to disable the Twig extension and the TwigRenderer
twig:
template: KnpMenuBundle::menu.html.twig
# if true, enables the helper for PHP templates
templating: false
# the renderer to use, list is also available by default
default_renderer: twig
.. code-block:: xml
<!-- app/config/config.xml -->
<?xml version="1.0" charset="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:knp-menu="http://knplabs.com/schema/dic/menu">
<!--
templating: if true, enabled the helper for PHP templates
default-renderer: the renderer to use, list is also available by default
-->
<knp-menu:config
templating="false"
default-renderer="twig"
>
<!-- add enabled="false" to disable the Twig extension and the TwigRenderer -->
<knp-menu:twig template="KnpMenuBundle::menu.html.twig"/>
</knp-menu:config>
</container>
.. code-block:: php
// app/config/config.php
$container->loadFromExtension('knp_menu', [
// use 'twig' => false to disable the Twig extension and the TwigRenderer
'twig' => [
'template' => 'KnpMenuBundle::menu.html.twig'
],
// if true, enabled the helper for PHP templates
'templating' => false,
// the renderer to use, list is also available by default
'default_renderer' => 'twig',
]);
.. versionadded::2.1.2
The template used to be ``knp_menu.html.twig`` which did not translate menu entries.
Version 2.1.2 adds the template that translates menu entries.
.. note::
Take care to change the default renderer if you disable the Twig support.
Create your first menu!
-----------------------
There are two ways to create a menu: the "easy" way, and the more flexible
method of creating a menu as a service.
Method a) The Easy Way (yay)!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To create a menu, first create a new class in the ``Menu`` directory of one
of your bundles. This class - called ``Builder`` in our example - will have
one method for each menu that you need to build.
An example builder class would look like this:
.. code-block:: php
// src/AppBundle/Menu/Builder.php
namespace AppBundle\Menu;
use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
class Builder implements ContainerAwareInterface
{
use ContainerAwareTrait;
public function mainMenu(FactoryInterface $factory, array $options)
{
$menu = $factory->createItem('root');
$menu->addChild('Home', ['route' => 'homepage']);
// access services from the container!
$em = $this->container->get('doctrine')->getManager();
// findMostRecent and Blog are just imaginary examples
$blog = $em->getRepository('AppBundle:Blog')->findMostRecent();
$menu->addChild('Latest Blog Post', [
'route' => 'blog_show',
'routeParameters' => ['id' => $blog->getId()]
]);
// create another menu item
$menu->addChild('About Me', ['route' => 'about']);
// you can also add sub levels to your menus as follows
$menu['About Me']->addChild('Edit profile', ['route' => 'edit_profile']);
// ... add more children
return $menu;
}
}
With the standard ``knp_menu.html.twig`` template and your current page being
'Home', your menu would render with the following markup:
.. code-block:: html
<ul>
<li class="current first">
<a href="#route_to/homepage">Home</a>
</li>
<li class="current_ancestor">
<a href="#route_to/page_show/?id=42">About Me</a>
<ul class="menu_level_1">
<li class="current first last">
<a href="#route_to/edit_profile">Edit profile</a>
</li>
</ul>
</li>
</ul>
.. note::
You only need to implement ``ContainerAwareInterface`` if you need the
service container. The more elegant way to handle your dependencies is to
inject them in the constructor. If you want to do that, see method below.
.. note::
The menu builder can be overwritten using the bundle inheritance.
To actually render the menu, just do the following from anywhere in any template:
.. configuration-block::
.. code-block:: html+jinja
{{ knp_menu_render('AppBundle:Builder:mainMenu') }}
.. code-block:: html+php
<?php echo $view['knp_menu']->render('AppBundle:Builder:mainMenu') ?>
With this method, you refer to the menu using a three-part string:
**bundle**:**class**:**method**.
If you needed to create a second menu, you'd simply add another method to
the ``Builder`` class (e.g. ``sidebarMenu``), build and return the new menu,
then render it via ``AppBundle:Builder:sidebarMenu``.
That's it! The menu is *very* configurable. For more details, see the
`KnpMenu documentation`_.
Method b) A menu builder as a service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For information on how to register a menu builder as a service, read
:doc:`Creating Menu Builders as Services <menu_builder_service>`.
Method c) A menu as a service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For information on how to register a service and tag it as a menu, read
:doc:`Creating Menus as Services <menu_service>`.
.. note::
To improve performances, you can :doc:`disable providers you don't need <disabling_providers>`.
Rendering Menus
---------------
Once you've setup your menu, rendering it easy. If you've used the "easy"
way, then do the following:
.. configuration-block::
.. code-block:: html+jinja
{{ knp_menu_render('AppBundle:Builder:mainMenu') }}
.. code-block:: html+php
<?php echo $view['knp_menu']->render('AppBundle:Builder:mainMenu') ?>
Additionally, you can pass some options to the renderer:
.. configuration-block::
.. code-block:: html+jinja
{{ knp_menu_render('AppBundle:Builder:mainMenu', {'depth': 2, 'currentAsLink': false}) }}
.. code-block:: html+php
<?php echo $view['knp_menu']->render('AppBundle:Builder:mainMenu', [
'depth' => 2,
'currentAsLink' => false,
]) ?>
For a full list of options, see the "Other rendering options" header on the
`KnpMenu documentation`_.
You can also "get" a menu, which you can use to render later:
.. configuration-block::
.. code-block:: html+jinja
{% set menuItem = knp_menu_get('AppBundle:Builder:mainMenu') %}
{{ knp_menu_render(menuItem) }}
.. code-block:: html+php
<?php $menuItem = $view['knp_menu']->get('AppBundle:Builder:mainMenu') ?>
<?php echo $view['knp_menu']->render($menuItem) ?>
If you want to only retrieve a certain branch of the menu, you can do the
following, where 'Contact' is one of the root menu items and has children
beneath it.
.. configuration-block::
.. code-block:: html+jinja
{% set menuItem = knp_menu_get('AppBundle:Builder:mainMenu', ['Contact']) %}
{{ knp_menu_render(['AppBundle:Builder:mainMenu', 'Contact']) }}
.. code-block:: html+php
<?php $menuItem = $view['knp_menu']->get('AppBundle:Builder:mainMenu', ['Contact']) ?>
<?php echo $view['knp_menu']->render(['AppBundle:Builder:mainMenu', 'Contact']) ?>
If you want to pass some options to the builder, you can use the third parameter
of the ``knp_menu_get`` function:
.. configuration-block::
.. code-block:: html+jinja
{% set menuItem = knp_menu_get('AppBundle:Builder:mainMenu', [], {'some_option': 'my_value'}) %}
{{ knp_menu_render(menuItem) }}
.. code-block:: html+php
<?php $menuItem = $view['knp_menu']->get('AppBundle:Builder:mainMenu', [], [
'some_option' => 'my_value'
]) ?>
<?php echo $view['knp_menu']->render($menuItem) ?>
More Advanced Stuff
-------------------
.. toctree::
:maxdepth: 1
menu_service
menu_builder_service
i18n
events
custom_renderer
custom_provider
disabling_providers
.. _`installation chapter`: https://getcomposer.org/doc/00-intro.md
.. _`KnpMenu documentation`: https://github.com/KnpLabs/KnpMenu/blob/master/doc/01-Basic-Menus.markdown

View File

@@ -0,0 +1,124 @@
Creating Menu Builders as Services
==================================
This bundle gives you a really convenient way to create menus by following
a convention and - if needed - injecting the entire container.
However, if you want to, you can instead choose to create a service for your
menu builder. The advantage of this method is that you can inject the exact
dependencies that your menu builder needs, instead of injecting the entire
service container. This can lead to code that is more testable and also potentially
more reusable. The disadvantage is that it needs just a little more setup.
Start by creating a builder for your menu. You can stick as many menus into
a builder as you want, so you may only have one (or just a few) of these
builder classes in your application:
.. code-block:: php
// src/AppBundle/Menu/MenuBuilder.php
namespace AppBundle\Menu;
use Knp\Menu\FactoryInterface;
class MenuBuilder
{
private $factory;
/**
* @param FactoryInterface $factory
*
* Add any other dependency you need
*/
public function __construct(FactoryInterface $factory)
{
$this->factory = $factory;
}
public function createMainMenu(array $options)
{
$menu = $this->factory->createItem('root');
$menu->addChild('Home', ['route' => 'homepage']);
// ... add more children
return $menu;
}
}
Next, register your menu builder as service and register its ``createMainMenu`` method as a menu builder:
.. code-block:: yaml
# app/config/services.yml
services:
app.menu_builder:
class: AppBundle\Menu\MenuBuilder
arguments: ["@knp_menu.factory"]
tags:
- { name: knp_menu.menu_builder, method: createMainMenu, alias: main } # The alias is what is used to retrieve the menu
# ...
.. note::
The menu service must be public as it will be retrieved at runtime to keep
it lazy-loaded.
You can now render the menu directly in a template via the name given in the
``alias`` key above:
.. code-block:: html+jinja
{{ knp_menu_render('main') }}
Suppose now we need to create a second menu for the sidebar. The process
is simple! Start by adding a new method to your builder:
.. code-block:: php
// src/AppBundle/Menu/MenuBuilder.php
// ...
class MenuBuilder
{
// ...
public function createSidebarMenu(array $options)
{
$menu = $this->factory->createItem('sidebar');
if (isset($options['include_homepage']) && $options['include_homepage']) {
$menu->addChild('Home', ['route' => 'homepage']);
}
// ... add more children
return $menu;
}
}
Now, create a service for *just* your new menu, giving it a new name, like
``sidebar``:
.. code-block:: yaml
# app/config/services.yml
services:
app.menu_builder:
class: AppBundle\Menu\MenuBuilder
arguments: ["@knp_menu.factory"]
tags:
- { name: knp_menu.menu_builder, method: createMainMenu, alias: main } # the previous menu
- { name: knp_menu.menu_builder, method: createSidebarMenu, alias: sidebar } # Named "sidebar" this time
# ...
It can now be rendered, just like the other menu:
.. code-block:: html+jinja
{% set menu = knp_menu_get('sidebar', [], {include_homepage: false}) %}
{{ knp_menu_render(menu) }}

View File

@@ -0,0 +1,143 @@
Creating Menus as Services
==========================
.. note::
Registering a menu as service comes with several limitations:
- it does not allow to use builder options
- it reuses the same instance several times in case you render the same
menu several times, which can have weird side-effects.
It is recommended to register only :doc:`menu builders as services <menu_builder_service>`
instead.
This bundle gives you a really convenient way to create menus by following
a convention and - if needed - injecting the entire container.
However, if you want to, you can instead choose to create a service for your
menu object. The advantage of this method is that you can inject the exact
dependencies that your menu needs, instead of injecting the entire service
container. This can lead to code that is more testable and also potentially
more reusable. The disadvantage is that it needs just a little more setup.
Start by creating a builder for your menu. You can stick as many menus into
a builder as you want, so you may only have one (or just a few) of these
builder classes in your application:
.. code-block:: php
// src/AppBundle/Menu/MenuBuilder.php
namespace AppBundle\Menu;
use Knp\Menu\FactoryInterface;
use Symfony\Component\HttpFoundation\RequestStack;
class MenuBuilder
{
private $factory;
/**
* @param FactoryInterface $factory
*/
public function __construct(FactoryInterface $factory)
{
$this->factory = $factory;
}
public function createMainMenu(RequestStack $requestStack)
{
$menu = $this->factory->createItem('root');
$menu->addChild('Home', ['route' => 'homepage']);
// ... add more children
return $menu;
}
}
Next, register two services: one for your menu builder, and one for the menu
object created by the ``createMainMenu`` method:
.. code-block:: yaml
# app/config/services.yml
services:
app.menu_builder:
class: AppBundle\Menu\MenuBuilder
arguments: ["@knp_menu.factory"]
app.main_menu:
class: Knp\Menu\MenuItem # the service definition requires setting the class
factory: ["@app.menu_builder", createMainMenu]
arguments: ["@request_stack"]
tags:
- { name: knp_menu.menu, alias: main } # The alias is what is used to retrieve the menu
# ...
.. note::
The menu service must be public as it will be retrieved at runtime to keep
it lazy-loaded.
.. note::
If you are using Symfony `2.5` or older version please check the `Using a Factory to Create Services`_
article for correct factories syntax corresponding to your version.
You can now render the menu directly in a template via the name given in the
``alias`` key above:
.. code-block:: html+jinja
{{ knp_menu_render('main') }}
Suppose now we need to create a second menu for the sidebar. The process
is simple! Start by adding a new method to your builder:
.. code-block:: php
// src/AppBundle/Menu/MenuBuilder.php
// ...
class MenuBuilder
{
// ...
public function createSidebarMenu(RequestStack $requestStack)
{
$menu = $this->factory->createItem('sidebar');
$menu->addChild('Home', ['route' => 'homepage']);
// ... add more children
return $menu;
}
}
Now, create a service for *just* your new menu, giving it a new name, like
``sidebar``:
.. code-block:: yaml
# app/config/services.yml
services:
app.sidebar_menu:
class: Knp\Menu\MenuItem
factory: ["@app.menu_builder", createSidebarMenu]
arguments: ["@request_stack"]
tags:
- { name: knp_menu.menu, alias: sidebar } # Named "sidebar" this time
# ...
It can now be rendered, just like the other menu:
.. code-block:: html+jinja
{{ knp_menu_render('sidebar') }}
.. _`Using a Factory to Create Services`: http://symfony.com/doc/2.5/components/dependency_injection/factories.html

View File

@@ -0,0 +1,10 @@
{% extends 'knp_menu.html.twig' %}
{% block label %}
{%- set translation_domain = item.extra('translation_domain', 'messages') -%}
{%- set label = item.label -%}
{%- if translation_domain is not same as(false) -%}
{%- set label = label|trans(item.extra('translation_params', {}), translation_domain) -%}
{%- endif -%}
{%- if options.allow_safe_labels and item.extra('safe_label', false) %}{{ label|raw }}{% else %}{{ label }}{% endif -%}
{% endblock %}