fix php 5.6 in docker dev env (#1740)
[openemr.git] / vendor / zendframework / zend-navigation / doc / book / containers.md
blob9ee20dd91fcf2e00314b7f9e1e2c797b27687f6a
1 # Containers
3 Containers have methods for adding, retrieving, deleting, and iterating pages.
4 Containers implement the [SPL](http://php.net/spl) interfaces
5 `RecursiveIterator` and `Countable`, meaning that a container can be iterated
6 using the SPL `RecursiveIteratorIterator` class.
8 ## Creating containers
10 `Zend\Navigation\AbstractContainer` can not be instantiated directly. Use
11 `Zend\Navigation\Navigation` if you want to instantiate a container.
13 `Zend\Navigation\Navigation` can be constructed entirely empty, or take an array
14 or a `Traversable` object with pages to put in the container. Each page provided
15 via options will eventually be passed to the `addPage()` method of the container
16 class, which means that each element in the options can be also be an array,
17 Traversable object, or a `Zend\Navigation\Page\AbstractPage` instance.
19 ### Creating a container using an array
21 ```php
22 use Zend\Navigation\Navigation;
25  * Create a container from an array
26  *
27  * Each element in the array will be passed to
28  * Zend\Navigation\Page\AbstractPage::factory() when constructing.
29  */
30 $container = new Navigation([
31     [
32         'label' => 'Page 1',
33         'id' => 'home-link',
34         'uri' => '/',
35     ],
36     [
37         'label' => 'Zend',
38         'uri' => 'http://www.zend-project.com/',
39         'order' => 100,
40     ],
41     [
42         'label' => 'Page 2',
43         'controller' => 'page2',
44         'pages' => [
45             [
46                 'label' => 'Page 2.1',
47                 'action' => 'page2_1',
48                 'controller' => 'page2',
49                 'class' => 'special-one',
50                 'title' => 'This element has a special class',
51                 'active' => true,
52             ],
53             [
54                 'label' => 'Page 2.2',
55                 'action' => 'page2_2',
56                 'controller' => 'page2',
57                 'class' => 'special-two',
58                 'title' => 'This element has a special class too',
59             ],
60         ],
61     ],
62     [
63         'label' => 'Page 2 with params',
64         'action' => 'index',
65         'controller' => 'page2',
66         // specify a param or two,
67         'params' => [
68             'format' => 'json',
69             'foo' => 'bar',
70         ]
71     ],
72     [
73         'label' => 'Page 2 with params and a route',
74         'action' => 'index',
75         'controller' => 'page2',
77         // specify a route name and a param for the route
78         'route' => 'nav-route-example',
79         'params' => [
80             'format' => 'json',
81         ],
82     ],
83     [
84         'label' => 'Page 3',
85         'action' => 'index',
86         'controller' => 'index',
87         'module' => 'mymodule',
88         'reset_params' => false,
89     ],
90     [
91         'label' => 'Page 4',
92         'uri' => '#',
93         'pages' => [
94             [
95                 'label' => 'Page 4.1',
96                 'uri' => '/page4',
97                 'title' => 'Page 4 using uri',
98                 'pages' => [
99                     [
100                         'label' => 'Page 4.1.1',
101                         'title' => 'Page 4 using mvc params',
102                         'action' => 'index',
103                         'controller' => 'page4',
104                         // let's say this page is active
105                         'active' => '1',
106                     ]
107                 ],
108             ],
109         ],
110     ],
111     [
112         'label' => 'Page 0?',
113         'uri' => '/setting/the/order/option',
115         // setting order to -1 should make it appear first
116         'order' => -1,
117     ],
118     [
119         'label' => 'Page 5',
120         'uri' => '/',
122         // this page should not be visible
123         'visible' => false,
124         'pages' => [
125             [
126                 'label' => 'Page 5.1',
127                 'uri' => '#',
128                 'pages' => [
129                     [
130                         'label' => 'Page 5.1.1',
131                         'uri' => '#',
132                         'pages' => [
133                             [
134                                 'label' => 'Page 5.1.2',
135                                 'uri' => '#',
137                                 // let's say this page is active
138                                 'active' => true,
139                             ],
140                         ],
141                     ],
142                 ],
143             ],
144         ],
145     ],
146     [
147         'label' => 'ACL page 1 (guest)',
148         'uri' => '#acl-guest',
149         'resource' => 'nav-guest',
150         'pages' => [
151             [
152                 'label' => 'ACL page 1.1 (foo)',
153                 'uri' => '#acl-foo',
154                 'resource' => 'nav-foo',
155             ],
156             [
157                 'label' => 'ACL page 1.2 (bar)',
158                 'uri' => '#acl-bar',
159                 'resource' => 'nav-bar',
160             ],
161             [
162                 'label' => 'ACL page 1.3 (baz)',
163                 'uri' => '#acl-baz',
164                 'resource' => 'nav-baz',
165             ],
166             [
167                 'label' => 'ACL page 1.4 (bat)',
168                 'uri' => '#acl-bat',
169                 'resource' => 'nav-bat',
170             ],
171         ],
172     ],
173     [
174         'label' => 'ACL page 2 (member)',
175         'uri' => '#acl-member',
176         'resource' => 'nav-member',
177     ],
178     [
179         'label' => 'ACL page 3 (admin',
180         'uri' => '#acl-admin',
181         'resource' => 'nav-admin',
182         'pages' => [
183             [
184                 'label' => 'ACL page 3.1 (nothing)',
185                 'uri' => '#acl-nada',
186             ],
187         ],
188     ],
189     [
190         'label' => 'Zend Framework',
191         'route' => 'zf-route',
192     ],
196 ## Adding pages
198 Adding pages to a container can be done with the methods `addPage()`,
199 `addPages()`, or `setPages()`.  See examples below for explanation.
201 ```php
202 use Zend\Config\Config;
203 use Zend\Navigation\Navigation;
204 use Zend\Navigation\Page\AbstractPage;
206 // create container
207 $container = new Navigation();
209 // add page by giving a page instance
210 $container->addPage(AbstractPage::factory([
211     'uri' => 'http://www.example.com/',
212 ]]);
214 // add page by giving an array
215 $container->addPage([
216     'uri' => 'http://www.example.com/',
219 // add page by giving a Traversable object; in this case, a zend-config
220 // instance.
221 $container->addPage(Config([
222     'uri' => 'http://www.example.com/',
223 ]));
225 $pages = [
226     [
227         'label'  => 'Save',
228         'action' => 'save',
229     ],
230     [
231         'label' =>  'Delete',
232         'action' => 'delete',
233     ],
236 // add two pages
237 $container->addPages($pages);
239 // remove existing pages and add the given pages
240 $container->setPages($pages);
243 ## Removing pages
245 Removing pages can be done with `removePage()` or `removePages()`.
246 `removePage()` accepts an instance of a page or an integer. Integer arguments
247 correspond to the `order` a page has. `removePages()` will remove all pages in
248 the container.
250 ```php
251 use Zend\Navigation\Navigation;
253 $container = new Navigation([
254     [
255         'label'  => 'Page 1',
256         'action' => 'page1',
257     ],
258     [
259         'label'  => 'Page 2',
260         'action' => 'page2',
261         'order'  => 200,
262     ],
263     [
264         'label'  => 'Page 3',
265         'action' => 'page3',
266     ],
269 // remove page by implicit page order
270 $container->removePage(0);      // removes Page 1
272 // remove page by instance
273 $page3 = $container->findOneByAction('page3');
274 $container->removePage($page3); // removes Page 3
276 // remove page by explicit page order
277 $container->removePage(200);    // removes Page 2
279 // remove all pages
280 $container->removePages();      // removes all pages
283 ### Remove a page recursively
285 Removing a page recursively can be done with the second parameter of 
286 the `removePage()` method, which expects a `boolean` value.
288 ```php
289 use Zend\Navigation\Navigation;
291 $container = new Navigation(
292     [
293         [
294             'label' => 'Page 1',
295             'route' => 'page1',
296             'pages' => [
297                 [
298                     'label' => 'Page 1.1',
299                     'route' => 'page1/page1-1',
300                     'pages' => [
301                         [
302                             'label' => 'Page 1.1.1',
303                             'route' => 'page1/page1-1/page1-1-1',
304                         ],
305                     ],
306                 ],
307             ],
308         ],
309     ]
312 // Removes Page 1.1.1
313 $container->removePage(
314     $container->findOneBy('route', 'page1/page1-1/page1-1-1'),
315     true
319 ## Finding pages
321 Containers have three finder methods for retrieving pages. Each recursively
322 searches the container testing for properties with values that match the one
323 provided.
325 - `findOneBy($property, $value) : AbstractPage|null`: Returns the first page
326   found matching the criteria, or `null` if none was found.
327 - `findAllBy($property, $value) : AbstractPage[]`: Returns an array of all
328   page instances matching the criteria.
329 - `findBy($property, $value, $all = false) AbstractPage|AbstractPage[]|null`:
330   calls on one of the previous methods based on the value of `$all`.
332 The finder methods can also be used magically by appending the property name to
333 `findBy`, `findOneBy`, or `findAllBy`. As an example, `findOneByLabel('Home')`
334 will return the first matching page with label 'Home'.
335     
336 Other combinations include `findByLabel(...)`, `findOneByTitle(...)`,
337 `findAllByController(...)`, etc. Finder methods also work on custom properties,
338 such as `findByFoo('bar')`.
340 ```php
341 use Zend\Navigation\Navigation;
343 $container = new Navigation([
344     [
345         'label' => 'Page 1',
346         'uri'   => 'page-1',
347         'foo'   => 'bar',
348         'pages' => [
349             [
350                 'label' => 'Page 1.1',
351                 'uri'   => 'page-1.1',
352                 'foo'   => 'bar',
353             ],
354             [
355                 'label' => 'Page 1.2',
356                 'uri'   => 'page-1.2',
357                 'class' => 'my-class',
358             ],
359             [
360                 'type'   => 'uri',
361                 'label'  => 'Page 1.3',
362                 'uri'    => 'page-1.3',
363                 'action' => 'about',
364             ],
365         ],
366     ],
367     [
368         'label'      => 'Page 2',
369         'id'         => 'page_2_and_3',
370         'class'      => 'my-class',
371         'module'     => 'page2',
372         'controller' => 'index',
373         'action'     => 'page1',
374     ],
375     [
376         'label'      => 'Page 3',
377         'id'         => 'page_2_and_3',
378         'module'     => 'page3',
379         'controller' => 'index',
380     ],
383 // The 'id' is not required to be unique, but be aware that
384 // having two pages with the same id will render the same id attribute
385 // in menus and breadcrumbs.
387 // Returns "Page 2":
388 $found = $container->findBy('id', 'page_2_and_3');
390 // Returns "Page 2":
391 $found = $container->findOneBy('id', 'page_2_and_3');
393 // Returns "Page 2" AND "Page 3":
394 $found = $container->findBy('id', 'page_2_and_3', true);
396 // Returns "Page 2":
397 $found = $container->findById('page_2_and_3');
399 // Returns "Page 2":
400 $found = $container->findOneById('page_2_and_3');
402 // Returns "Page 2" AND "Page 3":
403 $found = $container->findAllById('page_2_and_3');
405 // Find all pages matching the CSS class "my-class":
406 // Returns "Page 1.2" and "Page 2":
407 $found = $container->findAllBy('class', 'my-class');
408 $found = $container->findAllByClass('my-class');
410 // Find first page matching CSS class "my-class":
411 // Returns "Page 1.2":
412 $found = $container->findOneByClass('my-class');
414 // Find all pages matching the CSS class "non-existent":
415 // Returns an empty array.
416 $found = $container->findAllByClass('non-existent');
418 // Find first page matching the CSS class "non-existent":
419 // Returns null.
420 $found = $container->findOneByClass('non-existent');
422 // Find all pages with custom property 'foo' = 'bar':
423 // Returns "Page 1" and "Page 1.1":
424 $found = $container->findAllBy('foo', 'bar');
426 // To achieve the same magically, 'foo' must be in lowercase.
427 // This is because 'foo' is a custom property, and thus the
428 // property name is not normalized to 'Foo':
429 $found = $container->findAllByfoo('bar');
431 // Find all with controller = 'index':
432 // Returns "Page 2" and "Page 3":
433 $found = $container->findAllByController('index');
436 ## Iterating containers
438 `Zend\Navigation\AbstractContainer` implements `RecursiveIterator`.  iterate a
439 container recursively, use the `RecursiveIteratorIterator` class.
441 ```php
442 use RecursiveIteratorIterator;
443 use Zend\Navigation\Navigation;
446  * Create a container from an array
447  */
448 $container = new Navigation([
449     [
450         'label' => 'Page 1',
451         'uri'   => '#',
452     ],
453     [
454         'label' => 'Page 2',
455         'uri'   => '#',
456         'pages' => [
457             [
458                 'label' => 'Page 2.1',
459                 'uri'   => '#',
460             ],
461             [
462                 'label' => 'Page 2.2',
463                 'uri'   => '#',
464             ],
465         ],
466     ],
467     [
468         'label' => 'Page 3',
469         'uri'   => '#',
470     ],
473 // Iterate flat using regular foreach:
474 // Output: Page 1, Page 2, Page 3
475 foreach ($container as $page) {
476     echo $page->label;
479 // Iterate recursively using RecursiveIteratorIterator
480 $it = new RecursiveIteratorIterator(
481     $container,
482     RecursiveIteratorIterator::SELF_FIRST
485 // Output: Page 1, Page 2, Page 2.1, Page 2.2, Page 3
486 foreach ($it as $page) {
487     echo $page->label;
491 ## Other operations
493 ### hasPage
495 ```php
496 hasPage(AbstractPage $page) : bool
499 Check if the container has the given page.
501 ### hasPages
503 ```php
504 hasPages() : bool
507 Checks if there are any pages in the container, and is equivalent to
508 `count($container) > 0`.
510 ### toArray
512 ```php
513 toArray() : array
516 Converts the container and the pages in it to a (nested) array. This can be useful
517 for serializing and debugging.
519 ```php
520 use Zend\Navigation\Navigation;
522 $container = new Navigation([
523     [
524         'label' => 'Page 1',
525         'uri'   => '#',
526     ],
527     [
528         'label' => 'Page 2',
529         'uri'   => '#',
530         'pages' => [
531             [
532                 'label' => 'Page 2.1',
533                 'uri'   => '#',
534             ],
535             [
536                 'label' => 'Page 2.2',
537                'uri'   => '#',
538             ],
539         ],
540     ],
543 var_dump($container->toArray());
545 /* Output:
546 array(2) {
547   [0]=> array(15) {
548     ["label"]=> string(6) "Page 1"
549     ["id"]=> NULL
550     ["class"]=> NULL
551     ["title"]=> NULL
552     ["target"]=> NULL
553     ["rel"]=> array(0) {
554     }
555     ["rev"]=> array(0) {
556     }
557     ["order"]=> NULL
558     ["resource"]=> NULL
559     ["privilege"]=> NULL
560     ["active"]=> bool(false)
561     ["visible"]=> bool(true)
562     ["type"]=> string(23) "Zend\Navigation\Page\Uri"
563     ["pages"]=> array(0) {
564     }
565     ["uri"]=> string(1) "#"
566   }
567   [1]=> array(15) {
568     ["label"]=> string(6) "Page 2"
569     ["id"]=> NULL
570     ["class"]=> NULL
571     ["title"]=> NULL
572     ["target"]=> NULL
573     ["rel"]=> array(0) {
574     }
575     ["rev"]=> array(0) {
576     }
577     ["order"]=> NULL
578     ["resource"]=> NULL
579     ["privilege"]=> NULL
580     ["active"]=> bool(false)
581     ["visible"]=> bool(true)
582     ["type"]=> string(23) "Zend\Navigation\Page\Uri"
583     ["pages"]=> array(2) {
584       [0]=> array(15) {
585         ["label"]=> string(8) "Page 2.1"
586         ["id"]=> NULL
587         ["class"]=> NULL
588         ["title"]=> NULL
589         ["target"]=> NULL
590         ["rel"]=> array(0) {
591         }
592         ["rev"]=> array(0) {
593         }
594         ["order"]=> NULL
595         ["resource"]=> NULL
596         ["privilege"]=> NULL
597         ["active"]=> bool(false)
598         ["visible"]=> bool(true)
599         ["type"]=> string(23) "Zend\Navigation\Page\Uri"
600         ["pages"]=> array(0) {
601         }
602         ["uri"]=> string(1) "#"
603       }
604       [1]=>
605       array(15) {
606         ["label"]=> string(8) "Page 2.2"
607         ["id"]=> NULL
608         ["class"]=> NULL
609         ["title"]=> NULL
610         ["target"]=> NULL
611         ["rel"]=> array(0) {
612         }
613         ["rev"]=> array(0) {
614         }
615         ["order"]=> NULL
616         ["resource"]=> NULL
617         ["privilege"]=> NULL
618         ["active"]=> bool(false)
619         ["visible"]=> bool(true)
620         ["type"]=> string(23) "Zend\Navigation\Page\Uri"
621         ["pages"]=> array(0) {
622         }
623         ["uri"]=> string(1) "#"
624       }
625     }
626     ["uri"]=> string(1) "#"
627   }