Zend Framework 2 Navigation Submenu (Top menu) - php

I'm building a menu using ZF2 and bootstrap and I already have this kind of menu:
Home | Users | Options
But now I need submenus, but I couldn't find a way to do so. I need something like hover the menu item (Ex: User) and then show 'List', 'Add', 'Edit'
I would really appreciate any help.
Thanks

You can achieve this with a partial view.
In you configuration file e.g. config/autoload/global.php :
return array(
// Your others config arrays
'navigation' => array(
'default' => array(
array(
'label' => 'Home',
'route' => 'home',
),
array(
'label' => 'User',
'route' => 'user',
'pages' => array(
array(
'label' => 'List',
'route' => 'list',
),
array(
'label' => 'Add',
'route' => 'add',
),
array(
'label' => 'Edit',
'route' => 'edit',
),
),
),
array(
'label' => 'Options',
'route' => 'options',
),
)
)
);
In your layout file, e.g. view/layout/layout.phtml :
<nav>
<?php
echo $this->navigation('navigation')
->menu()
->setPartial('partial/menu')
->render();
?>
</nav>
The partial view, here view/partial/menu.phtml :
<ul>
<?php
foreach ($this->container as $page)
{
$hasChildren = $page->hasPages();
if( ! $hasChildren)
{
?>
<li><?php echo $page->getLabel(); ?></li>
<?php
}
else
{
?>
<li>
<?php echo $page->getLabel(); ?>
<ul>
<?php
foreach($page->getPages() as $child)
{
?>
<li><?php echo $child->getLabel(); ?></li>
<?php
}
?>
</ul>
</li>
<?php
}
}
?>
</ul>
If you need CSS samples you can find some in this answer :
https://stackoverflow.com/a/13328340/3294723

Related

ZF2 - Active <li> in Zend Navigation Menu

I've managed to generate menu using Zend Navigation. However, the active page is never set (active class is not set for any <li> element).
My partial:
foreach ($pages as $page): ?>
<?php if (!$page->isVisible() || !$this->navigation()->menu()->accept($page)) continue; ?>
<li role="presentation" <?php if ($page->isActive()) echo 'class="active"' ?>>
<a href="<?php echo $page->getHref() ?>">
<?php if ($icon = $page->get('icon')) {
echo '<span class="' . $icon . '"></span>';
} ?>
<span> <?php echo $this->translate($page->getLabel()) ?> </span>
</a>
</li>
<?php endforeach ?>
Extract of module.config.php:
'navigation' => array(
'default' => array(
array(
'label' => 'Page 1',
'route' => 'application/default',
'namespace' => 'Application\Controller',
'controller' => 'Index',
'action' => 'page1',
'icon' => 'fa fa-2x fa-file-text',
'order' => 10,
),
array(
'label' => 'Page 2',
'route' => 'application/default',
'namespace' => 'Application\Controller',
'controller' => 'Index',
'action' => 'page2',
'icon' => 'fa fa-2x fa-file-text',
'order' => 20,
),
),
),
The menu is rendered properly on the page, but without any active class:
$partial = array('partial/menu.phtml', 'default');
echo $this->navigation('navigation')
->menu()
->setMinDepth(0)
->setMaxDepth(0)
->setPartial($partial);
After some research into ZF code, I've found something I don't understand (in Zend\View\Helper\Navigation\Menu.php):
// in renderNormalMenu function, line 288
$isActive = $page->isActive(true);
Any idea or suggestion regarding my problem?
Thanks a lot,
Problem was in module.config.php ; the isActive method (from Zend\Navigation\Mvc) was expected the "full" controller name (including namespace).
My config was splitting namespace and controller name, wich causes the issue.
Solution:
array(
'label' => 'Page 1',
'route' => 'application/default',
'controller' => 'Application\Controller\Index',
'action' => 'page1',
'icon' => 'fa fa-2x fa-file-text',
'order' => 10,
),

Separate navigation config for zend framework modules

I have the following configuration for my navigation in my application module in Application/config/module.config.php:
'navigation' => array(
'default' => array(
array(
'label' => 'Home',
'route' => 'home'
)
)
)
I have the following configuration for my navigation in my cortana module in Cortana/config/module.config.php:
'navigation' => array(
'default' => array(
array(
'label' => 'Home',
'route' => 'cortana-home'
),
array(
'label' => 'Resources',
'route' => 'cortana-resources'
),
array(
'label' => 'Reports',
'route' => 'cortana-reports'
),
array(
'label' => 'Services',
'route' => 'cortana-services'
),
array(
'label' => 'System',
'route' => 'cortana-system'
)
)
)
Im using the layout in my Cortana modulle. Here is the navigation code:
<div class="collapse navbar-collapse">
<?php echo $this->navigation('navigation')
->menu()
->setMinDepth(0)
->setMaxDepth(0)
->setUlClass('nav navbar-nav');
?>
</div><!--/.nav-collapse -->
And finally, unfortunately my result compiles the following HTML:
<li>
Home
</li>
<li class="active">
Home
</li>
<li>
Resources
</li>
<li>
Reports
</li>
<li>
Services
</li>
<li>
System
</li>
</ul> </div><!--/.nav-collapse -->
As you can see, there is 2 home navigation pages. It looks like the code merged the Application navigation module and the Cortana navigation module.
What I need is to have a navigation for the Cortana module and then a separate navigation for the Application module.
UPDATE
I've also tried changing the navigation key to cortana-navigation the following:
/Cortana/config/module.config.php
'service_manager' => array(
'factories' => array(
'cortana-navigation' => 'Zend\Navigation\Service\DefaultNavigationFactory'
)
),
'cortana-navigation' => array(
'default' => array(
array(
'label' => 'Home',
'route' => 'cortana-home'
),
array(
'label' => 'Resources',
'route' => 'cortana-resources'
),
array(
'label' => 'Reports',
'route' => 'cortana-reports'
),
array(
'label' => 'Services',
'route' => 'cortana-services'
),
array(
'label' => 'System',
'route' => 'cortana-system'
)
)
)
And then in my Cortana layout (Cortana/view/layout/layout.phtml)
<div class="collapse navbar-collapse">
<?php echo $this->navigation('cortana-navigation')
->menu()
->setMinDepth(0)
->setMaxDepth(0)
->setUlClass('nav navbar-nav');
?>
</div><!--/.nav-collapse -->
And now my result compiled HTML is:
<ul class="nav navbar-nav">
<li>
Home
</li>
</ul> </div><!--/.nav-collapse -->
I unfortunately have no explanation for why its now using the Application navigation (navigation) instead of the (cortana-navigation) but it does mean that its responding to the change of factory
SECOND UPDATE
I did notice that in the file `Zend/Navigaiton/Service/DefaultNavigationFactory.php' :
class DefaultNavigationFactory extends AbstractNavigationFactory
{
/**
* #return string
*/
protected function getName()
{
return 'default';
}
}
This might mean something with using the default name

Add 2 tags on link in cakephp

I am new in cakephp and i have to create a link with 2 tags like following html
<li><i class="fa fa-th-list"></i> <span>Shop</span></li>
And in cake php i did something like this:
<li><?php echo $this->Html->link(
// $this->Html->tag('i', array('class' => array('fa', 'fa-th-list'))),
$this->Html->tag('span', 'Video / Imagini', null),
array(
'controller' => 'users',
'action' => 'video',
),
array('escape' => FALSE)) ?></li>
How can i add the tag?
I search to internet and on cake book but no details about the second tag.
Thank you for your time.
Your code was almost correct. I made only some little changes:
<li><?php
echo $this->Html->link(
$this->Html->tag('i', '', array('class' => array('fa', 'fa-th-list'))) .
$this->Html->tag('span', 'Video / Imagini'),
array(
'controller' => 'users',
'action' => 'video',
),
array('escape' => false)
);
?></li>

How to use $_GET with paginator?

I added in my project sorting data by select->order by $GET-variables. But when I navigate through the pages by paginator, of course this variables are not passing on the next page. What is the best way to pass this variables and use it with paginator?
Controller:
public function indexAction()
{
$sortForm = new \Records\Form\SortingForm();
$field = 'date';
$order = 'desc';
$request = $this->getRequest();
if ($request->isGet()){
$sortForm->setValidationGroup(array('field', 'order'));
$sortData = $request->getQuery()->toArray();
$sortForm->setData($sortData);
if($sortForm->isValid()) {
$sortForm->getData($sortData);
$field = (string) $this->params()->fromQuery('field', 'date');
$order = (string) $this->params()->fromQuery('order', 'desc');
}
}
$query = $this->getRecordsTable()->fetchAll($field, $order);
$paginator = new Paginator\Paginator(new Paginator\Adapter\Iterator($query));
$paginator->setCurrentPageNumber($this->params()->fromRoute('page', 1));
$paginator->setItemCountPerPage(25);
$vm = new ViewModel(array('records' => $paginator));
Model:
public function fetchAll($field, $order)
{
$this->field = $field;
$this->order = $order;
$resultSet = $this->tableGateway->select(function (Select $select) {
$select->columns(array('date', 'name', 'email', 'homepage', 'text', 'image', 'file'));
$select->order($this->field.' '.$this->order);
});
$resultSet->buffer();
$resultSet->next();
return $resultSet;
}
Form:
public function __construct($name = null)
{
parent::__construct('records');
$this->setAttribute('method', 'get');
$this->add(array(
'name' => 'field',
'required' => false,
'type' => 'Zend\Form\Element\Select',
'options' => array(
'label' => 'Sort by: ',
'value_options' => array(
'date' => 'Date',
'email' => 'E-mail',
'name' => 'Username',
),
)));
$this->add(array(
'name' => 'order',
'required' => false,
'type' => 'Zend\Form\Element\Select',
'options' => array(
'value_options' => array(
'asc' => 'ascending',
'desc' => 'descending',
),
)));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Go',
'id' => 'submitbutton',
),
));
}
Paginator view:
<!-- Numbered page links -->
<?php foreach ($this->pagesInRange as $page): ?>
<?php if ($page != $this->current): ?>
<a href="<?php echo $this->url($this->route, array('page' => $page)); ?>">
<?php echo $page; ?>
</a> |
<?php else: ?>
<?php echo $page; ?> |
<?php endif; ?>
<?php endforeach; ?>
And another one: when I passing get-variables, the query string looks like http://guest-book.me/page/7?field=date&order=asc&submit=Go How I can do not send pair submit=>value?
Thank you for help! :)
Firstly, you need to make sure the route you're using for the Paginator has a Query String child route, I would recommend having a route specifically for use with listings with pagination, an example:
'router' => array(
'routes' => array(
'paginator_route' => array(
'type' => 'segment',
'options' => array(
'route' => '/list/:controller/:action[/page/:page][/]',
'constraints' => array(
//'__NAMESPACE__' => 'Application\Controller',
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'page' => '[0-9]+',
),
'defaults' => array(
'controller' => 'index',
'action' => 'list',
'page' => 1,
),
),
'may_terminate' => true, // with or without Query string
'child_routes' => array(
'query' => array( // allows us to match query string
'type' => 'Query',
'options' => array(
'defaults' => array(
// Query string defaults here..
)
)
),
),
),
You now need to modify your pagination view to allow us to use current parameters as a base when generating the new links:
<!-- Numbered page links -->
<?php foreach ($this->pagesInRange as $page): ?>
<?php if ($page != $this->current): ?>
<?php // the last param allows us to reuse the matched params ?>
<a href="<?php echo $this->url($this->route, array('page' => $page), TRUE); ?>">
<?php echo $page; ?>
</a> |
<?php else: ?>
<?php echo $page; ?> |
<?php endif; ?>
<?php endforeach; ?>
Your pagination links should now retain the Query string values :-)
you can create a helper that pass a GET parameter to url too. i've created a sample module for this : https://github.com/samsonasik/SanSamplePagination

How to change submenu active class in zend navigation?

I am using zend navigation to create menus. I want to change the default class 'active' to 'selected' and I also want to add the class to anchor tag for active link.
Here is my sample code which I have put in bootstrap
protected function _initNavigation()
{
$pages = array(
array(
'module' => 'admin',
'label' => 'Services',
'resource' => 'admin',
'controller' => 'services',
'pages' => array(
array(
'module' => 'admin',
'label' => 'Add Services',
'controller' => 'services',
'action' => 'manage',
'route' => 'default',
),
array(
'module' => 'admin',
'label' => 'View Services',
'controller' => 'services',
'action' => 'view',
'route' => 'default',
),
),
)
);
$this->bootstrap('layout');
$layout = $this->getResource('layout');
$view = $layout->getView();
$config = new Zend_Config($pages);
$navigation = new Zend_Navigation($config);
$view->navigation($navigation);
}
In my view script at layout I have put this below code
echo $this->navigation()->menu()
->setUlId('menu');
Current Output
<ul class="navigation" id="menu">
<li class="active">
Services
<ul>
<li>
Add Services
</li>
<li class="active">
View Services
</li>
</ul>
</li>
Expected Output
<ul class="navigation" id="menu">
<li>
Services
<ul style='display:block;'>
<li>
Add Services
</li>
<li>
<a class='selected' href="/test/public/admin/services/view">View Services</a>
</li>
</ul>
</li>
You have to just set the registry for object 'view' at the end of '_initNavigation()' method in bootstrap.
Zend_Registry::set("view", $view);
Create plugin 'TestNavigation', in that add following code
public function routeShutdown(Zend_Controller_Request_Abstract $request)
{
foreach (Zend_Registry::get('view')->navigation()->getPages() as $page) {
foreach ($page->getPages() as $subpage){
$uri = $subpage->getHref();
if ($uri === $request->getRequestUri()) {
$subpage->setClass('selected');
}
}
}
}
that's it, you have done.

Categories