Pass custom variables in ZF2 routing config? - php

I'm thinking about the best way of implementing ACL. So - I need to protect certain routes. Some routes would be accessible only to users, some to guests and some to admins.
It seems like the best way of doing it would be by adding a $role variable in the routing config. So then I'd attach to post-route event, fetch the routeMatch and I would see if this user can enter this route.
How can I do that? Can I simply inject extra varibles like this:
'router' => array(
'routes' => array(
'route1' => array(
'type' => 'Zend\Mvc\Router\Http\Regex',
'options' => array(
'regex' => '/some/route/1',
'defaults' => array(
'controller' => 'Subscriber\Controller\View',
'action' => 'route1',
'role' => 'user', //extra
),
'spec' => '/some/route/1',
),
),
'route2' => array(
'type' => 'Zend\Mvc\Router\Http\Regex',
'options' => array(
'regex' => '/some/route/2',
'defaults' => array(
'controller' => 'Subscriber\Controller\View',
'action' => 'route2',
'role' => 'guest', //extra
),
'spec' => '/some/route/2',
),
),
//other routes....
),
),

Yes you can just add the router key like you have
'defaults' => array(
'controller' => 'Subscriber\Controller\View',
'action' => 'route1',
'role' => 'user', //extra
),
And then you can checkit like this
public function onBootstrap(MvcEvent $e) {
$application = $e->getApplication();
$eventManager = $application->getEventManager();
$eventManager->attach(MvcEvent::EVENT_ROUTE, function(MvcEvent $e) {
$e->getRouteMatch()->getParam('role');
});
}
There are however modules made for this
For example bjyoungblood/BjyAuthorize which works with ZfcUser

You should take a look at : ZfcRbac. It's well documented.

Related

Routing problems in ZF2 : Controller not mapped

I'm trying to create a simple CRUD in Zf2 to get to know it and I'm having problems routing the only controller I have. I have this error;
"The requested controller could not be mapped to an existing controller class".
I'm trying to call this route : http://zf2.local/Listapp
This is my structure :
module/Listapp/src/Listapp/Controller/ListappController.php
The namespace is namespace Listapp\Controller;
This is my autoloader config :
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
// Autoload Listapp classes
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
// Autoload ListappController classes
'ListappController' => __DIR__ . '/src/Listapp',
)
)
);
}
And this is my module.config.php :
return array(
'controllers' => array(
'invokables' => array(
'Listapp\Controller\Listapp' => 'Listapp\Controller\ListappController'
)
),
'router' => array(
'routes' => array(
'listapp' => array(
'type' => 'segment',
'options' => array(
'route' => '/[:controller[/:action][/:id]]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Listapp\Controller\Listapp',
'action' => 'index',
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'Listapp' => __DIR__ . '/../view',
),
), );
Any help would be appreciated thanks !
EDIT:
This is the code in my controller (minus the other CRUD functions) :
namespace Listapp\Controller;
use Zend\Mvc\Controller\AbstractActionController;
class ListappController extends AbstractActionController
{
public function indexAction()
{
}
}
So just to further explain my comment, by including a :controller segment in your route, you've told ZF to try and match the first thing in your URL to something that the controller manager can load (in your case, one of the keys in you controller invokables). The controller default you defined in your route would only apply if you visited http://zf2.local/.
So for you, the quickest fix is to change your configuration to:
'controllers' => array(
'invokables' => array(
'Listapp' => 'Listapp\Controller\ListappController'
)
),
'Listapp' in the URL will then match this controller, and everything will work as you expect.
In general it makes things clearer if you avoid using :controller in routes and have at least one route per controller instead, e.g.:
'controllers' => array(
'invokables' => array(
'Listapp\Controller\Listapp' => 'Listapp\Controller\ListappController'
)
),
'router' => array(
'routes' => array(
'listapp' => array(
'type' => 'segment',
'options' => array(
'route' => '/listapp[/:action[/:id]]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Listapp\Controller\Listapp',
'action' => 'index',
),
),
),
),
),

Zend 2 redirect with toRoute not working

Why is Zend 2 such a !##(#(!##??
OK, so I'm trying to get a simple redirect working. I have a controller called 'listitems' with an action called 'editlistitem'. After hours of banging on it with a hand sledge, I've finally got the form to work and the validation to work and the hydration to Doctrine to work so I can save the result.
The last step is to redirect the user to the 'showlistitem' action which includes the id trailing it. (full route sub path is 'listitem/showlistitem/2' where 2 is the id I want to see)
I have tried:
$this->redirect()->toRoute('/listitem/showlistitem/2');
$this->redirect()->toRoute('listitem/showlistitem/2');
$this->redirect()->toRoute('showlistitem/2');
$this->redirect()->toRoute('listitem/showlistitem', array('id' => 2));
$this->redirect()->toRoute('listitem-showlistitem', array('id' => 2));
None of them flippin work! (they all return route not found)
A route to the controller is in modules.config.php with a child route to the action. I can go directly to the url by typing it in manually and it works fine. How in the bleep do I get Zend to redirect the user to that route from an action?
The toRoute method provided by the The Redirect plugin needs the route name to be passed as parameter. This is its desciption :
toRoute(string $route = null, array $params = array(), array $options = array(), boolean $reuseMatchedParams = false)
Redirects to a named route, using the provided $params and $options to assembled the URL.
Given this simple route configuration example :
//module.config.php
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Segment',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'index',
'action' => 'index',
),
),
),
'app' => array(
'type' => 'Literal',
'options' => array(
'route' => '/app',
'defaults' => array(
'controller' => 'index',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'default' => array(
'type' => 'Segment',
'options' => array(
'route' => '/[:controller[/:action[/:id]]]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id'=>'[0-9]+',
),
),
),
),
),
),
),
This redirection works :
return $this->redirect()->toRoute('app/default',
array('controller'=>'controller-name', 'action'=>'action-name', 'id'=>$id));
In your case, this would work :
return $this->redirect()->toRoute('app/default',
array('controller'=>'listitem', 'action'=>'showlistitem', 'id'=>2));

Grant ACL permission by URLs in Zend Framework 2

I follow this tutorial: http://ivangospodinow.com/zend-framework-2-acl-setup-in-5-minutes-tutorial/
But, I want to grant permission by custom URLs, so I had some changes in my code.
In module.acl.roles.php
return array(
'guest'=> array(
'/home.html',
'/login.html',
'/register.html'
),
'admin'=> array(
'/user/add.html',
'/user/edit.html',
'/user/list.html',
),
);
In module.config.php
return array(
'router' => array(
'routes' => array(
'/home.html' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
),
'/user/add.html' => array(
'type' => 'Zend\Mvc\Router\Http\Regex',
'options' => array(
'regex' => '/user/add.html',
'defaults' => array(
'controller' => 'Application\Controller\User',
'action' => 'add',
'format' => 'html',
),
'spec' => '/user/add.%format%',
),
),
...
),
),
);
But I received this error: Route with name "" not found. Please give me some advices and solutions to grant permission by URLs
Thank you!
I really really recommend the BjyAuthorize module (https://packagist.org/packages/bjyoungblood/bjy-authorize).
But if you really want to do this by yourselft you need to add a listener to the \Zend\Mvc\MvcEvent::EVENT_ROUTE.
You can attach your listener with
$events->attach(MvcEvent::EVENT_ROUTE, array($this, 'myOnRoute'), -1000);
and in your myOnRoute method you can handle the route
public function myOnRoute(MvcEvent $event) {
$match = $event->getRouteMatch();
$routeName = $match->getMatchedRouteName();
// do stuff here (compare to config or whatever)
}

ZendFramework 2 - How to make all the actions available with one router rule? Its only allowing action index

How to allow all sub actions inside that controller with one router rule? For example this follow:
visit: site/login - works only
site/login/forgetpassword - does not work
site/login/remmeberme - does not work
Example:
$router = $e->getApplication()->getServiceManager()->get('router');
$route = Http\Literal::factory(array(
'route' => '/login',
'defaults' => array(
'controller' => 'Application\Controller\Login',
'action' => 'index'
),
));
$router->addRoute('login', $route, null);
Follow up:
How can i make it so that /login and /login/anything works?
$route = Http\Segment::factory(array(
'route' => '/login[/:action]',
'defaults' => array(
'controller' => 'Application\Controller\Login',
'action' => 'index'
),
));
$router->addRoute('login', $route, null);
There is an excellent QuickStart Tutorial available within the official Documentation. Set up your route like the following to be allowed multiple actions and an ID Parameter. Fur further information please take a look at the documentation.
You may also be interested in DASPRiDs presentation from ZendCon2012
'router' => array(
'routes' => array(
'album' => array(
'type' => 'segment',
'options' => array(
'route' => '/album[/:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Album\Controller\Album',
'action' => 'index',
),
),
),
),
),

How to create a generic module/controller/action route in Zend Framework 2?

I would like to create a generic module/controller/action route in Zend Framework 2 to be used with ZF2 MVC architecture.
In ZF1 the default route was defined like /[:module][/:controller][/:action] where module would default to default, controller would default to index and action to index.
Now, ZF2 changed the way modules are intended, from simple groups of controllers and views, to real standalone applications, with explicit mapping of controller name to controller class.
Since all controller names must be unique across all modules, I was thinking to name them like modulename-controllername but I would like the URL to look like /modulename/controllername without the need to create specific routes for each module, using something like the old default route for ZF1 described above.
Yes it is very possible, but you will have to do a little work. Use the following config:
'default' => array(
'type' => 'My\Route\Matcher',
'options' => array(
'route' => '/[:module][/:controller[/:action]]',
'constraints' => array(
'module' => '[a-zA-Z][a-zA-Z0-9_-]*',
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'module' => 'default',
'controller' => 'index',
'action' => 'index',
),
),
),
Then you have to write your own My\Route\Matcher to create a Routemap object that the MVC can use. It's not hard, look at the other route matchers already in the framework and you'll get the idea.
If you use the Zend Skeleton Application you have already configured this default controller.
See here https://github.com/zendframework/ZendSkeletonApplication/blob/master/module/Application/config/module.config.php
To have a general/standard routing system for a zf2 module, this is my solution for just one controller "module\controller\index" ( default controller ) :
'router' => array(
'routes' => array(
'default' => array(
'type' => 'Literal',
'options' => array(
'route' => '/', // <======== this is take the first step to our module "profil"
'defaults' => array(
'module' => 'profil',
'controller' => 'profil\Controller\Index',
'action' => 'index',
),
),
),
'profil' => array(
'type' => 'Segment',
'options' => array(
'route' => '/[profil][/:action]', // <======== this is take the next steps of the module "profil"
'constraints' => array(
'module' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array( // force the default one
'module' => 'profil',
'controller' => 'profil\Controller\Index',
'action' => 'index',
),
),
),
),
),
then in our controller "profil\Controller\Index" we have three actions "index" "home" "signout" :
public function indexAction()
{
if ($this->identity()) {
return $this->redirect()->toRoute('profil',array('action'=>'home'));
} else {
// ......
$authResult = $authService->authenticate();
if ($authResult->isValid()) {
//......
return $this->redirect()->toRoute('profil',array('action'=>'home'));
} else {
// ......
}
} else {
$messages = $form->getMessages();
}
}
return new ViewModel();
}
}
public function homeAction()
{
if (!$this->identity()) {
return $this->redirect()->toRoute('profil',array('action'=>'signout'));
}
}
public function signoutAction()
{
if ($this->identity()) {
$authService = $this->getServiceLocator()->get('Zend\Authentication\AuthenticationService');
$authService->clearIdentity();
}
$this->redirect()->toRoute('profil');
}
and thank you anyway :)

Categories