I am attempting to create multiple navigation menus to use in my application based on a specific user role. The majority of the code is similar to zfc-admin. When I use zfc-admin in my application I am able to bring up an admin menu, however I will have about four roles, and decided to put this in my Application module.
module.config.php
'navigation' => array(
'admin' => array(
array(
'label' => 'Admin Home',
'route' => 'adminhome',
),
),
'default' => array(
array(
'label' => 'Home',
'route' => 'home',
),
),
),
AdminNavigationFactory.php
namespace Application\Navigation\Service;
use Zend\Navigation\Service\DefaultNavigationFactory;
class AdminNavigationFactory extends DefaultNavigationFactory
{
protected function getName()
{
return 'admin';
}
}
Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'admin_navigation' => 'Application\Navigation\Service\AdminNavigationFactory',
),
);
}
layout.phtml
<?php echo $this->navigation('admin_navigation')->menu(); ?>
I get the error.
Fatal error: Uncaught exception 'Zend\ServiceManager\Exception\ServiceNotCreatedException' with message 'While attempting to create adminnavigation(alias: admin_navigation) an invalid factory was registered for this instance type.' in /Applications/MAMP/htdocs/myapp/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php on line 987
If I change the layout.phtml to use the default menu everything works as expected.
<?php echo $this->navigation('navigation')->menu(); ?>
first I got exactly the same issue. After moving the factory configuration from the getServiceConfig() method in the module class to the module.config.php it worked.
So my admin navigation works now like the follows:
module.config.php
(module/Admin/config/module.config.php)
return array(
// yada yada yada...
'service_manager' => array(
'factories' => array(
'navigation' => 'Zend\Navigation\Service\DefaultNavigationFactory',
'adminnav' => 'Application\Navigation\Service\AdminNavigationFactory',
),
),
'navigation' => array(
'default' => array(
array(
'label' => 'Home',
'route' => 'home',
),
array(
'label' => 'Filme',
'route' => 'movies',
),
array(
'label' => 'Admin',
'route' => 'admin',
),
),
'adminnav' => array(
array(
'label' => 'Film hinzufügen',
'route' => 'add-movie',
),
array(
'label' => 'Buch hinzufügen',
'route' => 'add-book',
),
),
),
);
AdminNavigationFactory
(module/Application/src/Application/Navigation/Service/AdminNavigationFactory.php)
namespace Application\Navigation\Service;
use Zend\Navigation\Service\DefaultNavigationFactory;
class AdminNavigationFactory extends DefaultNavigationFactory
{
protected function getName()
{
return 'adminnav';
}
}
Maybe you want to check out the code in context of the entire application, so here are the links to the my github:
AdminNavigationFactory
module.config.php
Regards,
Sascha
Related
I am trying to get my head around Module routing in ZF2.
At the moment I am only able to create a single controller for a single action and am struggling to figure this routing out. I have looked at other modules and plugins and I kind of get it, just need a small push to "get it".
In this example I am trying to route to the two actions: indexAction and cmstoolsAction
Essentially a user navigates to:
/affiliates/overview
/affiliates/cmstools
And the error is:
The requested URL could not be matched by routing.
I think where I am struggling is firstly comprehending how MVC works and getting lost in the detail. There is so much information in the manual that it becomes a little overwhelming.
anyway - would greatly appreciate any input!
Image of the Module structure:
My controller looks like this:
<?php
namespace Affiliates\Controller;
use Zend\Mvc\Controller\AbstractActionController;
class AffiliatesController extends AbstractActionController
{
//Overview page
public function IndexAction()
{
}
public function CmstoolsAction()
{
}
}
And my module config looks like this:
<?php
return array(
'view_manager' => array(
'template_path_stack' => array(
'affiliates' => __DIR__ . '/../view',
),
),
'controllers' => array(
'invokables' => array(
'Affiliates\Controller\Affiliates' =>
'Affiliates\Controller\AffiliatesController'
),
),
'router' => array(
'routes' => array(
'affiliates' => array(
'type' => 'Literal',
'options' => array(
'route' => '/overview',
'defaults' => array(
'controller' => 'Affiliates',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'cmstools' => array(
'type' => 'Literal',
'options' => array(
'route' => '/cmstools',
'defaults' => array(
'controller' => 'Affiliates',
'action' => 'cmstools',
),
),
),
),
),
),
),
);
The routing config is the only important part here. At the moment, you have a route for /overview, which has a child route for /cmstool. This would match the following URLs:
/overview
/overview/cmstool
Not quite what you were after.
There are a few different ways you could configure this. The one closest to what you currently have would be a route for /affiliates, with two child routes, one for each of your actions. The configuration for this would be:
'router' => array(
'routes' => array(
'affiliates' => array(
'type' => 'Literal',
'options' => array(
'route' => '/affiliates',
'defaults' => array(
'controller' => 'Affiliates',
'action' => 'index',
),
),
'child_routes' => array(
'overview' => array(
'type' => 'Literal',
'options' => array(
'route' => '/overview',
'defaults' => array(
'controller' => 'Affiliates',
'action' => 'index',
),
),
),
'cmstools' => array(
'type' => 'Literal',
'options' => array(
'route' => '/cmstools',
'defaults' => array(
'controller' => 'Affiliates',
'action' => 'cmstools',
),
),
),
),
),
),
),
This configuration contains three routes: affiliates, overview and cmstools. The latter two are both child routes of affiliates. Note that I removed the line 'may_terminate' => true, from the affiliates route. This determines whether or not the affiliates route would match on its own (i.e. whether the URL /affiliates would work). Since you didn't list this I'm assuming you don't want it to.
Another way you could configure this would be to simply create two literal routes, once for each URL (not using child routes at all):
'router' => array(
'routes' => array(
'overview' => array(
'type' => 'Literal',
'options' => array(
'route' => '/affiliates/overview',
'defaults' => array(
'controller' => 'Affiliates',
'action' => 'index',
),
),
),
'cmstools' => array(
'type' => 'Literal',
'options' => array(
'route' => '/affiliates/cmstools',
'defaults' => array(
'controller' => 'Affiliates',
'action' => 'cmstools',
),
),
),
),
),
I've got a problem with adding many controllers in the one module. Zend2 is difficult for beginners.
I've created Module "Home" with Controllers "Home" and "News". HomeController is going fine but when I'm trying to connect to the NewsController I'm getting Fatal error: Class 'Home\Controller\NewsController' not found in C:\wamp\www\zend2\vendor\zendframework\zendframework\library\Zend\ServiceManager\AbstractPluginManager.php on line 170. And I don't know where the problem is.
My module.config looks like
return array(
'controllers' => array(
'invokables' => array(
'Home\Controller\Home' => 'Home\Controller\HomeController',
'Home\Controller\News' => 'Home\Controller\NewsController',
),
),
'router' => array(
'routes' => array(
'home' => array(
'type' => 'segment',
'options' => array(
'route' => '/home[/][:action]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*'
),
'defaults' => array(
'controller' => 'Home\Controller\Home',
'action' => 'index',
),
),
),
'news' => array(
'type' => 'segment',
'options' => array(
'route' => '/news[/][:action]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*'
),
'defaults' => array(
'controller' => 'Home\Controller\News',
'action' => 'index',
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'album' => __DIR__ . '/../view',
),
),
);
I'm using navigation factory so navigation file looks like :
return array(
'navigation' => array(
'default' => array(
array(
'label' => 'Home',
'route' => 'home'
),
array(
'label' => 'News',
'route' => 'news'
),
),
),
'service_manager' => array(
'factories' => array(
'navigation' => 'Zend\Navigation\Service\DefaultNavigationFactory'
)
)
);
And Module.php looks like
namespace Home;
class Module {
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
}
And NewsController looks like
namespace News\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class NewsController extends AbstractActionController {
public function indexAction()
{
return array();
}
}
In your controller class you're declaring the namespace as:
namespace News\Controller;
yet in your module config you list the invokable class as Home\Controller\NewsController. The namespaces need to match, so you probably want to change the controller class namespace to:
namespace Home\Controller;
I have this class:
<?php
class RegisterFilter extends InputFilter
{
public function __construct()
{
$this->add(array(
'name' => 'email1',
'required' => true,
'validators' => array(
array(
'name' => 'EmailAddress',
'options' => array(
'domain' => true,
),
),
array(
'name' => 'Identical',
'options' => array(
'token' => 'email2',
),
),
array(
'name' => 'Db\NoRecordExists',
'options' => array(
'table' => 'user',
'field' => 'email',
'messages' => array(
'recordFound' => "Email already exist ... ! <br>",
),
),
),
),
));
}
}
?>
I get this error: No database adapter present. Any ideas why this happens?
It would be good if you'd read the documentation about Zend\Validator\Db\Record*. The given error message means exactly what it said. You don't provide a DB-Adapter inside the Validator.
From the DOCs:
$validator = new Zend\Validator\Db\RecordExists(
array(
'table' => 'users',
'field' => 'emailaddress',
'adapter' => $dbAdapter
)
);
If you want to find out how to get the DB-Adapter into your Form, i have written a Blog Article about said topic.
I want to create admin panel using ZfcAdmin module. I want to create routing, to manage users. Here is it:
<?php
return array(
'controllers' => array(
'invokables' => array(
'AdminUser\Controller\AdminUser' => 'AdminUser\Controller\AdminUserController',
),
),
'view_manager' => array(
'template_path_stack' => array(
'admin-user' => __DIR__ . '/../view',
),
),
'router' => array(
'routes' => array(
'zfcadmin' => array(
'may_terminate' => true,
'child_routes' => array(
'user' => array(
'type' => 'segment',
'options' => array(
'route' => '/user',
'defaults' => array(
'controller' => 'AdminUser\Controller\AdminUser',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' =>array(
'edit' => array(
'type' => 'segment',
'options' => array(
'route' => '/edit/:user_id',
'defaults' => array(
'controller' => 'AdminUser\Controller\AdminUser',
'action' => 'edit',
),
),
),
),
),
),
),
),
),
);
I based on info from zfcadmin github page: https://github.com/ZF-Commons/ZfcAdmin. I just copy and paste the example, and change to fix my needs. However, I recieve a error message:
"Fatal error: Uncaught exception 'Zend\Mvc\Router\Exception\RuntimeException' with message 'Part route may not terminate'"
What's wrong?
EDIT:
I request: /admin/user and it's ok, but when I want to receive URL like: /admin/user/edit/1 I always get /admin/user I create the link this way:
<?php $this->url('zfcadmin/user/edit', array(
'action' => 'edit',
'user_id' => $user['user_id'],
)) ?>
You creating URL incorrectly. Please create the link like this.
<?php $this->url('zfcadmin/user/edit', array( 'user_id' => $user['user_id'], ) ?>
Is it possible to have 2 differents navigation ?
For example :
//in module.config.php
'service_manager'=>array(
'factories'=>array(
'navigation1'=>'Zend\Navigation\Service\DefaultNavigationFactory',
'navigation2'=>'Zend\Navigation\Service\DefaultNavigationFactory',
),
),
'navigation'=>array(
'navigation1'=>array(
'home'=>array('type' => 'mvc','route' => 'home','active'=>false,'label' => 'Home','title' => 'Home',
'pages'=>array(
'contact'=>array('type' => 'mvc','route'=>'contact','active'=>false,'label'=>'Contact','title' =>'Contact'),
)
),
),
'navigation2'=>array(
'home'=>array('type'=>'mvc','route'=>'home','active'=>false,'label'=>'Home','title'=>'Home',
'contact'=>array('type'=>'mvc','route'=>'faq','active'=>false,'label'=>'Faq','title'=>'Faq'),
),
),
//Dans laout
<?php echo $this->navigation()->menu('navigation1')->setMinDepth(0);?>
<hr />
<?php echo $this->navigation()->menu('navigation2')->setMinDepth(0);?>
I would like 2 differents menu with differents pages but this method doesn't run.
Every one has an idea please ?
Thanks
Birzat
You need to provide a custom factory class for each navigation group. For example, see how ZfcAdmin does this:
Create a custom factory class
<?php
namespace ZfcAdmin\Navigation\Service;
use Zend\Navigation\Service\DefaultNavigationFactory;
class AdminNavigationFactory extends DefaultNavigationFactory
{
protected function getName()
{
return 'admin';
}
}
Source: https://github.com/ZF-Commons/ZfcAdmin/blob/master/src/ZfcAdmin/Navigation/Service/AdminNavigationFactory.php
Register AdminNavigationFactory
// in Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'admin_navigation' => 'ZfcAdmin\Navigation\Service\AdminNavigationFactory',
),
);
}
Source: https://github.com/ZF-Commons/ZfcAdmin/blob/master/Module.php#L90
Define Navigation trees in your module's configuration under the key you specified in the getName method of your factory. As an example, this is how ZfcUserAdmin adds itself to the ZfcAdmin menu:
'navigation' => array(
'admin' => array(
'zfcuseradmin' => array(
'label' => 'Users',
'route' => 'zfcadmin/zfcuseradmin/list',
'pages' => array(
'create' => array(
'label' => 'New User',
'route' => 'admin/create',
),
),
),
),
),
Source: https://github.com/Danielss89/ZfcUserAdmin/blob/master/config/module.config.php
/vendor/MyNamespace/library/MyNamespace/Navigation/Service/SecondaryNavigationFactory.php
namespace MyNamespace\Navigation\Service;
use Zend\Navigation\Service\DefaultNavigationFactory;
class SecondaryNavigationFactory extends DefaultNavigationFactory {
protected function getName() {
return 'secondary';
}
}
/config/autoload/global.php
return array(
'service_manager' => array(
'factories' => array(
'navigation' => 'Zend\Navigation\Service\DefaultNavigationFactory',
'secondary' => 'MyNamespace\Navigation\Service\SecondaryNavigationFactory',
),
),
'navigation' => array(
'default' => array(
array(
'label' => 'Item-1.1',
'route' => 'foo',
),
array(
'label' => 'Item-1.2',
'route' => 'bar',
),
),
'secondary' => array(
array(
'label' => 'Item-2',
'route' => 'baz',
),
),
),
);
/module/Application/view/layout/layout.phtml
<?php echo $this->navigation('navigation')->menu(); ?>
<?php echo $this->navigation('secondary')->menu(); ?>