Zend Framework - routing same routes to different controller - zend-framework2

I have two routes and want to match both routes when some parameter exists in request.
Route 1:
'companies' => [
'type' => Segment::class,
'options' => [
'route' => '/api/v1/companies[/:id]',
'defaults' => [
'controller' => V1\Rest\Controller\CompaniesController::class,
]
],
'priority' => 2,
'may_terminate' => true,
],
Route 2:
'company_members' => [
'type' => Segment::class,
'options' => [
'route' => '/api/v1/companies[/:id][/:members][/:member_id]',
'defaults' => [
'controller' => V1\Rest\Controller\CompanyMembersController::class,
]
],
'priority' => 2,
'may_terminate' => true,
],
I want to use CompanyMembersController when members exists in the request and CompaniesController when members doesnt exists .But it is not working.

Your issue is in the second route where you defined members as a parameter [/:members]. You should change this to a /members.
I also would recommend to use constraints for your route parameters. Your routes should look like:
'companies' => [
'type' => Segment::class,
'options' => [
'route' => '/api/v1/companies[/:id]',
'defaults' => [
'controller' => Controller\CompaniesController::class,
'action' => 'index',
],
'constraints' => [
'id' => '\d+'
]
],
'priority' => 2,
'may_terminate' => true,
],
'company_members' => [
'type' => Segment::class,
'options' => [
'route' => '/api/v1/companies[/:id]/members[/:member_id]',
'defaults' => [
'controller' => Controller\CompanyMembersController::class,
'action' => 'index',
],
'constraints' => [
'id' => '\d+',
'member_id' => '\d+',
]
],
'priority' => 2,
'may_terminate' => true,
],
Also you can see the constraints to parameters id & member_id to integers.
References
zend mvc routing
understanding routing
routing and controllers

Related

I have two action for a single route but not as arming the URL

I have a problem I could not solve, I have a child route, like this:
'apps'=>array(
'type'=>'Segment',
'options'=>array(
'route' => '/apps[/[:action[/:id]]]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'controller' => 'Apps\Controller\Index',
'action' => 'index'
),
),
'may_terminate' => true,
'child_routes' => array(
'ximages' => array(
'type' => 'Segment',
'options' => array(
'route' => '/ximages[/[:action[/:id_ximage]]]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'controller' => 'Apps\Controller\xImages',
'action' => 'index'
)
),
),
In the file .phtml I want to access the path http://miserver/apps/view/1/ximages/images/1 and what I do is the following:
echo $this->url(
'apps/ximages',
array(
'action'=>'view',
'id' => 1,
'id_ximage' => 2
)
);
But this code only prints me to the path http://miserver/apps/view/1/ximages/index/1 and do not know how you can pass the name of the action of the child route.
your route is not properly set, because your params are the same between your main route and your child route (:action)
'route' => '/apps[/[:action[/:id]]]',
'route' => '/ximages[/[:action[/:id_ximage]]]',
the first parameters is defined by what your give here :
echo $this->url(
'apps/ximages',
array(
'action'=>'view',
'id' => 1,
'id_ximage' => 2
)
);
so the view parameters is correctly set for your main route, but this params is consumed, and cannot be used again. So in the second params called with the name action you have no params given soi the default is called and for you it's
controller' => 'Apps\Controller\xImages',
'action' => 'index'
By the way, your "controller" params is useless ;)
So i advise you to change your child route params :action to anything else, and set the param in your .phtml file like the others.
'route' => '/ximages[/[:action2[/:id_ximage]]]',
echo $this->url(
'apps/ximages',
array(
'action'=>'view',
'id' => 1,
'id_ximage' => 2,
'action2' => 'images'
)
);

ZF2 segment route with file extension

I have a route to an action which returns a pdf file. Now it would be fine if the url would contain the file extension .pdf. If the last part of my route is not a segment, it should work but not in my case.
Works
'my_route' => [
'type' => 'segment',
'may_terminate' => true,
'options' => [
'route' => '/my-file.pdf',
'defaults' => [
'action' => 'file'
]
]
],
Does not work
'my_route' => [
'type' => 'segment',
'may_terminate' => true,
'options' => [
'route' => '/my-file/:year.pdf',
'constraints' => [
'year' => '\d{4}'
],
'defaults' => [
'action' => 'file',
'year' => date('Y')
]
]
],
This is an example using Regex route (not fully tested):
'my_route' => [
'type' => 'regex',
'may_terminate' => true,
'options' => [
'route' => '/my-file/(?<year>\d{4}).pdf?',
'constraints' => [
'defaults' => [
'action' => 'file',
'year' => date('Y')
]
]
],
See the docs : https://framework.zend.com/manual/2.4/en/modules/zend.mvc.routing.html#zend-mvc-router-http-regex
You can adjust it to this:
'route' => '/my-file/:year:.pdf',
Note the extra : after the parameter

Zend 2: Add prefix to route's action

I have application with following URLs
www.myapp.com/admin/profile [index action]
www.myapp.com/admin/profile/add [add action]
www.myapp.com/admin/profile/edit [edit action]
www.myapp.com/admin/profile/del [delete action]
These URLs are for users with admin permissions.
Users who do NOT have admin permissions have following URLs
www.myapp.com/user/profile
www.myapp.com/user/profile/add
www.myapp.com/user/profile/edit
www.myapp.com/user/profile/del
Routes in Zend 2
// admin routes
'admin' => array(
'type' => 'Literal',
'options' => array(
'route' => '/admin',
'defaults' => array(
'__NAMESPACE__' => __NAMESPACE__.'\Controller',
),
),
'may_terminate' => true,
'child_routes' => array(
// Profile
'profile' => array(
'type' => 'Literal',
'options' => array(
'route' => '/profile',
'defaults' => array(
'__NAMESPACE__' => __NAMESPACE__ . '\Controller',
'controller' => 'Profile',
'action' => 'index'
)
),
'may_terminate' => true,
'child_routes' => array(
'default' => array(
'type' => 'Segment',
'options' => array(
'route' => '[/:action[/:id]]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '\d+'
),
'defaults' => array(
'__NAMESPACE__' => __NAMESPACE__ . '\Controller',
'controller' => 'Profile'
)
)
),
)
),
),
),
// user routes
'admin' => array(
'type' => 'Literal',
'options' => array(
'route' => '/user',
'defaults' => array(
'__NAMESPACE__' => __NAMESPACE__.'\Controller',
),
),
'may_terminate' => true,
'child_routes' => array(
// Profile
'profile' => array(
'type' => 'Literal',
'options' => array(
'route' => '/profile',
'defaults' => array(
'__NAMESPACE__' => __NAMESPACE__ . '\Controller',
'controller' => 'Profile',
'action' => 'clientIndex'
)
),
'may_terminate' => true,
'child_routes' => array(
'default' => array(
'type' => 'Segment',
'options' => array(
'route' => '[/:action[/:id]]',
'constraints' => array(
'action' => 'client[a-zA-Z][a-zA-Z0-9_-]*', <----- look here
'id' => '\d+'
),
'defaults' => array(
'__NAMESPACE__' => __NAMESPACE__ . '\Controller',
'controller' => 'Profile'
)
)
),
)
),
),
),
What I want to have is that if user access url: www.myapp.com/admin/profile/add
Application run controller Profile and action addAction
If user access url: www.myapp.com/user/profile/add
Application run controller Profile and action userAddAction
So I want to add prefix 'user' to every action when user routes are used.
I have tried:
'options' => array(
...
'defaults' => array(
'__NAMESPACE__' => __NAMESPACE__ . '\Controller',
'controller' => 'Profile',
'action' => 'user[:action]' <--- look here
)
)
But of course it doesn't work.
I know I could define static routes, but I would like to do it with Segment routes type
There is no need to change the route. Route definitions are there to be matched by the URL, so the application is able to execute the correct controller action.
So by defining 'action' => 'client[a-zA-Z][a-zA-Z0-9_-]*' you are saying that the [:action] part of the route needs to match on this pattern, which would only happen if you browsed to www.myapp.com/admin/profile/clientadd etc.
To resolve your problem you can split your child routes so you have a route per action.
This example shows for the user route, however you can copy this and add them as children of the /admin/profile route also (changing the action value point addAction rather than clientAddAction etc).
// user routes
'user' => [
// same as before
'child_routes' => [
'profile' => [
// same as before
'child_routes' => [
'add' => [
'type' => 'literal',
'options' => [
'route' => '/add'
'defaults' => [
// no need for controller value as is
// inherited from the 'profile' parent route
'action' => 'clientAddAction'
],
],
],
'edit' => [
'type' => 'segment',
'options' => [
'route' => '/edit/:id',
'defaults' => [
'action' => 'clientEditAction',
]
],
],
'del' => [
'type' => 'segment',
'options' => [
'route' => '/del/:id',
'defaults' => [
'action' => 'clientDeleteAction',
]
],
],
],
],
],
];
The only change you would need to make is when you render a URL within the view.
$this->url('/users/profile/default, ['action'=>'add']);
$this->url('/users/profile/default, ['action'=>'edit', 'id' => 123]);
Would become.
$this->url('/users/profile/add');
$this->url('/users/profile/edit, ['id' => 123]);

Zend Framework 2 Wildcard Route

I have the following route in my module.config.php:
'routes' => array(
'admin' => array(
'type' => 'Segment',
'options' => array(
'route' => '/admin[/:controller[/:action]][/]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]+',
'action' => '[a-zA-Z][a-zA-Z0-9_-]+',
),
'defaults' => array(
'__NAMESPACE__' => 'Admin\Controller',
'module' => 'Admin',
'controller' => 'Index',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'wildcard' => array(
'type' => 'Wildcard',
)
),
'priority' => 1000
),
),
The reason for the [/] in the end of the route is in the question: Zend Framework 2 Segment Route matching 'test' but not 'test/'
I want this route to be like in ZF1. I want to pass $_GET parameters in it (like /id/1/test/2/).
The problem it this route is actually matching /admin/customer/edit//id/20 but not matching /admin/customer/edit/id/20
Any ideas?
You are on the right track! Use "Wilcard" as a type of child-route to your admin-route.
There are two options available: key_value_delimiter and param_delimiter.
Both's default values are '/' which is equal to the ZF1 default behaviour of route parameters.
'router' => array(
'routes' => array(
'admin' => array(
'type' => 'Segment',
'options' => array(
'route' => '/admin[/:controller[/:action]]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]+',
'action' => '[a-zA-Z][a-zA-Z0-9_-]+',
),
),
'defaults' => array(
'__NAMESPACE__' => 'Admin\Controller',
'module' => 'Admin',
'controller' => 'Index',
'action' => 'index',
),
'may_terminate' => true,
'child_routes' => array(
'wildcard' => array(
'type' => 'Wildcard',
'options' => array(
'key_value_delimiter' => '/',
'param_delimiter' => '/'
)
)
)
)
)
)
If you want to address the wildcard route with the help of the url view-helper, you can use it like that:
$this->url('admin/wildcard', array('id' => 1234, 'foo' => 'bar'));
You can add route parameter for id :
'route' => '/admin[/: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 route matchs admin/customer/edit/20/, so you can get id in controller:
$this->params()->fromRoute('id');
If you want to have admin/customer/edit/id/20/ ,try:
'route' => '/admin[/:controller[/:action]][id/:id][/]',
If I am understanding correctly, you are trying to get multiple parameters from the URL, right?
e.g.
Traditional GET: www.domain.com/ctrl/action?key1=abc&key2=efg& ... & keyN=xyz
ZF2 route: www.domain.com/ctrl/action/key1/abc/key2/efg/.../keyN/xyz
If so, this is one way of doing it:
'adminPage' => array(
'type' => 'regex',
'options' => array(
'regex' => '/admin/customer/edit[/](?<keyValuePairs>.*)',
'defaults' => array(
'controller' => 'YourProject\Controller\YourController',
'action' => 'yourAction',
),
'spec' => '/admin/customer/edit/%keyValuePairs%',
)
With this, every character after 'admin/customer/edit/' will be stored in 'keyValuePairs' parameter. In Controller::yourAction, get the 'keyValuePairs' parameter, then split the string back into a meaningful key-value data structure.

How to pass arrays in ZF2 routes?

for example, I want to get this url string
/1/2/3/4
In view:
$this->url('routeName', array(
'a' => array(1, 2, 3, 4)
));
In controller:
print_r($this->params()->fromRoute('a'));
Output is:
array(
0 => 1,
1 => 2,
2 => 3,
3 => 4
);
Is it possible to create this route?
IF it would work at all, it'd be using the class Zend\Mvc\Router\Http\WildCard. Since I never got that one to be working the way i expected it to be though, i suggest you go the ZF2 way where you have full control over what you're doing ;) Parameters and configuration stuff should be named always! I suggest you create a simple route of type Zend\Mvc\Router\Http\Segment:
'routename' => array(
'type' => 'Zend\Mvc\Router\Http\Segment',
'options' => array(
'route' => '/:val1/:val2/:val3/:val4',
'defaults' => array(
'controller' => 'controllername',
'action' => 'actionname'
),
'constraints' => array(
'val1' => '[0-9]+',
'val2' => '[0-9]+',
'val3' => '[0-9]+',
'val4' => '[0-9]+'
)
)
)
If the requirements are different, obviously the route configuration would change. You'd need to set up the route like this:
$this->url('routename', array(
'val1' => 1,
'val2' => 2,
'val3' => 3,
'val4' => 4
));
Add the url routing in module.config.php file like this:
'routename' => array(
'type' => 'Zend\Mvc\Router\Http\Segment',
'options' => array(
'route' => 'routename[/:val1][/:val2][/:val3][/:val4]',
'defaults' => array(
'controller' => 'controllername',
'action' => 'actionname'
),
'constraints' => array(
'val1' => '[0-9]+',
'val2' => '[0-9]+',
'val3' => '[0-9]+',
'val4' => '[0-9]+'
)
)
)
And then add the number by following this:
$this->url('routename', array(
'val1' => 1,
'val2' => 2,
'val3' => 3,
'val4' => 4
));
And you can get all the parameter by :
print_r($this->params());

Resources