This document is a start to get a new navigation component of the ground. The current Zend\Navigation
has shown to be a powerful component for navigation purposes. On the other hand, the code is since it's introduction in Zend Framework 1.8 not really updated. The complexity is for some features very difficult to comprehend. In ZF2, the overhaul of the view helpers made it even more difficult to customize the behaviour of Zend\Navigation
.
The good parts:
- A structure of containers and pages to create hierarchal trees
- A set of domain layer-like objects (containers and pages) and view helpers to render them into html
- The option to mark pages as "active"
- The option to tune visibility of pages
- The option to attach an ACL object to the navigation list to show or hide parts based on access permission
The bad parts:
- The complexity to set pages active, especially with:
- MVC pages and the use of route matches;
- When a page is not active, the check if a page is active is performed every time the method
$page->isActive()
is called.
- The simplicity of visibility of pages, especially when the visibility flag should be context aware. Ie, on the menu the page is not visible, but in the breadcrumbs it is.
- The view helper plugin manager, hidden inside a view helper
- The extensibility of view helpers is because of #3 very hard to accomplish
The new navigation component will probably live inside a module, maintained by a couple of core zf2 developers. An example might be the ZF-Commons group (having a ZfcNavigation) but it is not the intend of this proposal to become part of Zfc, but rather provide an alternative navigation implementation. The goal is to develop something alike Zend\Navigation
but without all the reasons why you wouldn't use Zend\Navigation
.
It is a wish to keep as close as possible to Zend\Navigation
, because of the simpler learning curve and migration. However, backwards compatibility will probably not be maintained.
A Navigation
object is a class representing a set of navigation collection. A Collection
is a set of pages. A Page
is a node inside the tree.
- The
Navigation
can hold multiple collections. An example is the main menu of a website and somewhere in the footer a second navigations structure for pages below the fold. It is recommended to keep the navigation object a shared instance among all consumers of navigation, but this isn't necessarily required. - The
Collection
is an abstract class representing an object able to store some other collections in a specific order. - The
Page
is the lowest type in this hierarchy. The page extends a collection and is therefore able to contain several other sub pages. A page also contain information like it has now: a uri, a label (or title), visibility flag etc.
There might be a multitude of page types, of which the uri and mvc page types like they are now the most obvious choices are.
A sample is a container is stored inside navigation with a key/value based system:
$navigation = new Navigation;
$container = new Container;
$navigation->setContainer('default', $container);
$container = new Container;
$navigation->setContainer('secondary', $container);
The same will be for the navigation view helper:
$this->navigationMenu('secondary')->render();
The Navigation
is aware in which collection which page is active. A code sample might be:
$page = $navigation->findByRoute('some/route');
$navigation->setActive($page);
The navigation holds a reference to the page. This makes one of the most common tasks of the navigation (finding the active page) extremely simple. The behaviour can be tuned such that parent pages are automatically set to active too:
$page = $navigation->findByRoute('some/route');
$navigation->setActive($page);
$parent = $page->getParent();
$navigation->isActive($parent); // true
// or
$parent->isActive(); // true
The navigation view helpers should be designed like the Zend\Form
view helpers. They live in a separate namespace (like Zend\Form\View\Helper
) and are constructed with prefixed components names (like formElement
, formElementLabel
). A plugin manager will hold a default set of view helpers. The current set is a good list of what is initially required:
- Menu
- Breadcrumbs
- Sitemap
Now ACL is accompanied with a RBAC proposal, the navigation module must be flexible to support any type of permission setting. This is involved in three layers:
- The navigation class must have a collection which is accessible
- The page in the navigation must be accessible
- The view helper must hold a reference to a ACL or RBAC system
For the first one, the use case is an admin menu must be completely hidden from the anonymous visitor. The second one is similar to what Zend\Navigation
now already supports.
-- tbd --
Visibility is something that you have neglected to mention, The ability to hide certain pages from a view renderer.