ZF2 segment route with file extension - zend-framework2

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

Related

Zend Framework - routing same routes to different controller

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

Incorporate custom validation error messages into form object by element

I have the following code which creates a specific text element:
$this->add([
'type' => 'text',
'name' => 'newpassword',
'attributes' => [
'id' => 'newpassword',
'class' => 'form-control'
],
'options' => [
'label' => 'Enter New User Password',
],
]);
And I have the following code which produces my input filter definitions:
$inputFilter->add([
'name' => 'newpassword',
'required' => true,
'filters' => [
['name' => 'StringTrim'],
['name' => 'StripTags']
],
'validators' => [
[
'name' => 'StringLength',
'options' => [
'min' => 6,
'max' => 256
],
]
],
]);
What I want to accomplish is adding my custom messages. Here's the way they have it in the api documentation:
$validator = new Zend\Validator\StringLength(array('min' => 8, 'max' => 12));
$validator->setMessages( array(
Zend\Validator\StringLength::TOO_SHORT =>
'The string \'%value%\' is too short',
Zend\Validator\StringLength::TOO_LONG =>
'The string \'%value%\' is too long'
));
How do I incorporate my custom validation messages into my already programmed code?
UPDATE:
I think this is where i will find success, but not sure how to do it:
$inputFilter->get('newpassword')->getValidatorChain()->
Use this-: its messageTemplates to set custom message
$inputFilter->add([
'name' => 'newpassword',
'required' => true,
'filters' => [
['name' => 'StringTrim'],
['name' => 'StripTags']
],
'validators' => [
[
'name' => 'StringLength',
'options' => [
'min' => 6,
'max' => 256,
'messageTemplates'=>array(
\Zend\Validator\StringLength::TOO_SHORT =>
'The string \'%value%\' is too short',
\Zend\Validator\StringLength::TOO_LONG =>
'The string \'%value%\' is too long'
)
],
]
],
]);

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