PageRenderTime 55ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/doc/01-Basic-Menus.md

http://github.com/KnpLabs/KnpMenu
Markdown | 320 lines | 238 code | 82 blank | 0 comment | 0 complexity | 29fbb59618367ce3c83f6863ff5e4145 MD5 | raw file
  1. Creating Menus: The Basics
  2. ==========================
  3. Let's face it, creating menus sucks. Menus - a common aspect of any
  4. site - can range from being simple and mundane to giant monsters that
  5. become a headache to code and maintain.
  6. This bundle solves the issue by giving you a small, yet powerful and flexible
  7. framework for handling your menus. While most of the examples shown here
  8. are simple, the menus can grow arbitrarily large and deep.
  9. Creating a menu
  10. ---------------
  11. The menu framework centers around one main interface: `Knp\Menu\ItemInterface`.
  12. Items are created by a factory implementing `Knp\Menu\FactoryInterface`.
  13. It's best to think of each `ItemInterface` object as an `<li>` tag that can
  14. hold children objects (`<li>` tags that are wrapped in a `<ul>` tag).
  15. For example:
  16. ```php
  17. <?php
  18. use Knp\Menu\Matcher\Matcher;
  19. use Knp\Menu\MenuFactory;
  20. use Knp\Menu\Renderer\ListRenderer;
  21. $factory = new MenuFactory();
  22. $menu = $factory->createItem('My menu');
  23. $menu->addChild('Home', ['uri' => '/']);
  24. $menu->addChild('Comments', ['uri' => '#comments']);
  25. $menu->addChild('Symfony', ['uri' => 'http://symfony.com/']);
  26. $renderer = new ListRenderer(new Matcher());
  27. echo $renderer->render($menu);
  28. ```
  29. The above would render the following html code:
  30. ```html
  31. <ul>
  32. <li class="first">
  33. <a href="/">Home</a>
  34. </li>
  35. <li class="current">
  36. <a href="#comments">Comments</a>
  37. </li>
  38. <li class="last">
  39. <a href="http://symfony.com/">Symfony</a>
  40. </li>
  41. </ul>
  42. ```
  43. >**NOTE**
  44. >The menu framework automatically adds `first` and `last` classes to each
  45. >`<li>` tag at each level for easy styling. Notice also that a `current`
  46. >class is added to the "current" menu item by uri and `current_ancestor`
  47. >to its ancestors (the classes are configurable) The above example assumes
  48. >the menu is being rendered on the `/comments` page, making the Comments
  49. >menu the "current" item.
  50. When the menu is rendered, it's actually spaced correctly so that it appears
  51. as shown in the source html. This is to allow for easier debugging and can
  52. be turned off by passing the `true` as the second argument to the renderer.
  53. ```php
  54. <?php
  55. // ...
  56. $renderer = new ListRenderer(new Matcher(), ['compressed' => true]);
  57. echo $renderer->render($menu);
  58. ```
  59. You can also compress (or not compress) on a menu-by-menu basis by using the
  60. `compressed` option:
  61. ```php
  62. <?php
  63. // ...
  64. $renderer = new ListRenderer(new Matcher());
  65. echo $renderer->render($menu, ['compressed' => true]);
  66. ```
  67. Note: You can customize the rendering by extending the `ListRenderer` and
  68. overwrite some of its methods. If you use the [TwigRenderer](02-Twig-Integration.markdown), you can overwrite
  69. templates. Or you can provide your own implementation of the `RendererInterface`.
  70. Working with your menu tree
  71. ---------------------------
  72. Your menu tree works and acts like a multi-dimensional array. Specifically,
  73. it implements ArrayAccess, Countable and Iterator:
  74. ```php
  75. <?php
  76. use Knp\Menu\MenuFactory;
  77. $factory = new MenuFactory();
  78. $menu = $factory->createItem('My menu');
  79. $menu->addChild('Home', ['uri' => '/']);
  80. $menu->addChild('Comments');
  81. // ArrayAccess
  82. $menu['Comments']->setUri('#comments');
  83. $menu['Comments']->addChild('My comments', ['uri' => '/my_comments']);
  84. // Countable
  85. echo count($menu); // returns 2
  86. // Iterator
  87. foreach ($menu as $child) {
  88. echo $child->getLabel();
  89. }
  90. ```
  91. As you can see, the name you give your menu item (e.g. overview, comments)
  92. when creating it is the name you'll use when accessing it. By default,
  93. the name is also used when displaying the menu, but that can be overridden
  94. by setting the menu item's label (see below).
  95. Customizing each menu item
  96. --------------------------
  97. There are many ways to customize the output of each menu item. Each property
  98. can be customized in two ways: either by passing it as an option when creating
  99. the item, or by using the setter of an existing item.
  100. ### The label
  101. By default, a menu item uses its name when rendering. You can easily
  102. change this without changing the name of your menu item by setting its label:
  103. ```php
  104. <?php
  105. // Setting the label when creating the item
  106. $menu->addChild('Home', ['uri' => '/', 'label' => 'Back to homepage']);
  107. // Changing the label of an existing item
  108. $menu['Home']->setLabel('Back to homepage');
  109. ```
  110. ### The uri
  111. If an item isn't given a url, then text will be output instead of a link:
  112. ```php
  113. <?php
  114. $menu->addChild('Not a link');
  115. $menu->addChild('Home', '/');
  116. $menu->addChild('Symfony', 'http://www.symfony-reloaded.org');
  117. ```
  118. You can also specify the uri after creation via the `setUri()` method:
  119. ```php
  120. <?php
  121. $menu['Home']->setUri('/');
  122. ```
  123. >**NOTE**
  124. >If you want to remove the uri of an item, set it to `null`.
  125. ### Menu attributes
  126. In fact, you can add any attribute to the `<li>` tag of a menu item. This
  127. can be done when creating a menu item or via the `setAttribute()` and `setAttributes()`
  128. methods:
  129. ```php
  130. <?php
  131. $menu->addChild('Home', ['attributes' => ['id' => 'back_to_homepage']]);
  132. $menu['Home']->setAttribute('id', 'back_to_homepage');
  133. ```
  134. >**NOTE**
  135. >`setAttributes()` will overwrite all existing attributes.
  136. >**NOTE**
  137. >To remove an existing attribute, set it to `null`. It will not be rendered.
  138. You can also add link attributes (displayed on the `<a>` element), label
  139. attributes (displayed on the `<span>` element when it is not a link) or
  140. children attributes (rendered on the `<ul>` containing the list of children):
  141. ```php
  142. <?php
  143. $menu->addChild('KnpLabs.com', ['uri' => 'http://knplabs.com']);
  144. $menu['KnpLabs.com']->setLinkAttribute('class', 'external-link');
  145. $menu->addChild('Not a link');
  146. $menu['Not a link']->setLabelAttribute('class', 'no-link-span');
  147. $menu->setChildrenAttribute('class', 'pull-left');
  148. ```
  149. >**NOTE**
  150. >For the root element, only the children attributes are used as only the
  151. >`<ul>` element is displayed.
  152. >**NOTE**
  153. >In the 1.0 version of the library, the attributes were rendered on the root
  154. >element instead of rendering the children attributes, which was inconsistent
  155. >and has been changed for 1.1.
  156. ### Rendering only part of a menu
  157. If you need to render only part of your menu, the menu framework gives
  158. you unlimited control to do so:
  159. ```php
  160. <?php
  161. // render only 2 levels deep (root, parents, children)
  162. $renderer->render($menu, ['depth' => 2]);
  163. // rendering everything except for the children of the Home branch
  164. $menu['Home']->setDisplayChildren(false);
  165. $renderer->render($menu);
  166. // render everything except for Home AND its children
  167. $menu['Home']->setDisplay(false);
  168. $renderer->render($menu);
  169. ```
  170. Using the above controls, you can specify exactly which part of your menu
  171. you need to render at any given time.
  172. ### Other rendering options
  173. Most renderers also support several other options, which can be passed as
  174. the second argument to the `render()` method:
  175. * `depth`
  176. * `matchingDepth`: The depth of the scan to determine whether an item
  177. is an ancestor of the current item.
  178. * `currentAsLink` (default: `true`): Whether to render the "current" menu item as link or as span.
  179. * `currentClass` (default: `current`)
  180. * `ancestorClass` (default: `current_ancestor`)
  181. * `firstClass` (default: `first`)
  182. * `lastClass` (default: `last`)
  183. * `compressed` (default: `false`)
  184. * `allow_safe_labels` (default: `false`)
  185. * `clear_matcher` (default `true`): whether to clear the internal cache of the matcher after rendering
  186. * `leaf_class` (default: `null`): class for leaf elements in your html tree
  187. * `branch_class` (default: `null`): class for branch elements in your html tree
  188. >**NOTE**
  189. >When setting the `allow_safe_labels` option to `true`, you can specify that
  190. >a label should not be escaped by the renderer by adding the `safe_label`
  191. >extra in the item. Use it with caution as it can create some XSS holes in
  192. >your application if the label is coming from the user.
  193. The Current Menu Item
  194. ---------------------
  195. If the menu item is matched as current, a `current` class will be added to
  196. the `li` around that item, as well as a `current_ancestor` around any of
  197. its parent `li` elements. This state can either be forced on the item by
  198. setting it explicitly or matched using several voters.
  199. By default, the current item is rendered as link too. You can make the current
  200. item not a link by setting the `currentAsLink` option to false. The ListRenderer
  201. then renders the item with a `<span>` tag instead of an `<a>`.
  202. ```php
  203. <?php
  204. use Knp\Menu\Matcher\Matcher;
  205. use Knp\Menu\Matcher\Voter\UriVoter;
  206. use Knp\Menu\MenuFactory;
  207. use Knp\Menu\Renderer\ListRenderer;
  208. $factory = new MenuFactory();
  209. $menu = $factory->createItem('My menu');
  210. // set the current state explicitly
  211. $menu['current_item']->setCurrent(true);
  212. $menu['non_current_item']->setCurrent(false);
  213. // Use the voter
  214. $menu['other_item']->setCurrent(null); // default value for items
  215. $matcher = new Matcher();
  216. $matcher->addVoter(new UriVoter($_SERVER['REQUEST_URI']));
  217. $renderer = new ListRenderer($matcher);
  218. ```
  219. The library provides 3 implementations of the VoterInterface:
  220. * `Knp\Menu\Matcher\Voter\UriVoter` matching against the uri of the item
  221. * `Knp\Menu\Matcher\Voter\RouteVoter` matching the `_route` attribute of a
  222. Symfony Request object against the `routes` extra of the item
  223. * `Knp\Menu\Matcher\Voter\RegexVoter` matching against the uri of the item using a regular expression
  224. Here are some examples for instantiation of voters:
  225. ```php
  226. <?php
  227. $regexVoter = new \Knp\Menu\Matcher\Voter\RegexVoter('/^StartOfUri/');
  228. $routeVoter = new \Knp\Menu\Silex\Voter\RouteVoter();
  229. $routeVoter->setRequest($symfonyRequest);
  230. ```
  231. Creating a Menu from a Tree structure
  232. -------------------------------------
  233. See [Advanced Menu documentation page](01a-Advanced-Menu.md)
  234. Change the charset
  235. ------------------
  236. ```php
  237. $renderer = new ListRenderer(new Matcher(), [], 'ISO-8859-1');
  238. ```