Programmer's Reference Guide

Pages

Containers

Containers have methods for adding, retrieving, deleting and iterating pages. Containers implement the » SPL interfaces RecursiveIterator and Countable, meaning that a container can be iterated using the SPL RecursiveIteratorIterator class.

Creating containers

Zend_Navigation_Container is abstract, and can not be instantiated directly. Use Zend_Navigation if you want to instantiate a container.

Zend_Navigation can be constructed entirely empty, or take an array or a Zend_Config object with pages to put in the container. Each page in the given array/config will eventually be passed to the addPage() method of the container class, which means that each element in the array/config can be an array or a config object, or a Zend_Navigation_Page instance.

Example #1 Creating a container using an array

  1. /*
  2. * Create a container from an array
  3. *
  4. * Each element in the array will be passed to
  5. * Zend_Navigation_Page::factory() when constructing.
  6. */
  7. $container = new Zend_Navigation(array(
  8.     array(
  9.         'label' => 'Page 1',
  10.         'id' => 'home-link',
  11.         'uri' => '/'
  12.     ),
  13.     array(
  14.         'label' => 'Zend',
  15.         'uri' => 'http://www.zend-project.com/',
  16.         'order' => 100
  17.     ),
  18.     array(
  19.         'label' => 'Page 2',
  20.         'controller' => 'page2',
  21.         'pages' => array(
  22.             array(
  23.                 'label' => 'Page 2.1',
  24.                 'action' => 'page2_1',
  25.                 'controller' => 'page2',
  26.                 'class' => 'special-one',
  27.                 'title' => 'This element has a special class',
  28.                 'active' => true
  29.             ),
  30.             array(
  31.                 'label' => 'Page 2.2',
  32.                 'action' => 'page2_2',
  33.                 'controller' => 'page2',
  34.                 'class' => 'special-two',
  35.                 'title' => 'This element has a special class too'
  36.             )
  37.         )
  38.     ),
  39.     array(
  40.         'label' => 'Page 2 with params',
  41.         'action' => 'index',
  42.         'controller' => 'page2',
  43.         // specify a param or two
  44.         'params' => array(
  45.             'format' => 'json',
  46.             'foo' => 'bar'
  47.         )
  48.     ),
  49.     array(
  50.         'label' => 'Page 2 with params and a route',
  51.         'action' => 'index',
  52.         'controller' => 'page2',
  53.         // specify a route name and a param for the route
  54.         'route' => 'nav-route-example',
  55.         'params' => array(
  56.             'format' => 'json'
  57.         )
  58.     ),
  59.     array(
  60.         'label' => 'Page 3',
  61.         'action' => 'index',
  62.         'controller' => 'index',
  63.         'module' => 'mymodule',
  64.         'reset_params' => false
  65.     ),
  66.     array(
  67.         'label' => 'Page 4',
  68.         'uri' => '#',
  69.         'pages' => array(
  70.             array(
  71.                 'label' => 'Page 4.1',
  72.                 'uri' => '/page4',
  73.                 'title' => 'Page 4 using uri',
  74.                 'pages' => array(
  75.                     array(
  76.                         'label' => 'Page 4.1.1',
  77.                         'title' => 'Page 4 using mvc params',
  78.                         'action' => 'index',
  79.                         'controller' => 'page4',
  80.                         // let's say this page is active
  81.                         'active' => '1'
  82.                     )
  83.                 )
  84.             )
  85.         )
  86.     ),
  87.     array(
  88.         'label' => 'Page 0?',
  89.         'uri' => '/setting/the/order/option',
  90.         // setting order to -1 should make it appear first
  91.         'order' => -1
  92.     ),
  93.     array(
  94.         'label' => 'Page 5',
  95.         'uri' => '/',
  96.         // this page should not be visible
  97.         'visible' => false,
  98.         'pages' => array(
  99.             array(
  100.                 'label' => 'Page 5.1',
  101.                 'uri' => '#',
  102.                 'pages' => array(
  103.                     array(
  104.                         'label' => 'Page 5.1.1',
  105.                         'uri' => '#',
  106.                         'pages' => array(
  107.                             array(
  108.                                 'label' => 'Page 5.1.2',
  109.                                 'uri' => '#',
  110.                                 // let's say this page is active
  111.                                 'active' => true
  112.                             )
  113.                         )
  114.                     )
  115.                 )
  116.             )
  117.         )
  118.     ),
  119.     array(
  120.         'label' => 'ACL page 1 (guest)',
  121.         'uri' => '#acl-guest',
  122.         'resource' => 'nav-guest',
  123.         'pages' => array(
  124.             array(
  125.                 'label' => 'ACL page 1.1 (foo)',
  126.                 'uri' => '#acl-foo',
  127.                 'resource' => 'nav-foo'
  128.             ),
  129.             array(
  130.                 'label' => 'ACL page 1.2 (bar)',
  131.                 'uri' => '#acl-bar',
  132.                 'resource' => 'nav-bar'
  133.             ),
  134.             array(
  135.                 'label' => 'ACL page 1.3 (baz)',
  136.                 'uri' => '#acl-baz',
  137.                 'resource' => 'nav-baz'
  138.             ),
  139.             array(
  140.                 'label' => 'ACL page 1.4 (bat)',
  141.                 'uri' => '#acl-bat',
  142.                 'resource' => 'nav-bat'
  143.             )
  144.         )
  145.     ),
  146.     array(
  147.         'label' => 'ACL page 2 (member)',
  148.         'uri' => '#acl-member',
  149.         'resource' => 'nav-member'
  150.     ),
  151.     array(
  152.         'label' => 'ACL page 3 (admin',
  153.         'uri' => '#acl-admin',
  154.         'resource' => 'nav-admin',
  155.         'pages' => array(
  156.             array(
  157.                 'label' => 'ACL page 3.1 (nothing)',
  158.                 'uri' => '#acl-nada'
  159.             )
  160.         )
  161.     ),
  162.     array(
  163.         'label' => 'Zend Framework',
  164.         'route' => 'zf-route'
  165.     )
  166. ));

Example #2 Creating a container using a config object

  1. /* CONTENTS OF /path/to/navigation.xml:
  2. <?xml version="1.0" encoding="UTF-8"?>
  3. <config>
  4.     <nav>
  5.  
  6.         <zend>
  7.             <label>Zend</label>
  8.             <uri>http://www.zend-project.com/</uri>
  9.             <order>100</order>
  10.         </zend>
  11.  
  12.         <page1>
  13.             <label>Page 1</label>
  14.             <uri>page1</uri>
  15.             <pages>
  16.  
  17.                 <page1_1>
  18.                     <label>Page 1.1</label>
  19.                     <uri>page1/page1_1</uri>
  20.                 </page1_1>
  21.  
  22.             </pages>
  23.         </page1>
  24.  
  25.         <page2>
  26.             <label>Page 2</label>
  27.             <uri>page2</uri>
  28.             <pages>
  29.  
  30.                 <page2_1>
  31.                     <label>Page 2.1</label>
  32.                     <uri>page2/page2_1</uri>
  33.                 </page2_1>
  34.  
  35.                 <page2_2>
  36.                     <label>Page 2.2</label>
  37.                     <uri>page2/page2_2</uri>
  38.                     <pages>
  39.  
  40.                         <page2_2_1>
  41.                             <label>Page 2.2.1</label>
  42.                             <uri>page2/page2_2/page2_2_1</uri>
  43.                         </page2_2_1>
  44.  
  45.                         <page2_2_2>
  46.                             <label>Page 2.2.2</label>
  47.                             <uri>page2/page2_2/page2_2_2</uri>
  48.                             <active>1</active>
  49.                         </page2_2_2>
  50.  
  51.                     </pages>
  52.                 </page2_2>
  53.  
  54.                 <page2_3>
  55.                     <label>Page 2.3</label>
  56.                     <uri>page2/page2_3</uri>
  57.                     <pages>
  58.  
  59.                         <page2_3_1>
  60.                             <label>Page 2.3.1</label>
  61.                             <uri>page2/page2_3/page2_3_1</uri>
  62.                         </page2_3_1>
  63.  
  64.                         <page2_3_2>
  65.                             <label>Page 2.3.2</label>
  66.                             <uri>page2/page2_3/page2_3_2</uri>
  67.                             <visible>0</visible>
  68.                             <pages>
  69.  
  70.                                     <page2_3_2_1>
  71.                                         <label>Page 2.3.2.1</label>
  72.                                         <uri>page2/page2_3/page2_3_2/1</uri>
  73.                                         <active>1</active>
  74.                                     </page2_3_2_1>
  75.  
  76.                                     <page2_3_2_2>
  77.                                         <label>Page 2.3.2.2</label>
  78.                                         <uri>page2/page2_3/page2_3_2/2</uri>
  79.                                         <active>1</active>
  80.  
  81.                                         <pages>
  82.                                             <page_2_3_2_2_1>
  83.                                                 <label>Ignore</label>
  84.                                                 <uri>#</uri>
  85.                                                 <active>1</active>
  86.                                             </page_2_3_2_2_1>
  87.                                         </pages>
  88.                                     </page2_3_2_2>
  89.  
  90.                             </pages>
  91.                         </page2_3_2>
  92.  
  93.                         <page2_3_3>
  94.                             <label>Page 2.3.3</label>
  95.                             <uri>page2/page2_3/page2_3_3</uri>
  96.                             <resource>admin</resource>
  97.                             <pages>
  98.  
  99.                                     <page2_3_3_1>
  100.                                         <label>Page 2.3.3.1</label>
  101.                                         <uri>page2/page2_3/page2_3_3/1</uri>
  102.                                         <active>1</active>
  103.                                     </page2_3_3_1>
  104.  
  105.                                     <page2_3_3_2>
  106.                                         <label>Page 2.3.3.2</label>
  107.                                         <uri>page2/page2_3/page2_3_3/2</uri>
  108.                                         <resource>guest</resource>
  109.                                         <active>1</active>
  110.                                     </page2_3_3_2>
  111.  
  112.                             </pages>
  113.                         </page2_3_3>
  114.  
  115.                     </pages>
  116.                 </page2_3>
  117.  
  118.             </pages>
  119.         </page2>
  120.  
  121.         <page3>
  122.             <label>Page 3</label>
  123.             <uri>page3</uri>
  124.             <pages>
  125.  
  126.                 <page3_1>
  127.                     <label>Page 3.1</label>
  128.                     <uri>page3/page3_1</uri>
  129.                     <resource>guest</resource>
  130.                 </page3_1>
  131.  
  132.                 <page3_2>
  133.                     <label>Page 3.2</label>
  134.                     <uri>page3/page3_2</uri>
  135.                     <resource>member</resource>
  136.                     <pages>
  137.  
  138.                         <page3_2_1>
  139.                             <label>Page 3.2.1</label>
  140.                             <uri>page3/page3_2/page3_2_1</uri>
  141.                         </page3_2_1>
  142.  
  143.                         <page3_2_2>
  144.                             <label>Page 3.2.2</label>
  145.                             <uri>page3/page3_2/page3_2_2</uri>
  146.                             <resource>admin</resource>
  147.                         </page3_2_2>
  148.  
  149.                     </pages>
  150.                 </page3_2>
  151.  
  152.                 <page3_3>
  153.                     <label>Page 3.3</label>
  154.                     <uri>page3/page3_3</uri>
  155.                     <resource>special</resource>
  156.                     <pages>
  157.  
  158.                         <page3_3_1>
  159.                             <label>Page 3.3.1</label>
  160.                             <uri>page3/page3_3/page3_3_1</uri>
  161.                             <visible>0</visible>
  162.                         </page3_3_1>
  163.  
  164.                         <page3_3_2>
  165.                             <label>Page 3.3.2</label>
  166.                             <uri>page3/page3_3/page3_3_2</uri>
  167.                             <resource>admin</resource>
  168.                         </page3_3_2>
  169.  
  170.                     </pages>
  171.                 </page3_3>
  172.  
  173.             </pages>
  174.         </page3>
  175.  
  176.         <home>
  177.             <label>Home</label>
  178.             <order>-100</order>
  179.             <module>default</module>
  180.             <controller>index</controller>
  181.             <action>index</action>
  182.         </home>
  183.  
  184.     </nav>
  185. </config>
  186. */
  187.  
  188. $config = new Zend_Config_Xml('/path/to/navigation.xml', 'nav');
  189. $container = new Zend_Navigation($config);

Adding pages

Adding pages to a container can be done with the methods addPage(), addPages(), or setPages(). See examples below for explanation.

Example #3 Adding pages to a container

  1. // create container
  2. $container = new Zend_Navigation();
  3.  
  4. // add page by giving a page instance
  5. $container->addPage(Zend_Navigation_Page::factory(array(
  6.     'uri' => 'http://www.example.com/'
  7. )))
  8.  
  9. // add page by giving an array
  10. $container->addPage(array(
  11.     'uri' => 'http://www.example.com/'
  12. )))
  13.  
  14. // add page by giving a config object
  15. $container->addPage(new Zend_Config(array(
  16.     'uri' => 'http://www.example.com/'
  17. )))
  18.  
  19. $pages = array(
  20.     array(
  21.         'label'  => 'Save'
  22.         'action' => 'save',
  23.     ),
  24.     array(
  25.         'label' =>  'Delete',
  26.         'action' => 'delete'
  27.     )
  28. );
  29.  
  30. // add two pages
  31. $container->addPages($pages);
  32.  
  33. // remove existing pages and add the given pages
  34. $container->setPages($pages);

Removing pages

Removing pages can be done with removePage() or removePages(). The first method accepts a an instance of a page, or an integer. The integer corresponds to the order a page has. The latter method will remove all pages in the container.

Example #4 Removing pages from a container

  1. $container = new Zend_Navigation(array(
  2.     array(
  3.         'label'  => 'Page 1',
  4.         'action' => 'page1'
  5.     ),
  6.     array(
  7.         'label'  => 'Page 2',
  8.         'action' => 'page2',
  9.         'order'  => 200
  10.     ),
  11.     array(
  12.         'label'  => 'Page 3',
  13.         'action' => 'page3'
  14.     )
  15. ));
  16.  
  17. // remove page by implicit page order
  18. $container->removePage(0);      // removes Page 1
  19.  
  20. // remove page by instance
  21. $page3 = $container->findOneByAction('Page 3');
  22. $container->removePage($page3); // removes Page 3
  23.  
  24. // remove page by explicit page order
  25. $container->removePage(200);    // removes Page 2
  26.  
  27. // remove all pages
  28. $container->removePages();      // removes all pages

Finding pages

Containers have finder methods for retrieving pages. They are findOneBy($property, $value), findAllBy($property, $value), and findBy($property, $value, $all = false). Those methods will recursively search the container for pages matching the given $page->$property == $value. The first method, findOneBy(), will return a single page matching the property with the given value, or NULL if it cannot be found. The second method will return all pages with a property matching the given value. The third method will call one of the two former methods depending on the $all flag.

The finder methods can also be used magically by appending the property name to findBy, findOneBy, or findAllBy, e.g. findOneByLabel('Home') to return the first matching page with label 'Home'. Other combinations are findByLabel(...), findOnyByTitle(...), findAllByController(...), etc. Finder methods also work on custom properties, such as findByFoo('bar').

Example #5 Finding pages in a container

  1. $container = new Zend_Navigation(array(
  2.     array(
  3.         'label' => 'Page 1',
  4.         'uri'   => 'page-1',
  5.         'foo'   => 'bar',
  6.         'pages' => array(
  7.             array(
  8.                 'label' => 'Page 1.1',
  9.                 'uri'   => 'page-1.1',
  10.                 'foo'   => 'bar',
  11.             ),
  12.             array(
  13.                 'label' => 'Page 1.2',
  14.                 'uri'   => 'page-1.2',
  15.                 'class' => 'my-class',
  16.             ),
  17.             array(
  18.                 'type'   => 'uri',
  19.                 'label'  => 'Page 1.3',
  20.                 'uri'    => 'page-1.3',
  21.                 'action' => 'about'
  22.             )
  23.         )
  24.     ),
  25.     array(
  26.         'label'      => 'Page 2',
  27.         'id'         => 'page_2_and_3',
  28.         'class'      => 'my-class',
  29.         'module'     => 'page2',
  30.         'controller' => 'index',
  31.         'action'     => 'page1'
  32.     ),
  33.     array(
  34.         'label'      => 'Page 3',
  35.         'id'         => 'page_2_and_3',
  36.         'module'     => 'page3',
  37.         'controller' => 'index'
  38.     )
  39. ));
  40.  
  41. // The 'id' is not required to be unique, but be aware that
  42. // having two pages with the same id will render the same id attribute
  43. // in menus and breadcrumbs.
  44. $found = $container->findBy('id',
  45.                             'page_2_and_3');      // returns Page 2
  46. $found = $container->findOneBy('id',
  47.                                'page_2_and_3');   // returns Page 2
  48. $found = $container->findBy('id',
  49.                             'page_2_and_3',
  50.                             true);                // returns Page 2 and Page 3
  51. $found = $container->findById('page_2_and_3');    // returns Page 2
  52. $found = $container->findOneById('page_2_and_3'); // returns Page 2
  53. $found = $container->findAllById('page_2_and_3'); // returns Page 2 and Page 3
  54.  
  55. // Find all matching CSS class my-class
  56. $found = $container->findAllBy('class',
  57.                                'my-class');       // returns Page 1.2 and Page 2
  58. $found = $container->findAllByClass('my-class')// returns Page 1.2 and Page 2
  59.  
  60. // Find first matching CSS class my-class
  61. $found = $container->findOneByClass('my-class')// returns Page 1.2
  62.  
  63. // Find all matching CSS class non-existant
  64. $found = $container->findAllByClass('non-existant'); // returns array()
  65.  
  66. // Find first matching CSS class non-existant
  67. $found = $container->findOneByClass('non-existant'); // returns null
  68.  
  69. // Find all pages with custom property 'foo' = 'bar'
  70. $found = $container->findAllBy('foo', 'bar'); // returns Page 1 and Page 1.1
  71.  
  72. // To achieve the same magically, 'foo' must be in lowercase.
  73. // This is because 'foo' is a custom property, and thus the
  74. // property name is not normalized to 'Foo'
  75. $found = $container->findAllByfoo('bar');
  76.  
  77. // Find all with controller = 'index'
  78. $found = $container->findAllByController('index'); // returns Page 2 and Page 3

Iterating containers

Zend_Navigation_Container implements RecursiveIteratorIterator, and can be iterated using any Iterator class. To iterate a container recursively, use the RecursiveIteratorIterator class.

Example #6 Iterating a container

  1. /*
  2. * Create a container from an array
  3. */
  4. $container = new Zend_Navigation(array(
  5.     array(
  6.         'label' => 'Page 1',
  7.         'uri'   => '#'
  8.     ),
  9.     array(
  10.         'label' => 'Page 2',
  11.         'uri'   => '#',
  12.         'pages' => array(
  13.             array(
  14.                 'label' => 'Page 2.1',
  15.                 'uri'   => '#'
  16.             ),
  17.             array(
  18.                 'label' => 'Page 2.2',
  19.                 'uri'   => '#'
  20.             )
  21.         )
  22.     ),
  23.     array(
  24.         'label' => 'Page 3',
  25.         'uri'   => '#'
  26.     )
  27. ));
  28.  
  29. // Iterate flat using regular foreach:
  30. // Output: Page 1, Page 2, Page 3
  31. foreach ($container as $page) {
  32.     echo $page->label;
  33. }
  34.  
  35. // Iterate recursively using RecursiveIteratorIterator
  36. $it = new RecursiveIteratorIterator(
  37.         $container, RecursiveIteratorIterator::SELF_FIRST);
  38.  
  39. // Output: Page 1, Page 2, Page 2.1, Page 2.2, Page 3
  40. foreach ($it as $page) {
  41.     echo $page->label;
  42. }

Other operations

The method hasPage(Zend_Navigation_Page $page) checks if the container has the given page. The method hasPages() checks if there are any pages in the container, and is equivalent to count($container) > 1.

The toArray() method converts the container and the pages in it to an array. This can be useful for serializing and debugging.

Example #7 Converting a container to an array

  1. $container = new Zend_Navigation(array(
  2.     array(
  3.         'label' => 'Page 1',
  4.         'uri'   => '#'
  5.     ),
  6.     array(
  7.         'label' => 'Page 2',
  8.         'uri'   => '#',
  9.         'pages' => array(
  10.             array(
  11.                 'label' => 'Page 2.1',
  12.                 'uri'   => '#'
  13.             ),
  14.             array(
  15.                 'label' => 'Page 2.2',
  16.                'uri'   => '#'
  17.             )
  18.         )
  19.     )
  20. ));
  21.  
  22. var_dump($container->toArray());
  23.  
  24. /* Output:
  25. array(2) {
  26.   [0]=> array(15) {
  27.     ["label"]=> string(6) "Page 1"
  28.     ["id"]=> NULL
  29.     ["class"]=> NULL
  30.     ["title"]=> NULL
  31.     ["target"]=> NULL
  32.     ["rel"]=> array(0) {
  33.     }
  34.     ["rev"]=> array(0) {
  35.     }
  36.     ["order"]=> NULL
  37.     ["resource"]=> NULL
  38.     ["privilege"]=> NULL
  39.     ["active"]=> bool(false)
  40.     ["visible"]=> bool(true)
  41.     ["type"]=> string(23) "Zend_Navigation_Page_Uri"
  42.     ["pages"]=> array(0) {
  43.     }
  44.     ["uri"]=> string(1) "#"
  45.   }
  46.   [1]=> array(15) {
  47.     ["label"]=> string(6) "Page 2"
  48.     ["id"]=> NULL
  49.     ["class"]=> NULL
  50.     ["title"]=> NULL
  51.     ["target"]=> NULL
  52.     ["rel"]=> array(0) {
  53.     }
  54.     ["rev"]=> array(0) {
  55.     }
  56.     ["order"]=> NULL
  57.     ["resource"]=> NULL
  58.     ["privilege"]=> NULL
  59.     ["active"]=> bool(false)
  60.     ["visible"]=> bool(true)
  61.     ["type"]=> string(23) "Zend_Navigation_Page_Uri"
  62.     ["pages"]=> array(2) {
  63.       [0]=> array(15) {
  64.         ["label"]=> string(8) "Page 2.1"
  65.         ["id"]=> NULL
  66.         ["class"]=> NULL
  67.         ["title"]=> NULL
  68.         ["target"]=> NULL
  69.         ["rel"]=> array(0) {
  70.         }
  71.         ["rev"]=> array(0) {
  72.         }
  73.         ["order"]=> NULL
  74.         ["resource"]=> NULL
  75.         ["privilege"]=> NULL
  76.         ["active"]=> bool(false)
  77.         ["visible"]=> bool(true)
  78.         ["type"]=> string(23) "Zend_Navigation_Page_Uri"
  79.         ["pages"]=> array(0) {
  80.         }
  81.         ["uri"]=> string(1) "#"
  82.       }
  83.       [1]=>
  84.       array(15) {
  85.         ["label"]=> string(8) "Page 2.2"
  86.         ["id"]=> NULL
  87.         ["class"]=> NULL
  88.         ["title"]=> NULL
  89.         ["target"]=> NULL
  90.         ["rel"]=> array(0) {
  91.         }
  92.         ["rev"]=> array(0) {
  93.         }
  94.         ["order"]=> NULL
  95.         ["resource"]=> NULL
  96.         ["privilege"]=> NULL
  97.         ["active"]=> bool(false)
  98.         ["visible"]=> bool(true)
  99.         ["type"]=> string(23) "Zend_Navigation_Page_Uri"
  100.         ["pages"]=> array(0) {
  101.         }
  102.         ["uri"]=> string(1) "#"
  103.       }
  104.     }
  105.     ["uri"]=> string(1) "#"
  106.   }
  107. }
  108. */

Pages

Comments

---this comment form captcha is bugging me---

I use a database to store my pages (or navigation) to be able to edit (CRUD) my navigation.

Example #1 (above) shows how to create a Container with an array. That's how I want to create my Container, but then dynamically from a database.

At the moment I'm stuck at finding the RIGHT way to do this and the right place to put my code.

My app looks as follows (simplified):
/application/configs/config.ini
/application/controllers/IndexController.php
/application/controllers/ProductsController.php
/application/forms/Products.php
/application/layouts/scripts/layout.phtml
/application/models/ProductsTable.php
/application/models/NavigationTable.php
/application/views/scripts/index/index.phtml
/application/views/scripts/products/index.phtml
/application/Bootstrap.php
/library/Zend/*
/public/css|js|index.php

Now, where should I put the code to read the Navigation databasetable and to create the array for Zend_Navigation_Container? (I get it, in my model, but I mean where do I call the model to do its job?)

>In the bootstrapper?
* Pro: Since a navigation menu is sitewide, I'm not going to add a line of code into every controller and action.
* Contra: The bootstrapper should not be responsible for retrieving database entries and passing them on to a view.
>In my layout.phtml?
* Pro: Its the place where the menu needs to be rendered.
* Contra: A View talking to a Model does not follow MVC standards.

Any other good places? Thanks in advance!
---then login---
---and post questions in the forum---
http://forums.zend.com/
The Example #6 Iterating a container example seems to be missing a comma sign on line 22:
*** 21,23 ****
)
! )
array(
--- 21,23 ----
)
! ),
array(
How come these examples are not very good at explaining how to implement them?
@barleone:
In case you still haven't figured out where to put the code that will help render your navigation menu,

"the code should be implemented via a view helper or action helper". I personally I use App_View_Helper_MenuModule (where "App" should be your aps namespace).

The structure for my App_View_Helper_MenuModule looks as follows:

_createPage(stdClass $link):array or (Zend_Navigation_Page_(Uri|Mvc))
_getLinkPages(stdClass $link):mixed
_getNavigationObject():Zend_Navigation
_injectAcl(Zend_Navigation $nav):Zend_Navigation
menuModule(array $options, Zend_View_Abstract $view = null)

and the call chain from within looks as follows:
get the navigation object ($nav = $this->_getNavigationObject())
get result set (using a model or service within _getNavigationObject())
loop through result set
_createPage(tuple from result set ($link))
_getLinkPages($link) (should be name getPagesForLink instead)

then return the rendered nav (from the main menuModule function of the view helper).

and here is where I create a page

    private function _createPage( stdClass $link) {
        $page = array(
            'label' => $link->label,
            'uri' => $link->uri
            //'id' => $link->id,
            //'class' => $link->class,
            //'title' => $link->title
            //'target' => $link->target,
            //'rel' => $link->rel
        );

        $children = $this->_getLinkPages($link);
        if ($children !== false) {
            $page['pages'] = $children;
        }

        return $page;
    }


Happy Phping!
Woops! Forgot to enforce the indent on the sudo code in my last comment. Here is the entire MenuModule View Helper I talked about there:


<?php
/**
 * Description of MenuModule
 *
 * @author ElyDeLaCruz
 */
class Edm_View_Helper_MenuModule extends
Edm_View_Helper_Abstract
{
    private 
$_linkServ;
    
    public function 
menuModule(array $options null,
            
Zend_View_Abstract $view null)
    {
        
$this->_linkServ = new Edm_Service_LinkService();

        
// Check if we need process options
        
if (!empty($options)) {

            
// Check if we already have valid key names
            
$validKeyNames $this->getValidKeyNames();

            
// If we don't set them.
            
if (empty($validKeyNames)) {
                
$this->setValidKeyNames(array('tuple''wrapInDivs''showTitle',
                    
'showHeader''showBody''showFooter''wrapContent',
                    
'attributes''injectAcl'));
            }

            
// Validate the option key names
            
$this->validateKeyNames($options);

            
// Set the options so that they are accessible via $this->
            
$this->setOptions($options);

            
// Set the tuple columns to options for this view helper
            // must cast it as an array since the tuples will be passed
            // stdClass objects
            
$this->setOptions((array)$this->tuple);
        }

        
// Check whether we have to set the view
        
if (!empty($view)) {
            
$this->setView($view);
        }

        
// Get a zend navigation object with all its pages (links) added to it.
        
$nav $this->_getNavigationObject();

        
$this->menuHelperName = empty($this->menuHelperName) ? 'EdmMenu' :
                    
$this->menuHelperName;

        
$this->content $this->view->navigation()
                ->
findHelper($this->menuHelperName)
                ->
setOnlyActiveBranch((bool)$this->onlyActiveBranch)
                ->
setMinDepth($this->minDepth)
                ->
setMaxDepth($this->maxDepth)
                ->
setUlClass($this->ulClass)
                ->
renderMenu($nav);

        
// Options for the plain html module
        
$plainHtmlModule_options = array('title' => $this->title,
            
'content' => $this->content'css_class' => $this->css_class,
            
'html_id' => $this->html_id'showTitle' => $this->showTitle,
            
'showFooter' => $this->showFooter,
            
'wrapContent' => $this->wrapContent);

        
// Return output wrapped in a plain html module html wrapper
        
return $this->wrapInDivs ?
                
$this->view->plainHtmlModule($plainHtmlModule_options) :
                
$this->content;

        
// minDepth
        // maxDepth
        // ulClass
        // onlyActiveBranch
        // renderParents
        // partial script
        // menuHelperName
        // module_id
        // menu_id
    
}

    
/**
     * Returns a Zend_Navigation object with its pages already populated
     * with links that have a menu_id of $menu_id
     * @param uint $menu_id
     * @return Zend_Navigation 
     */
    
private function _getNavigationObject()
    {        
        
// Get all top level links of this menu that are published
        
$rslt $this->_linkServ->read('t1.menu_id="'$this->menu_id .
                
'" AND t2.status="published" AND t1.parentId="0"');

        if (!empty(
$this->inheritFrom_menu_id)) {
            
// If inherits from another menu then get the links from that menu
            
$inherited =  $this->_linkServ->read('t1.menu_id="'.
                    
$this->inheritFrom_menu_id .
                    
'" AND t2.status="published" AND t1.parentId="0"');

            
$rslt array_merge($inherited$rslt);
        }

        
// Loop through top level link results and create a config array for our
        // Zend Navigation object.
        
$pages = array();
        foreach(
$rslt as $link) {
            
$link = (object) $link;
            
$pages[] = $this->_createPage($link);
        }
        
$nav = new Zend_Navigation($pages);
        if (
$this->injectAcl === true) {
            
$nav $this->_injectAcl($nav);
        }

        return 
$nav;
    }

    private function 
_getLinkPages(stdClass  $link) {

        
// Get all top level links of this menu that are published
        
$rslt $this->_linkServ->read('t1.menu_id="'$link->menu_id .
                
'" AND t2.status="published" AND t1.parentId="'.
                
$link->link_id .'"');

        
// Loop through results
        
$pages = array(); $i 0;
        foreach(
$rslt as $child) {
            
            
// Cast child tuple as object
            
$child = (object) $child;
            
            
// add Child to pages array
            
$pages[] = $this->_createPage($child);
        }

        return (
count($pages) > $pages false);
    }

    
/**
     * Puts the pertinent link information needed to create a Zend_Nav..._Page
     * within an array.
     * @param object $link
     * @return array
     */
    
private function _createPagestdClass $link) {
        
$page = array(
            
'label' => $link->label,
            
'uri' => $link->uri
            
//'id' => $link->id,
            //'class' => $link->class,
            //'title' => $link->title
            //'target' => $link->target,
            //'rel' => $link->rel
        
);

        
$children $this->_getLinkPages($link);
        if (
$children !== false) {
            
$page['pages'] = $children;
        }

        return 
$page;
    }

    
/**
     * Injects the front acl into the Zend_Navigation object passed in
     * @param Zend_Navigation $nav
     * @return Zend_Navigation
     */
    
private function _injectAclZend_Navigation $nav) {
        
// Pass acl to navigation
        
$acl_config = new Zend_Config_Ini(
                    
APPLICATION_PATH .'/configs/acl.ini',
                    
APPLICATION_ENV);
        
$acl = new Edm_Acl($acl_config);
        
$auth Zend_Auth::getInstance();
        
$role $auth->hasIdentity() ?
                (string)(
$auth->getIdentity()->role) : 'guest';
        
$this->view->navigation($nav)->setAcl($acl)->setRole($role);
        return 
$nav;
        
    }

}
About last comment and view helper example:

The setOnlyActiveBranch((bool)$var) doesn't work for me. If you leave the line out the class works fine. Kudos.
Very nice example Ely De La Cruz,
tried to make it work, but then realise that i am missing one part :)
$this->_linkServ = new Edm_Service_LinkService();
Any chance to see whats in there? :)
Thanks anyway!
Dovla
FYI,
"Example #2 Creating a container using a config object" is not correct. You do not need the nav node.
In regards to the guy who asked: 'How come these examples are not very good at explaining how to implement them?'

I'm also asking the same question and I think now after reading so many documents in the documentation that they're receiving income from pushing people through consultancy and support packages. The documentation appears as vague as possible and to make it much more likely that you can't do anything.

For example: the Zend_Form tutorial tells you to create your forms like ->addElement() and then the Zend_Form_Decorator examples are showing you how to implement them by using $element->addDecorator rather than 'decorators' => which fits directly into the first example.

Also, stuff like Zend_Form is extremely picky about using the correct case and it doesn't actually make logical sense so you have to spend a few hours, days searching the internet looking for a solution.

As the guy before me says 'where do I put this?'. Well it's a framework and frameworks are there to follow a standard way of doing things. I haven't seen one page yet that explains how to actually implement anything and how to follow the general rules it lays out.

I've survived thus far through asking absolutely every question through stackoverflow and even then they're pointing you to articles that are only relevant to a particular setup, installation, version and use terms that haven't been explained or detailed.

We've all been funneled through to the Zend Framework through celebrity endorsement. "Oh this is by the ACTUAL creators of PHP..." why would you use anything else? If they were behind CakePHP or any other framework for instance then we'd all be attempting to use that as well. Totally regretting even attempting to port my application over to Zend!

It's surprising really as the PHP manual has one of the best documentations available but that's to get you through the door then they can start charging you at Zend Framework...
Ignore EVERYTHING up there. It's CRAP. This is what you're after:

Copy and paste this (1.11)

/application/configs/navigation.xml
--------------------------------------------------

<?xml version="1.0" encoding="UTF-8"?>
<configdata>
<nav>

<home>
<label>Home</label>
<controller>index</controller>
<action>index</action>
</home>

<user>
<label>Users</label>
<controller>user</controller>
<action>index</action>

<pages>
<login>
<label>Login</label>
<controller>index</controller>
<action>index</action>
</login>
<register>
<label>Register</label>
<controller>register</controller>
<action>index</action>
</register>
</pages>
</user>

</nav>
</configdata>


/application/Bootstrap.php
-------------------------------------------------

<?php

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{

protected function _initNavigation()
{

$this->bootstrap("layout");
$layout = $this->getResource('layout');
$view = $layout->getView();

$config = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.xml','nav');
$navigation = new Zend_Navigation($config);

$view->navigation($navigation);

}

}


application/layouts/scripts/layout.phtml
---------------------------------------------------------

<!DOCTYPE html>
<html>
<head>
<?php echo $this->headTitle() ?>
<?php echo $this->headMeta() ?>
<?php echo $this->headScript() ?>
<?php echo $this->headStyle() ?>
</head>
<body>
<?php echo $this->navigation()->menu()->setMaxDepth(1); ?>
<?php echo $this->layout()->content; ?>
</body>
</html>



Bing, bang, boom. This is ALL anyone wanted to come here for.
Is there any way to attach html tag parameters to "li" elements of rendered navigation menu? All html paramters of "Pages" instances are added to anchor tag.
Extend the default menu helper so that you can inject your ”li” options through there (I did this a while ago to do ”<li class=”active”>” on the condition that the current link was the active one).

+ Add A Comment

Please do not report issues via comments; use the ZF Issue Tracker.

If you have a JIRA/Crowd account, we suggest you login first before commenting.

  • BBCode is allowed in the comment markup

  • Select a Version

    Languages Available

    Components

    Search the Manual