Skip to content
This repository was archived by the owner on Sep 16, 2021. It is now read-only.

Commit 016e426

Browse files
committed
Merge pull request #447 from symfony-cmf/menu-event
Document the CreateMenuItemFromNodeEvent
2 parents 04d8a80 + dd1c663 commit 016e426

File tree

1 file changed

+132
-3
lines changed

1 file changed

+132
-3
lines changed

bundles/menu/menu_factory.rst

Lines changed: 132 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ A menu item should have a URL associated with it. The CMF provides the
1919
``MenuFactory``.
2020

2121
* The ``MenuFactory`` only supports using the ``uri`` option to specify the
22-
menu items link.
22+
menu items link.
2323
* The ``RouterAwareFactory`` adds support for for generating a URL from the
2424
``route`` and ``routeParameters`` options.
2525
* The CMF adds the ``ContentAwareFactory`` which supports generating the URL
@@ -44,7 +44,7 @@ of the three URL generation techniques to use.
4444
The values for this options can be one of the following:
4545

4646
* ``null``: If the value is ``null`` (or the options is not set) then the link
47-
type is determined automatically by looking at each of the ``uri``, ``route`` and
47+
type is determined automatically by looking at each of the ``uri``, ``route`` and
4848
``content`` options and using the first one which is non-null.
4949
* **uri**: Use the URI provided by the ``uri`` option.
5050
* **route**: Generate a URL using the route named by the ``route`` option
@@ -62,6 +62,135 @@ visible by use of the :doc:`publish workflow checker
6262

6363
.. versionadded:: 1.1
6464
The ``MenuContentVoter`` was added in CmfMenuBundle 1.1.
65-
65+
6666
The ``MenuContentVoter`` decides that a menu node is not published if the
6767
content it is pointing to is not published.
68+
69+
Customizing Menus using Events
70+
------------------------------
71+
72+
The CMF menu factory dispatches a ``cmf_menu.create_menu_item_from_node`` event
73+
during the process of creating a ``MenuItem`` from a class implementing
74+
``NodeInterface``. You can use this event to control the ``MenuItem`` that is
75+
created. The ``CreateMenuItemFromNodeEvent`` provides access to the
76+
``NodeInterface`` and ``ContentAwareFactory``, which can be used to create a
77+
custom ``MenuItem``, or to tell the factory to ignore the current node or its
78+
children. For example, this event is used by the
79+
:doc:`publish workflow checker <../core/publish_workflow>` to skip
80+
``MenuItem`` generation for unpublished nodes.
81+
82+
The ``CreateMenuItemFromNodeEvent`` which is dispatched includes the following
83+
methods which can be used to customize the creation of the ``MenuItem`` for a
84+
``NodeInterface``.
85+
86+
* ``CreateMenuItemFromNodeEvent::setSkipNode(true|false)``: Setting skipNode
87+
to true will prevent creation of item from the node and skip any child nodes.
88+
**Note:** If setSkipNode(true) is called for ``Menu`` the
89+
``ContentAwareFactory`` will still create an empty item for the menu. This is
90+
to prevent the KnpMenuBundle code from throwing an exception due to ``null``
91+
being passed to a function to render a menu;
92+
* ``CreateMenuItemFromNodeEvent::setItem(ItemInterface $item|null)``: A
93+
listener can call setItem to provide a custom item to use for the given node.
94+
If an item is set, the ``ContentAwareFactory`` will use it instead of
95+
creating one for the node. The children of the node will still be processed
96+
by the ``ContentAwareFactory`` and listeners will have an opportunity then to
97+
override their items using this method;
98+
* ``CreateMenuItemFromNodeEvent::setSkipChildren(true|false)``: Listeners can
99+
set this to true and the ``ContentAwareFactory`` will skip processing of the
100+
children of the current node.
101+
102+
Example Menu Listener
103+
~~~~~~~~~~~~~~~~~~~~~
104+
105+
This listener handles menu nodes that point to a different menu by implementing
106+
the ``MenuReferrerInterface``::
107+
108+
namespace Acme\DemoBundle;
109+
110+
interface MenuReferrerInterface
111+
{
112+
public function getMenuName();
113+
public function getMenuOptions();
114+
}
115+
116+
namespace Acme\DemoBundle\EventListener;
117+
118+
use Symfony\Cmf\Bundle\MenuBundle\Event\CreateMenuItemFromNodeEvent;
119+
use Acme\DemoBundle\MenuReferrerInterface;
120+
use Knp\Menu\Provider\MenuProviderInterface;
121+
122+
class CreateMenuItemFromNodeListener
123+
{
124+
protected $provider;
125+
126+
public function __construct(MenuProviderInterface $provider)
127+
{
128+
$this->provider = $provider;
129+
}
130+
131+
public function onCreateMenuItemFromNode(CreateMenuItemFromNodeEvent $event)
132+
{
133+
$node = $event->getNode();
134+
135+
if ($node implements MenuReferrerInterface) {
136+
$menuName = $node->getMenuName();
137+
$menuOptions = $node->getMenuOptions();
138+
139+
if (!$this->provider->has($menuName)) {
140+
return;
141+
}
142+
143+
$menu = $this->provider->get($menuName, $menuOptions);
144+
$event->setItem($menu);
145+
146+
// as this does not call $event->setSkipChildren(true),
147+
// children of $node will be rendered as children items of $menu.
148+
}
149+
}
150+
151+
}
152+
153+
The service needs to be tagged as event listener:
154+
155+
.. configuration-block::
156+
157+
.. code-block:: yaml
158+
159+
services:
160+
acme_demo.listener.menu_referrer_listener:
161+
class: Acme\DemoBundle\EventListener\CreateMenuItemFromNodeListener
162+
arguments:
163+
- @knp_menu.menu_provider
164+
tags:
165+
-
166+
name: kernel.event_listener
167+
event: cmf_menu.create_menu_item_from_node
168+
method: onCreateMenuItemFromNode
169+
170+
.. code-block:: xml
171+
172+
<?xml version="1.0" encoding="UTF-8" ?>
173+
<container xmlns="http://symfony.com/schema/dic/services">
174+
<service id="acme_demo.listener.menu_referrer_listener" class="Acme\DemoBundle\EventListener\CreateMenuItemFromNodeListener">
175+
<argument type="service" id="knp_menu.menu_provider" />
176+
<tag name="kernel.event_listener"
177+
event="cmf_menu.create_menu_item_from_node"
178+
method="onCreateMenuItemFromNode"
179+
/>
180+
</service>
181+
</container>
182+
183+
.. code-block:: php
184+
185+
use Symfony\Component\DependencyInjection\Definition;
186+
use Symfony\Component\DependencyInjection\Reference;
187+
188+
$definition = new Definition('Acme\DemoBundle\EventListener\CreateMenuItemFromNodeListener', array(
189+
new Reference('knp_menu.menu_provider'),
190+
));
191+
$definition->addTag('kernel.event_listener', array(
192+
'event' => 'cmf_menu.create_menu_item_from_node',
193+
'method' => 'onCreateMenuItemFromNode',
194+
));
195+
196+
$container->setDefinition('acme_demo.listener.menu_referrer_listener', $definition);

0 commit comments

Comments
 (0)