Segment Routing to factory instead of controller - php

I am currently setting up a ZF2 application and got stuck with the router. I looked up Zend's example for segmented routing:
$route = Segment::factory(array(
'route' => '/:controller[/:action]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]+',
'action' => '[a-zA-Z][a-zA-Z0-9_-]+',
),
'defaults' => array(
'controller' => 'Application\Controller\IndexController',
'action' => 'index',
),
));
By calling http://example.com/Maps/edit Zend would automatically "navigate" to the MapController and call EditAction().
Since I use Factory for the MapController I am looking for a solution like
$route = Segment::factory(array(
'route' => '/:factory[/:action]',
'constraints' => array(
'factory' => '[a-zA-Z][a-zA-Z0-9_-]+',
'action' => '[a-zA-Z][a-zA-Z0-9_-]+',
),
'defaults' => array(
'factory' => 'Application\Controller\Factory\DefaultControllerFactory',
'action' => 'index',
),
));
Basically I want the framework to access the factory instead of the controller without listing any single factory manually.
Thanks for any suggestions!

controller manager is ServiceManager, all service manager features applies. Register controller factory instead of declaring it as invokable

Related

Zend Framework 2 Routing subdomains to module

After searching a long time with no success.
before I give up, I would like to ask:
Is there a way to route a subdomain to a module in Zend Framework 2? like:
Subdomain => Module
api.site.com => api
dev.site.com => dev
admin.site.com => admin
site.com => public
...
I tried doing it like this but I can't get access to controllers other than the default (Index).
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Hostname',
'options' => array(
'route' => 'site.com',
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Index',
'action' => 'index',
),
)
)
),
),
Thank you for taking the time to help me.
Zend Framework 2 doesn't have a notion of routing to modules; all routing mappings are between a URI pattern (for HTTP routes) and a specific controller class. That said, Zend\Mvc provides an event listener (Zend\Mvc\ModuleRouteListener) which allows you to define a URI pattern that maps to multiple controllers based on a given pattern, and so emulates "module routing". To define such a route, you would place this as your routing configuration:
'router' => array(
'routes' => array(
// This defines the hostname route which forms the base
// of each "child" route
'home' => array(
'type' => 'Hostname',
'options' => array(
'route' => 'site.com',
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Index',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
// This Segment route captures the requested controller
// and action from the URI and, through ModuleRouteListener,
// selects the correct controller class to use
'default' => array(
'type' => 'Segment',
'options' => array(
'route' => '/[:controller[/:action]]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'controller' => 'Index',
'action' => 'index',
),
),
),
),
),
),
),
(Click here to see an example of this # ZendSkeletonApplication)
This is only half of the equation, though. You must also register every controller class in your module using a specific naming format. This is also done through the same configuration file:
'controllers' => array(
'invokables' => array(
'Application\Controller\Index' => 'Application\Controller\IndexController'
),
),
The array key is the alias ModuleRouteListener will use to find the right controller, and it must be in the following format:
<Namespace>\<Controller>\<Action>
The value assigned to this array key is the fully-qualified name of the controller class.
(Click here to see an example of this # ZendSkeletonApplication)
NOTE: IF you aren't using ZendSkeletonApplication, or have removed it's default Application module, you will need to register the ModuleRouteListener in one of your own modules. Click here to see an example of how ZendSkeletonApplication registers this listener
If i understand slide #39 of DASPRIDS Rounter Presentation correctly, it's as simple as - on a per module basis - to define your subdomain hosts, i.e.:
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Hostname',
'options' => array(
'route' => 'api.site.com',
'defaults' => array(
'__NAMESPACE__' => 'Api\Controller',
'controller' => 'Index',
'action' => 'index',
),
)
)
),
),
Etc, you'd do this for every Module on its own.

Zend Framework 2 Console Routes

I'm trying to define some console routes for my ZF2 application as described here http://packages.zendframework.com/docs/latest/manual/en/modules/zend.console.routes.html
in the module config I have:
'console' => array(
'router' => array(
'routes' => array(
'user-set-password' => array(
'options' => array(
'route' => 'user password <username> <password>',
'defaults' => array(
'controller' => 'User\Profile',
'action' => 'setpassword'
),
),
),
),
),
),
but it seems to never match the route as it always prints the usage information. also simple routes like just 'test' won't be matched.
(when I write some crap into the route parameter, the execution fails with an Zend\Mvc\Router\Exception\InvalidArgumentException so it recognizes the console route when loading the module)
is it my fault or maybe a bug in the latest zf2 version?
I just found the solution in an inconsistent interface for the route definitions:
it works if you provide the following schema for the controller:
'controller' => 'User\Controller\Profile'
would be better to be able to define it in the same way as http routes:
'defaults' => array(
'__NAMESPACE__' => 'User\Controller',
'controller' => 'Profile',
'action' => 'setpassword',
),
just opened an issue for that: http://framework.zend.com/issues/browse/ZF2-515

Zend Framework 2: Router\Exception "Part route may not terminate"

When trying to assemble a route by calling
return $this->redirect()->toRoute('application');
in my controller I get the following exception:
Zend\Mvc\Router\Exception\RuntimeException
File: library\Zend\Mvc\Router\Http\Part.php:181
Message: Part route may not terminate
the route is configures as following:
'routes' => array(
'application' => array(
'type' => 'Segment',
'options' => array(
'route' => '/[:controller[/[:action[/]]]]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Index',
'action' => 'index',
),
),
'child_routes' => array(
'wildcard' => array(
'type' => 'Wildcard',
),
),
),
),
Is it required to have the controller/action route as a child route from the route /?
when I configure it like that it works. When I use the route [/[:controller[/[:action[/]]]]] (with optional leading slash) it works for some assemblies but not for all and they're all called in the same way described above, partially from other modules.
The error already tells you the problem: You're missing a may_terminate option in your current route. Therefore, you can't short-circuit it by return the redirect() plugin return value.
Just add a
'may_terminate' => true
to your route's config (probably to all route configurations).

Zend Framework 2 Part Route Assembly

My Zend Framework 2 application has a route definition that's trying to mimic the default Zend Framework 1 route. It looks like:
'router' => array(
'routes' => array(
'default' => array(
'type' => 'segment',
'options' => array(
'route' => '/[:controller[/:action]]',
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Index',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'wildcard' => array(
'type' => 'wildcard',
),
),
),
),
),
It matches routes just fine, but I can't assemble routes with arbitrary parameters using the Url view helper.
For example,
$this->url('default', array('controller' => 'test', 'action' => 'test', 'id' => 5));
results in /test/test instead of /test/test/id/5.
Does anyone know how to assemble partial routes like this? Or is there a better way of getting ZF1-style routes?
It turns out that you need to specify the entire route name (including child routes) in the Url view helper.
Using the router defined in my question, the proper view helper call would look like:
$this->url('default/wildcard', array('controller' => 'test', 'action' => 'test', 'id' => 5));
which would result in a url of /test/test/id/5.

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