Zend Framework 2 : Dynamic Navigation using Zend\Navigation
Zend Framework 2 provide Navigation component to generate menu. It can utilize by creating static config in autoload/*.global.php. Sometime, we need dynamic menu to be generated in our application. I will give you a simple example to do that.
For example, i want structure menu like this :

So, we should do step by step like the following :
1. Create a menu Table (I’m using postgresql, you can specify yourself for your database )
CREATE TABLE menu ( id bigserial NOT NULL, name character varying(255), label character varying(255), route character varying(255), CONSTRAINT pk_menu PRIMARY KEY (id ) ) WITH ( OIDS=FALSE ); ALTER TABLE menu OWNER TO postgres;
2. Insert the data like the following :

3. create a Model :
namespace ZendSkeletonModule\Model;
use Zend\Db\Adapter\Adapter;
use Zend\Db\ResultSet\HydratingResultSet;
use Zend\Db\TableGateway\AbstractTableGateway;
use Zend\Db\Sql\Select;
use Zend\Db\Adapter\AdapterAwareInterface;
class MenuTable extends AbstractTableGateway
implements AdapterAwareInterface
{
protected $table = 'menu';
public function setDbAdapter(Adapter $adapter)
{
$this->adapter = $adapter;
$this->resultSetPrototype = new HydratingResultSet();
$this->initialize();
}
public function fetchAll()
{
$resultSet = $this->select(function (Select $select){
$select->order(array('id asc'));
});
$resultSet = $resultSet->toArray();
return $resultSet;
}
}
4. Extends Zend\Navigation\Service\DefaultNavigationFactory and override getPages() function.
namespace ZendSkeletonModule\Navigation;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Navigation\Service\DefaultNavigationFactory;
class MyNavigation extends DefaultNavigationFactory
{
protected function getPages(ServiceLocatorInterface $serviceLocator)
{
if (null === $this->pages) {
//FETCH data from table menu :
$fetchMenu = $serviceLocator->get('menu')->fetchAll();
$configuration['navigation'][$this->getName()] = array();
foreach($fetchMenu as $key=>$row)
{
$configuration['navigation'][$this->getName()][$row['name']] = array(
'label' => $row['label'],
'route' => $row['route'],
);
}
if (!isset($configuration['navigation'])) {
throw new Exception\InvalidArgumentException('Could not find navigation configuration key');
}
if (!isset($configuration['navigation'][$this->getName()])) {
throw new Exception\InvalidArgumentException(sprintf(
'Failed to find a navigation container by the name "%s"',
$this->getName()
));
}
$application = $serviceLocator->get('Application');
$routeMatch = $application->getMvcEvent()->getRouteMatch();
$router = $application->getMvcEvent()->getRouter();
$pages = $this->getPagesFromConfig($configuration['navigation'][$this->getName()]);
$this->pages = $this->injectComponents($pages, $routeMatch, $router);
}
return $this->pages;
}
}
5. Create Your Navigation Factory
namespace ZendSkeletonModule\Navigation;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class MyNavigationFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$navigation = new MyNavigation();
return $navigation->createService($serviceLocator);
}
}
6. Register MenuTable model, and your Navigation in ServiceManager :
class Module
{
public function getServiceConfig()
{
return array(
'initializers' => array(
function ($instance, $sm) {
if ($instance instanceof \Zend\Db\Adapter\AdapterAwareInterface) {
$instance->setDbAdapter($sm->get('Zend\Db\Adapter\Adapter'));
}
}
),
'invokables' => array(
'menu' => 'ZendSkeletonModule\Model\MenuTable'
),
'factories' => array(
'Navigation' => 'ZendSkeletonModule\Navigation\MyNavigationFactory'
)
);
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
}
6. Configuration done, let’s call from layout:
<div class="nav-collapse">
<?php echo $this->navigation('Navigation')->menu()->setUlClass('nav'); ?>
</div>
Done !
45 Responses
Subscribe to comments with RSS.
Excelente, Very good
Tank you very much, I appreciate.
You’re welcome
[...] http://samsonasik.wordpress.com/2012/11/18/zend-framework-2-dynamic-navigation-using-zend-navigation… [...]
Really good examples, would be great to get examples on GitHub as well
You can follow my github account : https://github.com/samsonasik
You might take a look at ensemble as well (http://ensemble.github.com). The kernel (https://github.com/ensemble/EnsembleKernel) does exactly this, together with two more options:
1. Navigation can be a tree and not only a flat structure
2. Like the tree structure of the navigation component, routes can be hierarchical as well
The kernel implements an adapter pattern where currently only a doctrine one exists, but it’s easy to make one for Zend\Db as well.
great!, my post is just a sample to who are need simple implementation of dynamic navigation.
I apologize if too bold but may I suggest another blog post: Multi step form
thanks for the suggestion.
[...] Zend Framework 2 : Dynamic Navigation using ZendNavigation Автор: Abdul Malik Ikhsan Перевод: Лобач [...]
it would have been great if you explained the code ..
not in details but few lines below each block explaining what is was doing.
Must have really helped the beginners. Anyways nice post indeed ..
HJ samsonasik!
has error how to fix?
Fatal error: Uncaught exception ‘Zend\Db\TableGateway\Exception\RuntimeException’ with message ‘This table does not have an Adapter setup’ in E:\webproject\ZendFramework2\library\Zend\Db\TableGateway\AbstractTableGateway.php:104 Stack trace: #0 E:\webproject\ZendFramework2\library\Zend\Db\TableGateway\AbstractTableGateway.php(187): Zend\Db\TableGateway\AbstractTableGateway->initialize() #1 E:\webproject\htdocs\zf2shopcms\backend\Admin\src\Admin\Model\MenuTable.php(27): Zend\Db\TableGateway\AbstractTableGateway->select(Object(Closure)) #2 E:\webproject\htdocs\zf2shopcms\backend\Admin\src\Admin\Navigation\MyNavigation.php(13): Admin\Model\MenuTable->fetchAll() #3 E:\webproject\ZendFramework2\library\Zend\Navigation\Service\AbstractNavigationFactory.php(40): Admin\Navigation\MyNavigation->getPages(Object(Zend\ServiceManager\ServiceManager)) #4 E:\webproject\htdocs\zf2shopcms\backend\Admin\src\Admin\Navigation\MyNavigationFactory.php(12): Zend\Navigation\Service\AbstractNavigationFactory->createService(Object(Zend\ServiceMana in E:\webproject\ZendFramework2\library\Zend\ServiceManager\ServiceManager.php on line 733
You have to set adapter first.
thank you for support!
i’m write getServiceConfig() in module.php file:
public function getServiceConfig()
{
return array(
‘factories’ => array(
‘Admin\Model\Users’ => function($sm) {
$dbAdapter = $sm->get(‘Zend\Db\Adapter\Adapter’);
$table = new Users($dbAdapter);
return $table;
},
‘Admin\Model\GroupUsers’ => function($sm) {
$dbAdapter = $sm->get(‘Zend\Db\Adapter\Adapter’);
$table = new GroupUsers($dbAdapter);
return $table;
},
),
// menu config
‘invokables’ => array(
‘menu’ => ‘Admin\Model\MenuTable’
),
‘factories’ => array(
‘Navigation’ => ‘Admin\Navigation\MyNavigationFactory’
)
);
}
code remaining write like you!
i’m not understand code is not running
sorry english me not good
You should set adapter first. please take a look zf2 manual : http://zf2.readthedocs.org/en/latest/user-guide/database-and-models.html
Hi, has you work with zend framework 2 and postgres database with multiple schemas?, i’m using zf2 v2.0.6 but always add double quotes to the schema.table name, i llok in the zf2 issue tracker but i dont see nothing like this. i’m using pdo driver to connect.
in setDbAdapter, re-define the $table with TableIdentifier :
public function setDbAdapter(Adapter $adapter) { $this->table = new \Zend\Db\Sql\TableIdentifier('menu', 'yourschema'); $this->adapter = $adapter; $this->resultSetPrototype = new HydratingResultSet(); $this->initialize(); }Thanks, i’m looking for this, is posible to implement in the AuthAdapter?, i can’t believe that this issue isn’t supported like zf1
.
feel free to contribute to zf2 : https://github.com/zendframework/zf2/
Hi, very good tutorial, but I have now problem adding a second navigation bar. Is it posible to do that when yes how, I have read this but dosn’t help.
http://stackoverflow.com/questions/12972316/how-to-set-up-2-navigations-in-zf2
maybe, you should take a look Jurian Sluiman AssembleKernel : https://github.com/ensemble/EnsembleKernel
hey man your all tutorials are wonderfull. I followed your blog but i’m getting on issue that the address of all links showing only to home(www.weblogz2.loc). what could be the possible reason. please help me to rectify this issue.
check your module.config.php on route section, try with Literal first instead of Segment.
I’m really very thankful to you for reply, you are great instructor. This is my module.config.php file address http://pastie.org/6098043 Please if possible have a look of it and suggest me where i have to change for proper link address. i’m really messed up with this thing. if you can, then please mail me the changed file.
with your config. your call-ing route in navigation should be ‘album’ . and it should be work.
Hi, I’ve just attempted this tutorial and It seems the Navigation factory never gets called. I put some debug in the factory and nothing prints. I’m using the latest version of Zend Framework 2, is this still the correct way to do it? Code is as follows: https://gist.github.com/anonymous/5034200
The var_dump in DefaultNavigationFactory never happens.
NM, I got it to work.
Hi Samsonasik,
I’m new in ZF2 (2.1.3).
I follow entire step provided by you. But, I’m getting following error:
( ! ) Fatal error: Uncaught exception ‘Zend\Navigation\Exception\InvalidArgumentException’ with message ‘Invalid argument: Unable to determine class to instantiate’ in D:\wamp\www\zend\2.x\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php on line 744
( ! ) Zend\Navigation\Exception\InvalidArgumentException: Invalid argument: Unable to determine class to instantiate in D:\wamp\www\zend\2.x\vendor\zendframework\zendframework\library\Zend\Navigation\Page\AbstractPage.php on line 225
Thanks
Bharat
add the following common functions to your module class :
public function getConfig() { return include __DIR__ . '/config/module.config.php'; } public function getAutoloaderConfig() { return array( 'Zend\Loader\StandardAutoloader' => array( 'namespaces' => array( __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__, ), ), ); }and don’t forget to set your db adapter. read the docs http://zf2.readthedocs.org/en/latest/user-guide/database-and-models.html
Hello, samsonasik!
I follow entire step provided by you and I’m getting error:
Fatal error: Uncaught exception ‘Zend\ServiceManager\Exception\ServiceNotCreatedException’ with message ‘While attempting to create navigation(alias: Navigation) an invalid factory was registered for this instance type.’ in W:\domains\lp.loc\vendor\ZF2\library\Zend\ServiceManager\ServiceManager.php:871
Thanks!
you should be aware with namespace you used.
Hi, very nice code!!! how can I get the current or active module from here? thank you!!!
I did it like this: $routeMatch->getMatchedRouteName();
I have other question, if I want to invocate a function like this:
echo $this->navigation(‘MyNavigation’)->testFunction();
from layout.phtml, how can I did it?
Thanks again!
i don’t think so, don’t use it even possible, use view_helpers!
i don’t think so. use view_helpers !
i don’t think so, use view_helpers to do something like that !
Hi, great code… helps a lot.
But, I am wondering on how to make it work on two separate menus (default and admin) in a fancy way (with submenu and icons).
I have made it work on a static way.
you can add class/id or/and other attributes beside of label and route.
hi sam.
could you show me how to use BREADCRUMBS by navigation . thanks a lot !!
read the docs http://zf2.readthedocs.org/en/latest/tutorials/tutorial.navigation.html
thank you for your help .
I did it follow the docs , I have made it works,
but the breadcrumbs seems always “Album > Add” whatever the page i visit.
how can i get the true breadcrumbs ?
it’s buggy in 2.1.5, update your zf lib to the latest dev master : https://github.com/zendframework/zf2
Awesome! Great work mate, keep it up!
1 more thing, if you get a chance or you have free time maybe you can add another feature. Like implementing the BjyAuthorize(ACL) in navigation. It would be a great help for all beginners like me. Again, Thank you for this helpful blog!
good idea, thanks.