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

Commit 6d7c24a

Browse files
committed
Merge pull request #738 from symfony-cmf/menu_20
Updated docs for CmfMenuBundle 2.0
2 parents c4f8127 + 793a18e commit 6d7c24a

File tree

8 files changed

+220
-272
lines changed

8 files changed

+220
-272
lines changed

book/structuring_content.rst

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -105,36 +105,29 @@ rendered by the ``MenuFactory``.
105105
The Factory
106106
...........
107107

108-
The ``ContentAwareFactory`` is a ``FactoryInterface`` implementation, which
109-
generates the full ``MenuItem`` hierarchy from the provided MenuNode. The data
110-
generated this way is later used to generate the actual HTML representation of
111-
the menu.
108+
Menu factories generate the full ``MenuItem`` hierarchy from the provided
109+
menu node. The data generated this way is later used to generate the actual
110+
HTML representation of the menu.
112111

113112
The included implementation focuses on generating ``MenuItem`` instances from
114113
``NodeInterface`` instances, as this is usually the best approach to handle
115114
tree-like structures typically used by a CMS. Other approaches are implemented in
116-
the base classes, and their respective documentation pages can be found in
115+
the base classes and their respective documentation pages can be found in
117116
KnpMenuBundle_'s page.
118117

119-
``ContentAwareFactory`` is responsible for loading the full menu hierarchy and
120-
transforming the ``MenuNode`` instances from the root node it receives from
121-
the ``MenuProviderInterface`` implementation. It is also responsible for
122-
determining which (if any) menu item is currently being viewed by the user.
123-
It supports a voter mechanism to have custom code decide what menu item is
124-
the current item.
125-
``KnpMenu`` already includes a specific factory targeted at Symfony2's Routing
126-
component, which this bundle extends, to add support for:
127-
128-
* ``Route`` instances stored in a database (refer to :ref:`RoutingBundle's
129-
RouteProvider <start-routing-getting-route-object>` for more details on
130-
this)
118+
``KnpMenu`` already includes a specific factory targeted at the Symfony Routing
119+
component to add support for:
120+
121+
* ``Route`` instances stored in a database (refer to
122+
:ref:`RoutingBundle's RouteProvider <start-routing-getting-route-object>` for
123+
more details on this)
131124
* ``Route`` instances with associated content (more on this on respective
132125
:ref:`RoutingBundle's section <start-routing-linking-a-route-with-a-model-instance>`)
133126

134-
As mentioned before, ``ContentAwareFactory`` is responsible for loading
135-
all the menu nodes from the provided root element. The actual loaded nodes can
136-
be of any class, even if it's different from the root's, but all must
137-
implement ``NodeInterface`` in order to be included in the generated menu.
127+
As mentioned before, the factory is responsible for loading all the menu nodes
128+
from the provided root element. The actual loaded nodes can be of any class,
129+
even if it's different from the root's, but all must implement
130+
``NodeInterface`` in order to be included in the generated menu.
138131

139132
The Menu Nodes
140133
..............

bundles/menu/introduction.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ tree:
120120
121121
echo $view['knp_menu']->render('main-menu');
122122
123-
Here the ``main-menu`` document from the previous
124-
example is specified. This will render an unordered list as follows:
123+
Here the ``main-menu`` document from the previous example is specified. This
124+
will render an unordered list as follows:
125125

126126
.. code-block:: html
127127

bundles/menu/menu_factory.rst

Lines changed: 107 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -5,143 +5,135 @@ Menu Factory
55
============
66

77
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.
1111

1212
.. _bundles_menu_menu_factory_url_generation:
1313

1414
URL Generation
1515
--------------
1616

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.
4350

4451
.. _bundles_menu_menu_factory_link_type:
4552

46-
Link Type
47-
---------
53+
Specifying the Link Type
54+
~~~~~~~~~~~~~~~~~~~~~~~~
4855

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.
5158

5259
The values for this options can be one of the following:
5360

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;
6365

64-
Menu Nodes without URL
65-
~~~~~~~~~~~~~~~~~~~~~~
66+
uri
67+
Use the URI provided by the ``uri`` option;
6668

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;
7172

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.
7377

7478
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+
~~~~~~~~~~~~~~~~
8080

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.
8685

8786
Customizing Menus using Events
8887
------------------------------
8988

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.
120111

121112
Example Menu Listener
122113
~~~~~~~~~~~~~~~~~~~~~
123114

124115
This listener handles menu nodes that point to a different menu by implementing
125116
the ``MenuReferrerInterface``::
126117

127-
// src/Acme/DemoBundle/MenuReferrerInterface.php
128-
namespace Acme\DemoBundle;
118+
// src/AppBundle/Menu/MenuReferrerInterface.php
119+
namespace AppBundle\Menu;
129120

130121
interface MenuReferrerInterface
131122
{
132123
public function getMenuName();
133124
public function getMenuOptions();
134125
}
135126

136-
namespace Acme\DemoBundle\EventListener;
127+
// src/AppBundle/EventListener/CreateMenuItemFromMenuListener.php
128+
namespace AppBundle\EventListener;
137129

138130
use Symfony\Cmf\Bundle\MenuBundle\Event\CreateMenuItemFromNodeEvent;
139-
use Acme\DemoBundle\MenuReferrerInterface;
140131
use Knp\Menu\Provider\MenuProviderInterface;
132+
use AppBundle\Menu\MenuReferrerInterface;
141133

142-
class CreateMenuItemFromNodeListener
134+
class CreateMenuItemFromMenuListener
143135
{
144-
protected $provider;
136+
private $provider;
145137

146138
public function __construct(MenuProviderInterface $provider)
147139
{
@@ -162,9 +154,6 @@ the ``MenuReferrerInterface``::
162154

163155
$menu = $this->provider->get($menuName, $menuOptions);
164156
$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.
168157
}
169158
}
170159

@@ -176,12 +165,11 @@ The service needs to be tagged as event listener:
176165

177166
.. code-block:: yaml
178167
179-
# src/Acme/DemoBundle/Resources/config/services.yml
168+
# app/config/services.yml
180169
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']
185173
tags:
186174
-
187175
name: kernel.event_listener
@@ -190,25 +178,31 @@ The service needs to be tagged as event listener:
190178
191179
.. code-block:: xml
192180
193-
<!-- src/Acme/DemoBundle/Resources/config/services.xml -->
181+
<!-- app/config/services.xml -->
194182
<?xml version="1.0" encoding="UTF-8" ?>
195183
<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>
203197
</container>
204198
205199
.. code-block:: php
206200
207-
// src/Acme/DemoBundle/Resources/config/services.php
201+
// app/config/services.php
208202
use Symfony\Component\DependencyInjection\Definition;
209203
use Symfony\Component\DependencyInjection\Reference;
210204
211-
$definition = new Definition('Acme\DemoBundle\EventListener\CreateMenuItemFromNodeListener', array(
205+
$definition = new Definition('AppBundle\EventListener\CreateMenuItemFromMenuListener', array(
212206
new Reference('knp_menu.menu_provider'),
213207
));
214208
$definition->addTag('kernel.event_listener', array(

0 commit comments

Comments
 (0)