@@ -5,143 +5,135 @@ Menu Factory
5
5
============
6
6
7
7
The menu documents are only used for persisting the menu data, they are not
8
- actually used when rendering a menu. `` MenuItem `` classes from the KnpMenu
9
- component are the objects that are needed, a menu factory takes data provided by
10
- a class implementing `` NodeInterface `` and creates a `` MenuItem `` tree .
8
+ actually used when rendering a menu. Menu items are the objects that are needed
9
+ to render a menu. A menu factory creates such * menu items * from the * menu
10
+ nodes * provided by the menu provider .
11
11
12
12
.. _bundles_menu_menu_factory_url_generation :
13
13
14
14
URL Generation
15
15
--------------
16
16
17
- A menu item should have a URL associated with it. The CMF provides the
18
- ``ContentAwareFactory ``, which extends the KnpMenu ``RouterAwareFactory `` and
19
- ``MenuFactory ``.
20
-
21
- * The ``MenuFactory `` only supports using the ``uri `` option to specify the
22
- menu items link.
23
- * The ``RouterAwareFactory `` adds support for for generating a URL from the
24
- ``route `` and ``routeParameters `` options.
25
- * The CMF adds the ``ContentAwareFactory `` which supports generating the URL
26
- from the ``content `` and ``routeParameters `` options when using the
27
- :ref: `dynamic router <bundles-routing-dynamic-generator >`.
28
-
29
- The ``content `` option, if specified, must contain something that the content
30
- URL generator can work with. When using the :ref: `dynamic router
31
- <bundles-routing-dynamic-generator>`, this needs to be a class implementing
32
- the ``RouteReferrersInterface ``. You can alternatively specify a custom
33
- ``UrlGeneratorInterface `` with the ``content_url_generator `` configuration
34
- option.
35
-
36
- .. versionadded :: 1.2
37
- The ``content_url_generator `` option was introduced in CmfMenuBundle 1.2.0.
38
- Prior to 1.2, the default service ``router `` was hardcoded to generate URLs
39
- from content.
40
-
41
- URL generation is absolute or relative, depending on the boolean value of the
42
- ``routeAbsolute `` option.
17
+ .. versionadded :: 2.0
18
+ Adding content support to the ``knp_menu.factory `` service was introduced
19
+ in CmfMenuBundle 2.0. Prior to 2.0, you had to use the
20
+ ``ContentAwareFactory `` class and ``cmf_menu.factory `` service.
21
+
22
+ Most menu items will need a URL. By default, KnpMenu allows generating this URL
23
+ by specifying a URI or a Symfony route name.
24
+
25
+ The CmfMenuBundle provides another way to generate URLs: By using the
26
+ :ref: `dynamic router <bundles-routing-dynamic-generator >` to generate routes
27
+ from content objects.
28
+
29
+ The ``content `` menu node option, if specified, must contain something that the
30
+ content URL generator can work with. When using the :ref: `dynamic router
31
+ <bundles-routing-dynamic-generator>`, this needs to be a class implementing the
32
+ ``RouteReferrersInterface ``.
33
+
34
+ .. tip ::
35
+
36
+ When you don't use the dynamic router, you can create a custom url
37
+ generator by implementing ``UrlGeneratorInterface `` and configure it using
38
+ the ``content_url_generator `` option in ``config.yml ``.
39
+
40
+ .. versionadded :: 1.2
41
+ The ``content_url_generator `` option was introduced in CmfMenuBundle 1.2.
42
+
43
+ How to handle Items without a URL
44
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
45
+
46
+ When menu nodes refer to content that has been deleted or there is another
47
+ error during route generation, a menu node is skipped by default. You can set
48
+ the ``allow_empty_items `` setting of the CmfMenuBundle to ``true `` to render
49
+ these nodes as plain text instead.
43
50
44
51
.. _bundles_menu_menu_factory_link_type :
45
52
46
- Link Type
47
- ---------
53
+ Specifying the Link Type
54
+ ~~~~~~~~~~~~~~~~~~~~~~~~
48
55
49
- The ``linkType `` option is a CMF addition which enables you to specify which
50
- of the three URL generation techniques to use .
56
+ The CMF provides a ``linkType `` option, which enables you to specify which URL
57
+ generation technique (URI, route or content) should be used .
51
58
52
59
The values for this options can be one of the following:
53
60
54
- * ``null ``: If the value is ``null `` (or the options is not set) then the link
55
- type is determined automatically by looking at each of the ``uri ``, ``route ``
56
- and ``content `` options and using the first one which is non-null.
57
- * **uri **: Use the URI provided by the ``uri `` option.
58
- * **route **: Generate a URL using the route named by the ``route `` option
59
- and the parameters provided by the ``routeParameters `` option.
60
- * **content **: Generate a URL by passing the value of the ``content `` option to
61
- the content URL generator, using any parameters provided by the
62
- ``routeParameters `` option.
61
+ `null``
62
+ If the value is ``null `` (or the option is not set) then the link type is
63
+ determined automatically by looking at each of the ``uri ``, ``route `` and
64
+ ``content `` options; using the first one which is non-null;
63
65
64
- Menu Nodes without URL
65
- ~~~~~~~~~~~~~~~~~~~~~~
66
+ uri
67
+ Use the URI provided by the `` uri `` option;
66
68
67
- A menu node document might not have a URL, when that information was never set
68
- or it points to a content that has been deleted meanwhile. In that case, there
69
- are two options: The menu node can be skipped, or it can be rendered as text
70
- without link. By default, the node is skipped.
69
+ route
70
+ Generate a URL using the route named by the ``route `` option and the
71
+ parameters provided by the ``routeParameters `` option;
71
72
72
- You can set ``cmf_menu.allow_empty_items `` to true to render nodes without URL.
73
+ content
74
+ Generate a URL by passing the value of the ``content `` option to the
75
+ content URL generator, using any parameters provided by the
76
+ ``routeParameters `` option.
73
77
74
78
Publish Workflow
75
- ----------------
76
-
77
- The CMF menu factory also determines if menu nodes are published and therefore
78
- visible by use of the :doc: `publish workflow checker
79
- <../core/publish_workflow>`.
79
+ ~~~~~~~~~~~~~~~~
80
80
81
- .. versionadded :: 1.1
82
- The ``MenuContentVoter `` was introduced in CmfMenuBundle 1.1.
83
-
84
- The ``MenuContentVoter `` decides that a menu node is not published if the
85
- content it is pointing to is not published.
81
+ The CmfMenuBundle provides a ``MenuContentVoter ``, which checks if the
82
+ referenced content is published using the
83
+ :doc: `publish workflow checker <../core/publish_workflow >`. If the content is
84
+ not yet published, the menu item not will not be rendered.
86
85
87
86
Customizing Menus using Events
88
87
------------------------------
89
88
90
- The CMF menu factory dispatches a ``cmf_menu.create_menu_item_from_node `` event
91
- during the process of creating a ``MenuItem `` from a class implementing
92
- ``NodeInterface ``. You can use this event to control the ``MenuItem `` that is
93
- created. The ``CreateMenuItemFromNodeEvent `` provides access to the
94
- ``NodeInterface `` and ``ContentAwareFactory ``, which can be used to create a
95
- custom ``MenuItem ``, or to tell the factory to ignore the current node or its
96
- children. For example, this event is used by the
97
- :doc: `publish workflow checker <../core/publish_workflow >` to skip
98
- ``MenuItem `` generation for unpublished nodes.
99
-
100
- The ``CreateMenuItemFromNodeEvent `` which is dispatched includes the following
101
- methods which can be used to customize the creation of the ``MenuItem `` for a
102
- ``NodeInterface ``.
103
-
104
- * ``CreateMenuItemFromNodeEvent::setSkipNode(true|false) ``: Setting
105
- ``skipNode `` to true will prevent creation of item from the node and skip
106
- any child nodes.
107
- **Note: ** If ``setSkipNode(true) `` is called for ``Menu `` the
108
- ``ContentAwareFactory `` will still create an empty item for the menu. This is
109
- to prevent the KnpMenuBundle code from throwing an exception due to ``null ``
110
- being passed to a function to render a menu;
111
- * ``CreateMenuItemFromNodeEvent::setItem(ItemInterface $item|null) ``: A
112
- listener can call ``setItem `` to provide a custom item to use for the given node.
113
- If an item is set, the ``ContentAwareFactory `` will use it instead of
114
- creating one for the node. The children of the node will still be processed
115
- by the ``ContentAwareFactory `` and listeners will have an opportunity then to
116
- override their items using this method;
117
- * ``CreateMenuItemFromNodeEvent::setSkipChildren(true|false) ``: Listeners can
118
- set this to true and the ``ContentAwareFactory `` will skip processing of the
119
- children of the current node.
89
+ The CmfMenuBundle dispatches a ``cmf_menu.create_menu_item_from_node `` event
90
+ during the process of creating a menu item from a menu node. You can use this
91
+ event to control the ``MenuItem `` that is created and to mark the current node
92
+ or its children as skipped.
93
+
94
+ Listeners for this method receive a ``CreateMenuItemFromNodeEvent `` instance,
95
+ which provides access to node using the ``getNode() `` method and allows
96
+ skipping nodes using the ``setSkipNode() `` and ``setSkipChildren() `` methods.
97
+
98
+ .. note ::
99
+
100
+ If you mark the ``Menu `` document (the root node of each menu) as skipped,
101
+ an empty item is still created to avoid errors when rendering a menu.
102
+
103
+ You can use the ``setItem() `` method to set the menu item to use instead of one
104
+ generated using the menu node. The child nodes are still processed like normal
105
+ and added to this new item.
106
+
107
+ .. tip ::
108
+
109
+ You can inject the ``knp_menu.factory `` service in the listener to generate
110
+ new menu items from nodes.
120
111
121
112
Example Menu Listener
122
113
~~~~~~~~~~~~~~~~~~~~~
123
114
124
115
This listener handles menu nodes that point to a different menu by implementing
125
116
the ``MenuReferrerInterface ``::
126
117
127
- // src/Acme/DemoBundle /MenuReferrerInterface.php
128
- namespace Acme\DemoBundle ;
118
+ // src/AppBundle/Menu /MenuReferrerInterface.php
119
+ namespace AppBundle\Menu ;
129
120
130
121
interface MenuReferrerInterface
131
122
{
132
123
public function getMenuName();
133
124
public function getMenuOptions();
134
125
}
135
126
136
- namespace Acme\DemoBundle\EventListener;
127
+ // src/AppBundle/EventListener/CreateMenuItemFromMenuListener.php
128
+ namespace AppBundle\EventListener;
137
129
138
130
use Symfony\Cmf\Bundle\MenuBundle\Event\CreateMenuItemFromNodeEvent;
139
- use Acme\DemoBundle\MenuReferrerInterface;
140
131
use Knp\Menu\Provider\MenuProviderInterface;
132
+ use AppBundle\Menu\MenuReferrerInterface;
141
133
142
- class CreateMenuItemFromNodeListener
134
+ class CreateMenuItemFromMenuListener
143
135
{
144
- protected $provider;
136
+ private $provider;
145
137
146
138
public function __construct(MenuProviderInterface $provider)
147
139
{
@@ -162,9 +154,6 @@ the ``MenuReferrerInterface``::
162
154
163
155
$menu = $this->provider->get($menuName, $menuOptions);
164
156
$event->setItem($menu);
165
-
166
- // as this does not call $event->setSkipChildren(true),
167
- // children of $node will be rendered as children items of $menu.
168
157
}
169
158
}
170
159
@@ -176,12 +165,11 @@ The service needs to be tagged as event listener:
176
165
177
166
.. code-block :: yaml
178
167
179
- # src/Acme/DemoBundle/Resources /config/services.yml
168
+ # app /config/services.yml
180
169
services :
181
- acme_demo.listener.menu_referrer_listener :
182
- class : Acme\DemoBundle\EventListener\CreateMenuItemFromNodeListener
183
- arguments :
184
- - " @knp_menu.menu_provider"
170
+ app.menu_referrer_listener :
171
+ class : AppBundle\EventListener\CreateMenuItemFromMenuListener
172
+ arguments : ['@knp_menu.menu_provider']
185
173
tags :
186
174
-
187
175
name : kernel.event_listener
@@ -190,25 +178,31 @@ The service needs to be tagged as event listener:
190
178
191
179
.. code-block :: xml
192
180
193
- <!-- src/Acme/DemoBundle/Resources /config/services.xml -->
181
+ <!-- app /config/services.xml -->
194
182
<?xml version =" 1.0" encoding =" UTF-8" ?>
195
183
<container xmlns =" http://symfony.com/schema/dic/services" >
196
- <service id =" acme_demo.listener.menu_referrer_listener" class =" Acme\DemoBundle\EventListener\CreateMenuItemFromNodeListener" >
197
- <argument type =" service" id =" knp_menu.menu_provider" />
198
- <tag name =" kernel.event_listener"
199
- event =" cmf_menu.create_menu_item_from_node"
200
- method =" onCreateMenuItemFromNode"
201
- />
202
- </service >
184
+
185
+ <services >
186
+ <service id =" acme_demo.listener.menu_referrer_listener"
187
+ class =" AppBundle\EventListener\CreateMenuItemFromMenuListener"
188
+ >
189
+ <argument type =" service" id =" knp_menu.menu_provider" />
190
+
191
+ <tag name =" kernel.event_listener"
192
+ event =" cmf_menu.create_menu_item_from_node"
193
+ method =" onCreateMenuItemFromNode"
194
+ />
195
+ </service >
196
+ </services >
203
197
</container >
204
198
205
199
.. code-block :: php
206
200
207
- // src/Acme/DemoBundle/Resources /config/services.php
201
+ // app /config/services.php
208
202
use Symfony\Component\DependencyInjection\Definition;
209
203
use Symfony\Component\DependencyInjection\Reference;
210
204
211
- $definition = new Definition('Acme\DemoBundle\ EventListener\CreateMenuItemFromNodeListener ', array(
205
+ $definition = new Definition('AppBundle\ EventListener\CreateMenuItemFromMenuListener ', array(
212
206
new Reference('knp_menu.menu_provider'),
213
207
));
214
208
$definition->addTag('kernel.event_listener', array(
0 commit comments