fix php 5.6 in docker dev env (#1740)
[openemr.git] / vendor / zendframework / zend-navigation / doc / book / helpers / intro.md
blobf97a9d291edd03f9343bd863ebee4e8966eb557a
1 # View Helpers
3 The navigation helpers are used for rendering navigational elements from
4 [`Zend\Navigation\Navigation`](../containers.md) instances.
6 There are 5 built-in helpers:
8 - [Breadcrumbs](breadcrumbs.md), used for rendering the path to the currently
9   active page.
10 - [Links](links.md), used for rendering navigational head links (e.g.
11   `<link rel="next" href="..." />`).
12 - [Menu](menu.md), used for rendering menus.
13 - [Sitemap](sitemap.md), used for rendering sitemaps conforming to the
14   [Sitemaps XML format](http://www.sitemaps.org/protocol.php).
15 - [Navigation](navigation.md), used for proxying calls to other navigational
16   helpers.
18 All built-in helpers extend `Zend\View\Helper\Navigation\AbstractHelper`, which
19 adds integration with
20 [zend-acl](https://zendframework.github.io/zend-permissions-acl/) and
21 [zend-i18n](https://zendframework.github.io/zend-i18n/). The abstract class
22 implements the interface `Zend\View\Helper\Navigation\HelperInterface`, which
23 defines the following methods:
25 Method signature                                                      | Description
26 --------------------------------------------------------------------- | -----------
27 `getContainer() : null|AbstractContainer`                             | Retrieve the current navigation container, if any.
28 `hasContainer() : bool`                                               | Is any navigation container currently registered?
29 `setContainer(AbstractContainer $container) : self`                   | Set a navigation container.
30 `getTranslator() : null|Zend\I18n\Translator\TranslatorInterface`     | Retrieve the current translator instance, if any.
31 `setTranslator(Zend\I18n\Translator\TranslatorInterface`) : self`     | Set a translator instance to use with labels.
32 `hasTranslator() | bool`                                              | Is a translator instance present?
33 `isTranslatorEnabled() : bool`                                        | Should translation occur? To be `true`, both the flag enabling translation must be set, and a translator instance present.
34 `setTranslatorEnabled(bool $flag) : self`                             | Set the flag indicating whether or not translation should occur.
35 `getAcl() : null|Zend\Permissions\Acl\AclInterface`                   | Retrieve the current ACL instance, if any.
36 `setAcl(Zend\Permissions\Acl\AclInterface $acl) : self`               | Set an ACL instance.
37 `hasAcl() : bool`                                                     | Whether or not an ACL instance is present.
38 `getRole() : null|string|Zend\Permissions\Acl\Role\RoleInterface`     | Retrieve the current ACL role instance, if any.
39 `setRole(string|Zend\Permissions\Acl\Role\RoleInterface $acl) : self` | Set an ACL role instance.
40 `hasRole() : bool`                                                    | Whether or not an ACL role instance is present.
41 `getUseAcl() : bool`                                                  | Whether or not to use ACLs; both the flag must be enabled and an ACL instance present.
42 `setUseAcl(bool $flag) : self`                                        | Set the flag indicating whether or not to use ACLs.
43 `__toString()`                                                        | Cast the helper to a string value; relies on `render()`.
44 `render()`                                                            | Render the helper to a string.
46 In addition to the method stubs from the interface, the abstract class also
47 implements the following methods:
49 Method signature                                                             | Description
50 ---------------------------------------------------------------------------- | -----------
51 `getIndent() : string`                                                       | Retrieve the indentation string to use; default is 4 spaces.
52 `setIndent(string|int $indent) : self`                                       | Set the indentation to use. In the case of an integer, this indicates the number of spaces. Indentation can be specified for all but the `Sitemap` helper.
53 `getMinDepth() : int`                                                        | Retrieve the minimum depth a page must have to be included in output
54 `setMinDepth(null|int $depth) : self`                                        | Set the minimum depth a page must have to be included in output; `null` means no minimum.
55 `getMaxDepth() : int`                                                        | Retrieve the maximum depth a page must have to be included in output
56 `setMaxDepth(null|int $depth) : self`                                        | Set the maximum depth a page must have to be included in output; `null` means no maximum.
57 `getRenderInvisible() : bool`                                                | Retrieve the flag indicating whether or not to render items marked as invisible; defaults to `false`.
58 `setRenderInvisible(bool $flag) : self`                                      | Set the flag indicating whether or not to render items marked as invisible.
59 `__call() : mixed`                                                           | Proxy method calls to the registered container; this allows you to use the helper as if it were a navigation container. See [the example below](#proxying-calls-to-the-navigation-container).
60 `findActive(/* ... */) : array`                                              | Find the deepest active page in the container, using the arguments `AbstractContainer $container, int $minDepth = null, int $maxDepth = -1)`. If depths are not given, the method will use the values retrieved from `getMinDepth()` and `getMaxDepth()`. The deepest active page must be between `$minDepth` and `$maxDepth` inclusively. Returns an array containing the found page instance (key `page`) and the depth (key `depth`) at which the page was found.
61 `htmlify(AbstractPage $page) : string`                                       | Renders an HTML `a` element based on the give page.
62 `accept(AbstractPage $page, bool $recursive = true) : bool`                  | Determine if a page should be accepted when iterating containers. This method checks for page visibility and verifies that the helper's role is allowed access to the page's resource and privilege.
63 `static setDefaultAcl(Zend\Permissions\Acl\AclInterface $acl) : void`        | Set a default ACL instance to use with all navigation helpers.
64 `static setDefaultRole(Zend\Permissions\Acl\Role\RoleInterface $acl) : void` | Set a default ACL role instance to use with all navigation helpers.
66 If a container is not explicitly set, the helper will create an empty
67 `Zend\Navigation\Navigation` container when calling `$helper->getContainer()`.
69 ### Proxying calls to the navigation container
71 Navigation view helpers use the magic method `__call()` to proxy method calls to
72 the navigation container that is registered in the view helper.
74 ```php
75 $this->navigation()->addPage([
76     'type' => 'uri',
77     'label' => 'New page',
78 ]);
79 ```
81 The call above will add a page to the container in the `Navigation` helper.
83 ## Translation of labels and titles
85 The navigation helpers support translation of page labels and titles. You can
86 set a translator of type `Zend\I18n\Translator\TranslatorInterface` in the
87 helper using `$helper->setTranslator($translator)`.
89 If you want to disable translation, use `$helper->setTranslatorEnabled(false)`.
91 The [proxy helper](navigation.md) will inject its own translator to the helper
92 it proxies to if the proxied helper doesn't already have a translator.
94 > ### Sitemaps do not use translation
96 > There is no translation in the sitemap helper, since there are no page labels
97 > or titles involved in an XML sitemap.
99 ## Integration with ACL
101 All navigational view helpers support ACLs.  An object implementing
102 `Zend\Permissions\Acl\AclInterface` can be assigned to a helper instance with
103 `$helper->setAcl($acl)`, and role with `$helper->setRole('member')` or
104 `$helper->setRole(new Zend\Permissions\Acl\Role\GenericRole('member'))`. If an
105 ACL is used in the helper, the role in the helper must be allowed by the ACL to
106 access a page's `resource` and/or have the page's `privilege` for the page to be
107 included when rendering.
109 If a page is not accepted by ACL, any descendant page will also be excluded from
110 rendering.
112 The [proxy helper](navigation.md) will inject its own ACL and role to the helper
113 it proxies to if the proxied helper doesn't already have any.
115 The examples below all show how ACL affects rendering.
117 ## Navigation setup used in examples
119 This example shows the setup of a navigation container for a fictional software company.
121 Notes on the setup:
123 - The domain for the site is `www.example.com`.
124 - Interesting page properties are marked with a comment.
125 - Unless otherwise is stated in other examples, the user is requesting the URL
126   `http://www.example.com/products/server/faq/`, which translates to the page
127   labeled `FAQ` under "Foo Server".
128 - The assumed ACL and router setup is shown below the container setup.
130 ```php
131 use Zend\Navigation\Navigation;
134  * Navigation container
136  * Each element in the array will be passed to
137  * Zend\Navigation\Page\AbstractPage::factory() when constructing
138  * the navigation container below.
139  */
140 $pages = [
141     [
142         'label'      => 'Home',
143         'title'      => 'Go Home',
144         'module'     => 'default',
145         'controller' => 'index',
146         'action'     => 'index',
147         'order'      => -100, // make sure home is the first page
148     ],
149     [
150         'label'      => 'Special offer this week only!',
151         'module'     => 'store',
152         'controller' => 'offer',
153         'action'     => 'amazing',
154         'visible'    => false, // not visible
155     ],
156     [
157         'label'      => 'Products',
158         'module'     => 'products',
159         'controller' => 'index',
160         'action'     => 'index',
161         'pages'      => [
162             [
163                 'label'      => 'Foo Server',
164                 'module'     => 'products',
165                 'controller' => 'server',
166                 'action'     => 'index',
167                 'pages'      => [
168                     [
169                         'label'      => 'FAQ',
170                         'module'     => 'products',
171                         'controller' => 'server',
172                         'action'     => 'faq',
173                         'rel'        => [
174                             'canonical' => 'http://www.example.com/?page=faq',
175                             'alternate' => [
176                                 'module'     => 'products',
177                                 'controller' => 'server',
178                                 'action'     => 'faq',
179                                 'params'     => ['format' => 'xml'],
180                             ],
181                         ],
182                     ],
183                     [
184                         'label'      => 'Editions',
185                         'module'     => 'products',
186                         'controller' => 'server',
187                         'action'     => 'editions',
188                     ],
189                     [
190                         'label'      => 'System Requirements',
191                         'module'     => 'products',
192                         'controller' => 'server',
193                         'action'     => 'requirements',
194                     ],
195                 ],
196             ],
197             [
198                 'label'      => 'Foo Studio',
199                 'module'     => 'products',
200                 'controller' => 'studio',
201                 'action'     => 'index',
202                 'pages'      => [
203                     [
204                         'label'      => 'Customer Stories',
205                         'module'     => 'products',
206                         'controller' => 'studio',
207                         'action'     => 'customers',
208                     ],
209                     [
210                         'label'      => 'Support',
211                         'module'     => 'products',
212                         'controller' => 'studio',
213                         'action'     => 'support',
214                     ],
215                 ],
216             ],
217         ],
218     ],
219     [
220         'label'      => 'Company',
221         'title'      => 'About us',
222         'module'     => 'company',
223         'controller' => 'about',
224         'action'     => 'index',
225         'pages'      => [
226             [
227                 'label'      => 'Investor Relations',
228                 'module'     => 'company',
229                 'controller' => 'about',
230                 'action'     => 'investors',
231             ],
232             [
233                 'label'      => 'News',
234                 'class'      => 'rss', // class
235                 'module'     => 'company',
236                 'controller' => 'news',
237                 'action'     => 'index',
238                 'pages'      => [
239                     [
240                         'label'      => 'Press Releases',
241                         'module'     => 'company',
242                         'controller' => 'news',
243                         'action'     => 'press',
244                     ],
245                     [
246                         'label'      => 'Archive',
247                         'route'      => 'archive', // route
248                         'module'     => 'company',
249                         'controller' => 'news',
250                         'action'     => 'archive',
251                     ],
252                 ],
253             ],
254         ],
255     ],
256     [
257         'label'      => 'Community',
258         'module'     => 'community',
259         'controller' => 'index',
260         'action'     => 'index',
261         'pages'      => [
262             [
263                 'label'      => 'My Account',
264                 'module'     => 'community',
265                 'controller' => 'account',
266                 'action'     => 'index',
267                 'resource'   => 'mvc:community.account', // resource
268             ],
269             [
270                 'label' => 'Forums',
271                 'uri'   => 'http://forums.example.com/',
272                 'class' => 'external', // class,
273             ],
274         ],
275     ],
276     [
277         'label'      => 'Administration',
278         'module'     => 'admin',
279         'controller' => 'index',
280         'action'     => 'index',
281         'resource'   => 'mvc:admin', // resource
282         'pages'      => [
283             [
284                 'label'      => 'Write new article',
285                 'module'     => 'admin',
286                 'controller' => 'post',
287                 'action'     => 'write',
288             ],
289         ],
290     ],
293 // Create container from array
294 $container = new Navigation($pages);
296 // Store the container in the proxy helper:
297 $view->plugin('navigation')->setContainer($container);
299 // ...or simply:
300 $view->navigation($container);
303 In addition to the container above, the following setup is assumed:
305 ```php
306 <?php
307 // module/MyModule/config/module.config.php
309 return [
310     /* ... */
311     'router' [
312         'routes' => [
313             'archive' => [
314                 'type'    => 'Segment',
315                 'options' => [
316                     'route'    => '/archive/:year',
317                     'defaults' => [
318                         'module'     => 'company',
319                         'controller' => 'news',
320                         'action'     => 'archive',
321                         'year'       => (int) date('Y') - 1,
322                     ],
323                     'constraints' => [
324                         'year' => '\d+',
325                     ],
326                 ],
327             ],
328             /* You can have other routes here... */
329         ],
330     ],
331     /* ... */
335 ```php
336 <?php
337 // module/MyModule/Module.php
339 namespace MyModule;
341 use Zend\View\HelperPluginManager;
342 use Zend\Permissions\Acl\Acl;
343 use Zend\Permissions\Acl\Role\GenericRole;
344 use Zend\Permissions\Acl\Resource\GenericResource;
346 class Module
348     /* ... */
349     public function getViewHelperConfig()
350     {
351         return [
352             'factories' => [
353                 // This will overwrite the native navigation helper
354                 'navigation' => function(HelperPluginManager $pm) {
355                     // Setup ACL:
356                     $acl = new Acl();
357                     $acl->addRole(new GenericRole('member'));
358                     $acl->addRole(new GenericRole('admin'));
359                     $acl->addResource(new GenericResource('mvc:admin'));
360                     $acl->addResource(new GenericResource('mvc:community.account'));
361                     $acl->allow('member', 'mvc:community.account');
362                     $acl->allow('admin', null);
364                     // Get an instance of the proxy helper
365                     $navigation = $pm->get('Zend\View\Helper\Navigation');
367                     // Store ACL and role in the proxy helper:
368                     $navigation->setAcl($acl);
369                     $navigation->setRole('member');
371                     // Return the new navigation helper instance
372                     return $navigation;
373                 }
374             ]
375         ];
376     }
377     /* ... */