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.
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.
例 37.10. Creating a container using an array
/* * Create a container from an array * * Each element in the array will be passed to * Zend_Navigation_Page::factory() when constructing. */ $container = new Zend_Navigation(array( array( 'label' => 'Page 1', 'id' => 'home-link' ), array( 'label' => 'Zend', 'uri' => 'http://www.zend-project.com/', 'order' => 100 ), array( 'label' => 'Page 2', 'controller' => 'page2', 'pages' => array( array( 'label' => 'Page 2.1', 'action' => 'page2_1', 'controller' => 'page2', 'class' => 'special-one', 'title' => 'This element has a special class', 'active' => true ), array( 'label' => 'Page 2.2', 'action' => 'page2_2', 'controller' => 'page2', 'class' => 'special-two', 'title' => 'This element has a special class too' ) ) ), array( 'label' => 'Page 2 with params', 'action' => 'index', 'controller' => 'page2', // specify a param or two 'params' => array( 'format' => 'json', 'foo' => 'bar' ) ), array( 'label' => 'Page 2 with params and a route', 'action' => 'index', 'controller' => 'page2', // specify a route name and a param for the route 'route' => 'nav-route-example', 'params' => array( 'format' => 'json' ) ), array( 'label' => 'Page 3', 'action' => 'index', 'controller' => 'index', 'module' => 'mymodule', 'reset_params' => false ), array( 'label' => 'Page 4', 'uri' => '#', 'pages' => array( array( 'label' => 'Page 4.1', 'uri' => '/page4', 'title' => 'Page 4 using uri', 'pages' => array( array( 'label' => 'Page 4.1.1', 'title' => 'Page 4 using mvc params', 'action' => 'index', 'controller' => 'page4', // let's say this page is active 'active' => '1' ) ) ) ) ), array( 'label' => 'Page 0?', 'uri' => '/setting/the/order/option', // setting order to -1 should make it appear first 'order' => -1 ), array( 'label' => 'Page 5', 'uri' => '/', // this page should not be visible 'visible' => false, 'pages' => array( array( 'label' => 'Page 5.1', 'uri' => '#', 'pages' => array( array( 'label' => 'Page 5.1.1', 'uri' => '#', 'pages' => array( array( 'label' => 'Page 5.1.2', 'uri' => '#', // let's say this page is active 'active' => true ) ) ) ) ) ) ), array( 'label' => 'ACL page 1 (guest)', 'uri' => '#acl-guest', 'resource' => 'nav-guest', 'pages' => array( array( 'label' => 'ACL page 1.1 (foo)', 'uri' => '#acl-foo', 'resource' => 'nav-foo' ), array( 'label' => 'ACL page 1.2 (bar)', 'uri' => '#acl-bar', 'resource' => 'nav-bar' ), array( 'label' => 'ACL page 1.3 (baz)', 'uri' => '#acl-baz', 'resource' => 'nav-baz' ), array( 'label' => 'ACL page 1.4 (bat)', 'uri' => '#acl-bat', 'resource' => 'nav-bat' ) ) ), array( 'label' => 'ACL page 2 (member)', 'uri' => '#acl-member', 'resource' => 'nav-member' ), array( 'label' => 'ACL page 3 (admin', 'uri' => '#acl-admin', 'resource' => 'nav-admin', 'pages' => array( array( 'label' => 'ACL page 3.1 (nothing)', 'uri' => '#acl-nada' ) ) ), array( 'label' => 'Zend Framework', 'route' => 'zf-route' ) ));
例 37.11. Creating a container using a config object
/* CONTENTS OF /path/to/navigation.xml: <?xml version="1.0" encoding="UTF-8"?> <config> <nav> <zend> <label>Zend</label> <uri>http://www.zend-project.com/</uri> <order>100</order> </zend> <page1> <label>Page 1</label> <uri>page1</uri> <pages> <page1_1> <label>Page 1.1</label> <uri>page1/page1_1</uri> </page1_1> </pages> </page1> <page2> <label>Page 2</label> <uri>page2</uri> <pages> <page2_1> <label>Page 2.1</label> <uri>page2/page2_1</uri> </page2_1> <page2_2> <label>Page 2.2</label> <uri>page2/page2_2</uri> <pages> <page2_2_1> <label>Page 2.2.1</label> <uri>page2/page2_2/page2_2_1</uri> </page2_2_1> <page2_2_2> <label>Page 2.2.2</label> <uri>page2/page2_2/page2_2_2</uri> <active>1</active> </page2_2_2> </pages> </page2_2> <page2_3> <label>Page 2.3</label> <uri>page2/page2_3</uri> <pages> <page2_3_1> <label>Page 2.3.1</label> <uri>page2/page2_3/page2_3_1</uri> </page2_3_1> <page2_3_2> <label>Page 2.3.2</label> <uri>page2/page2_3/page2_3_2</uri> <visible>0</visible> <pages> <page2_3_2_1> <label>Page 2.3.2.1</label> <uri>page2/page2_3/page2_3_2/1</uri> <active>1</active> </page2_3_2_1> <page2_3_2_2> <label>Page 2.3.2.2</label> <uri>page2/page2_3/page2_3_2/2</uri> <active>1</active> <pages> <page_2_3_2_2_1> <label>Ignore</label> <uri>#</uri> <active>1</active> </page_2_3_2_2_1> </pages> </page2_3_2_2> </pages> </page2_3_2> <page2_3_3> <label>Page 2.3.3</label> <uri>page2/page2_3/page2_3_3</uri> <resource>admin</resource> <pages> <page2_3_3_1> <label>Page 2.3.3.1</label> <uri>page2/page2_3/page2_3_3/1</uri> <active>1</active> </page2_3_3_1> <page2_3_3_2> <label>Page 2.3.3.2</label> <uri>page2/page2_3/page2_3_3/2</uri> <resource>guest</resource> <active>1</active> </page2_3_3_2> </pages> </page2_3_3> </pages> </page2_3> </pages> </page2> <page3> <label>Page 3</label> <uri>page3</uri> <pages> <page3_1> <label>Page 3.1</label> <uri>page3/page3_1</uri> <resource>guest</resource> </page3_1> <page3_2> <label>Page 3.2</label> <uri>page3/page3_2</uri> <resource>member</resource> <pages> <page3_2_1> <label>Page 3.2.1</label> <uri>page3/page3_2/page3_2_1</uri> </page3_2_1> <page3_2_2> <label>Page 3.2.2</label> <uri>page3/page3_2/page3_2_2</uri> <resource>admin</resource> </page3_2_2> </pages> </page3_2> <page3_3> <label>Page 3.3</label> <uri>page3/page3_3</uri> <resource>special</resource> <pages> <page3_3_1> <label>Page 3.3.1</label> <uri>page3/page3_3/page3_3_1</uri> <visible>0</visible> </page3_3_1> <page3_3_2> <label>Page 3.3.2</label> <uri>page3/page3_3/page3_3_2</uri> <resource>admin</resource> </page3_3_2> </pages> </page3_3> </pages> </page3> <home> <label>Home</label> <order>-100</order> </home> </nav> </config> */ $config = new Zend_Config_Xml('/path/to/navigation.xml', 'nav'); $container = new Zend_Navigation($config);
Adding pages to a container can be done with the methods
addPage()
, addPages()
, or
setPages()
. See examples below for explanation.
例 37.12. Adding pages to a container
// create container $container = new Zend_Navigation(); // add page by giving a page instance $container->addPage(Zend_Navigation_Page::factory(array( 'uri' => 'http://www.example.com/' ))) // add page by giving an array $container->addPage(array( 'uri' => 'http://www.example.com/' ))) // add page by giving a config object $container->addPage(new Zend_Config(array( 'uri' => 'http://www.example.com/' ))) $pages = array( array( 'label' => 'Save' 'action' => 'save', ), array( 'label' => 'Delete', 'action' => 'delete' ) ); // add two pages $container->addPages($pages); // remove existing pages and add the given pages $container->setPages($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.
例 37.13. Removing pages from a container
$container = new Zend_Navigation(array( array( 'label' => 'Page 1', 'action' => 'page1' ), array( 'label' => 'Page 2', 'action' => 'page2', 'order' => 200 ), array( 'label' => 'Page 3', 'action' => 'page3' ) )); // remove page by implicit page order $container->removePage(0); // removes Page 1 // remove page by instance $page3 = $container->findOneByAction('Page 3'); $container->removePage($page3); // removes Page 3 // remove page by explicit page order $container->removePage(200); // removes Page 2 // remove all pages $container->removePages(); // removes all 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')
.
例 37.14. Finding pages in a container
$container = new Zend_Navigation(array( array( 'label' => 'Page 1', 'uri' => 'page-1', 'foo' => 'bar', 'pages' => array( array( 'label' => 'Page 1.1', 'uri' => 'page-1.1', 'foo' => 'bar', ), array( 'label' => 'Page 1.2', 'uri' => 'page-1.2', 'class' => 'my-class', ), array( 'type' => 'uri', 'label' => 'Page 1.3', 'uri' => 'page-1.3', 'action' => 'about' ) ) ), array( 'label' => 'Page 2', 'id' => 'page_2_and_3', 'class' => 'my-class', 'module' => 'page2', 'controller' => 'index', 'action' => 'page1' ), array( 'label' => 'Page 3', 'id' => 'page_2_and_3', 'module' => 'page3', 'controller' => 'index' ) )); // The 'id' is not required to be unique, but be aware that // having two pages with the same id will render the same id attribute // in menus and breadcrumbs. $found = $container->findBy('id', 'page_2_and_3'); // returns Page 2 $found = $container->findOneBy('id', 'page_2_and_3'); // returns Page 2 $found = $container->findBy('id', 'page_2_and_3', true); // returns Page 2 and Page 3 $found = $container->findById('page_2_and_3'); // returns Page 2 $found = $container->findOneById('page_2_and_3'); // returns Page 2 $found = $container->findAllById('page_2_and_3'); // returns Page 2 and Page 3 // Find all matching CSS class my-class $found = $container->findAllBy('class', 'my-class'); // returns Page 1.2 and Page 2 $found = $container->findAllByClass('my-class'); // returns Page 1.2 and Page 2 // Find first matching CSS class my-class $found = $container->findOneByClass('my-class'); // returns Page 1.2 // Find all matching CSS class non-existant $found = $container->findAllByClass('non-existant'); // returns array() // Find first matching CSS class non-existant $found = $container->findOneByClass('non-existant'); // returns null // Find all pages with custom property 'foo' = 'bar' $found = $container->findAllBy('foo', 'bar'); // returns Page 1 and Page 1.1 // To achieve the same magically, 'foo' must be in lowercase. // This is because 'foo' is a custom property, and thus the // property name is not normalized to 'Foo' $found = $container->findAllByfoo('bar'); // Find all with controller = 'index' $found = $container->findAllByController('index'); // returns Page 2 and Page 3
Zend_Navigation_Container
implements
RecursiveIteratorIterator
, and can be
iterated using any Iterator
class. To iterate
a container recursively, use the
RecursiveIteratorIterator
class.
例 37.15. Iterating a container
/* * Create a container from an array */ $container = new Zend_Navigation(array( array( 'label' => 'Page 1', 'uri' => '#' ), array( 'label' => 'Page 2', 'uri' => '#', 'pages' => array( array( 'label' => 'Page 2.1', 'uri' => '#' ), array( 'label' => 'Page 2.2', 'uri' => '#' ) ) ) array( 'label' => 'Page 3', 'uri' => '#' ) )); // Iterate flat using regular foreach: // Output: Page 1, Page 2, Page 3 foreach ($container as $page) { echo $page->label; } // Iterate recursively using RecursiveIteratorIterator $it = new RecursiveIteratorIterator( $container, RecursiveIteratorIterator::SELF_FIRST); // Output: Page 1, Page 2, Page 2.1, Page 2.2, Page 3 foreach ($it as $page) { echo $page->label; }
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.
例 37.16. Converting a container to an array
$container = new Zend_Navigation(array( array( 'label' => 'Page 1', 'uri' => '#' ), array( 'label' => 'Page 2', 'uri' => '#', 'pages' => array( array( 'label' => 'Page 2.1', 'uri' => '#' ), array( 'label' => 'Page 2.2', 'uri' => '#' ) ) ) )); var_dump($container->toArray()); /* Output: array(2) { [0]=> array(15) { ["label"]=> string(6) "Page 1" ["id"]=> NULL ["class"]=> NULL ["title"]=> NULL ["target"]=> NULL ["rel"]=> array(0) { } ["rev"]=> array(0) { } ["order"]=> NULL ["resource"]=> NULL ["privilege"]=> NULL ["active"]=> bool(false) ["visible"]=> bool(true) ["type"]=> string(23) "Zend_Navigation_Page_Uri" ["pages"]=> array(0) { } ["uri"]=> string(1) "#" } [1]=> array(15) { ["label"]=> string(6) "Page 2" ["id"]=> NULL ["class"]=> NULL ["title"]=> NULL ["target"]=> NULL ["rel"]=> array(0) { } ["rev"]=> array(0) { } ["order"]=> NULL ["resource"]=> NULL ["privilege"]=> NULL ["active"]=> bool(false) ["visible"]=> bool(true) ["type"]=> string(23) "Zend_Navigation_Page_Uri" ["pages"]=> array(2) { [0]=> array(15) { ["label"]=> string(8) "Page 2.1" ["id"]=> NULL ["class"]=> NULL ["title"]=> NULL ["target"]=> NULL ["rel"]=> array(0) { } ["rev"]=> array(0) { } ["order"]=> NULL ["resource"]=> NULL ["privilege"]=> NULL ["active"]=> bool(false) ["visible"]=> bool(true) ["type"]=> string(23) "Zend_Navigation_Page_Uri" ["pages"]=> array(0) { } ["uri"]=> string(1) "#" } [1]=> array(15) { ["label"]=> string(8) "Page 2.2" ["id"]=> NULL ["class"]=> NULL ["title"]=> NULL ["target"]=> NULL ["rel"]=> array(0) { } ["rev"]=> array(0) { } ["order"]=> NULL ["resource"]=> NULL ["privilege"]=> NULL ["active"]=> bool(false) ["visible"]=> bool(true) ["type"]=> string(23) "Zend_Navigation_Page_Uri" ["pages"]=> array(0) { } ["uri"]=> string(1) "#" } } ["uri"]=> string(1) "#" } } */