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.
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
22 use Zend\Navigation\Navigation;
25 * Create a container from an array
27 * Each element in the array will be passed to
28 * Zend\Navigation\Page\AbstractPage::factory() when constructing.
30 $container = new Navigation([
38 'uri' => 'http://www.zend-project.com/',
43 'controller' => 'page2',
46 'label' => 'Page 2.1',
47 'action' => 'page2_1',
48 'controller' => 'page2',
49 'class' => 'special-one',
50 'title' => 'This element has a special class',
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',
63 'label' => 'Page 2 with params',
65 'controller' => 'page2',
66 // specify a param or two,
73 'label' => 'Page 2 with params and a route',
75 'controller' => 'page2',
77 // specify a route name and a param for the route
78 'route' => 'nav-route-example',
86 'controller' => 'index',
87 'module' => 'mymodule',
88 'reset_params' => false,
95 'label' => 'Page 4.1',
97 'title' => 'Page 4 using uri',
100 'label' => 'Page 4.1.1',
101 'title' => 'Page 4 using mvc params',
103 'controller' => 'page4',
104 // let's say this page is active
112 'label' => 'Page 0?',
113 'uri' => '/setting/the/order/option',
115 // setting order to -1 should make it appear first
122 // this page should not be visible
126 'label' => 'Page 5.1',
130 'label' => 'Page 5.1.1',
134 'label' => 'Page 5.1.2',
137 // let's say this page is active
147 'label' => 'ACL page 1 (guest)',
148 'uri' => '#acl-guest',
149 'resource' => 'nav-guest',
152 'label' => 'ACL page 1.1 (foo)',
154 'resource' => 'nav-foo',
157 'label' => 'ACL page 1.2 (bar)',
159 'resource' => 'nav-bar',
162 'label' => 'ACL page 1.3 (baz)',
164 'resource' => 'nav-baz',
167 'label' => 'ACL page 1.4 (bat)',
169 'resource' => 'nav-bat',
174 'label' => 'ACL page 2 (member)',
175 'uri' => '#acl-member',
176 'resource' => 'nav-member',
179 'label' => 'ACL page 3 (admin',
180 'uri' => '#acl-admin',
181 'resource' => 'nav-admin',
184 'label' => 'ACL page 3.1 (nothing)',
185 'uri' => '#acl-nada',
190 'label' => 'Zend Framework',
191 'route' => 'zf-route',
198 Adding pages to a container can be done with the methods `addPage()`,
199 `addPages()`, or `setPages()`. See examples below for explanation.
202 use Zend\Config\Config;
203 use Zend\Navigation\Navigation;
204 use Zend\Navigation\Page\AbstractPage;
207 $container = new Navigation();
209 // add page by giving a page instance
210 $container->addPage(AbstractPage::factory([
211 'uri' => 'http://www.example.com/',
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
221 $container->addPage(Config([
222 'uri' => 'http://www.example.com/',
232 'action' => 'delete',
237 $container->addPages($pages);
239 // remove existing pages and add the given pages
240 $container->setPages($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
251 use Zend\Navigation\Navigation;
253 $container = new Navigation([
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
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.
289 use Zend\Navigation\Navigation;
291 $container = new Navigation(
298 'label' => 'Page 1.1',
299 'route' => 'page1/page1-1',
302 'label' => 'Page 1.1.1',
303 'route' => 'page1/page1-1/page1-1-1',
312 // Removes Page 1.1.1
313 $container->removePage(
314 $container->findOneBy('route', 'page1/page1-1/page1-1-1'),
321 Containers have three finder methods for retrieving pages. Each recursively
322 searches the container testing for properties with values that match the one
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'.
336 Other combinations include `findByLabel(...)`, `findOneByTitle(...)`,
337 `findAllByController(...)`, etc. Finder methods also work on custom properties,
338 such as `findByFoo('bar')`.
341 use Zend\Navigation\Navigation;
343 $container = new Navigation([
350 'label' => 'Page 1.1',
355 'label' => 'Page 1.2',
357 'class' => 'my-class',
361 'label' => 'Page 1.3',
369 'id' => 'page_2_and_3',
370 'class' => 'my-class',
372 'controller' => 'index',
377 'id' => 'page_2_and_3',
379 'controller' => 'index',
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.
388 $found = $container->findBy('id', 'page_2_and_3');
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);
397 $found = $container->findById('page_2_and_3');
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":
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.
442 use RecursiveIteratorIterator;
443 use Zend\Navigation\Navigation;
446 * Create a container from an array
448 $container = new Navigation([
458 'label' => 'Page 2.1',
462 'label' => 'Page 2.2',
473 // Iterate flat using regular foreach:
474 // Output: Page 1, Page 2, Page 3
475 foreach ($container as $page) {
479 // Iterate recursively using RecursiveIteratorIterator
480 $it = new RecursiveIteratorIterator(
482 RecursiveIteratorIterator::SELF_FIRST
485 // Output: Page 1, Page 2, Page 2.1, Page 2.2, Page 3
486 foreach ($it as $page) {
496 hasPage(AbstractPage $page) : bool
499 Check if the container has the given page.
507 Checks if there are any pages in the container, and is equivalent to
508 `count($container) > 0`.
516 Converts the container and the pages in it to a (nested) array. This can be useful
517 for serializing and debugging.
520 use Zend\Navigation\Navigation;
522 $container = new Navigation([
532 'label' => 'Page 2.1',
536 'label' => 'Page 2.2',
543 var_dump($container->toArray());
548 ["label"]=> string(6) "Page 1"
560 ["active"]=> bool(false)
561 ["visible"]=> bool(true)
562 ["type"]=> string(23) "Zend\Navigation\Page\Uri"
563 ["pages"]=> array(0) {
565 ["uri"]=> string(1) "#"
568 ["label"]=> string(6) "Page 2"
580 ["active"]=> bool(false)
581 ["visible"]=> bool(true)
582 ["type"]=> string(23) "Zend\Navigation\Page\Uri"
583 ["pages"]=> array(2) {
585 ["label"]=> string(8) "Page 2.1"
597 ["active"]=> bool(false)
598 ["visible"]=> bool(true)
599 ["type"]=> string(23) "Zend\Navigation\Page\Uri"
600 ["pages"]=> array(0) {
602 ["uri"]=> string(1) "#"
606 ["label"]=> string(8) "Page 2.2"
618 ["active"]=> bool(false)
619 ["visible"]=> bool(true)
620 ["type"]=> string(23) "Zend\Navigation\Page\Uri"
621 ["pages"]=> array(0) {
623 ["uri"]=> string(1) "#"
626 ["uri"]=> string(1) "#"