I have the following module.config.php :
return [
'router' => [
'routes' => [
'landingpage' => [
'type' => Segment::class,
'options' => [
'route' => '/landingpage[/:action/:id]',
'constraints' => [
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[a-zA-Z0-9_-]*'
],
'defaults' => [
'controller' => Controller\LandingPageController::class,
'action' => 'index'
]
],
'may_terminate' => true,
]
]
],
'controllers' => [
'factories' => [
Controller\LandingPageController::class => LandingPageControllerFactory::class
]
],
'service_manager' => [
'invokables' => [
'LandingPage\Service\LandingPageService' => 'LandingPage\Service\LandingPageService'
]
]
];
I am trying to use the following route and it doesn't work:
http://localhost:8081/landingpage/show/1CGe2cveQ
If I use the following route it works :
http://localhost:8081/landingpage/show
If I use the previous route with a / it doesn't work:
http://localhost:8081/landingpage/show/
If you need more info let me know.
Thanks.
You have a double slash in the route declaration: the route is matched by /landingpage/ followed by /:action/:id. If you remove this double slash, the route will work as expected.
'route' => '/landingpage[/:action/:id]',
Moreover, I'd suggest you to modify the route declaration to make the id optional:
'route' => '/landingpage[/:action[/:id]]',
'constraints' => [
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[a-zA-Z0-9_-]+'
]
Tested:
config
'landingpage' => [
'type' => Segment::class,
'options' => [
'route' => '/landingpage[/:action[/:id]]',
'constraints' => [
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[a-zA-Z0-9_-]*'
],
'defaults' => [
'controller' => Controller\IndexController::class,
'action' => 'index'
]
],
'may_terminate' => true,
],
IndexController:
public function indexAction () {
print '<pre>' . print_r($this->params()->fromRoute(), true);
die();
}
public function showAction(){
print '<pre>' . print_r($this->params()->fromRoute(), true);
die();
}
Calling /landingpage
Array
(
[controller] => Application\Controller\IndexController
[action] => index
)
Calling /landingpage/show
Array
(
[controller] => Application\Controller\IndexController
[action] => show
)
Calling /landingpage/show/1CGe2cveQ
Array
(
[controller] => Application\Controller\IndexController
[action] => show
[id] => 1CGe2cveQ
)
Don't forget to clear the configuration cache, if it enabled ;)
Related
I'm refactoring some routing in a project and I'm trying to retain the current path structure of the following...
/events <-- Works
/events/super-bowl <-- Works
/events/2012-super-bowl <-- Doesn't work! Archive Layout
/events/2012-super-bowl/detail-page <-- Doesn't work! Archive sub layout
/events/2018-super-bowl <-- Works. Standard Layout, no sub layout
This is what I have tried...
'router' => [
'routes' => [
'events' => [
'type' => 'literal',
'options' => [
'route' => '/events',
'defaults' => [
'controller' => 'events',
'action' => 'index',
],
],
'may_terminate' => true,
'child_routes' => [
'super-bowl' => [
'type' => 'segment',
'options' => [
'route' => '/super-bowl',
'defaults' => [
'action' => 'superBowl',
],
],
],
'super-bowl-archives' => [
'type' => 'segment',
'options' => [
'route' => '/[:year]-super-bowl[/:detail]',
'constraints' => [
'year' => '^(2012|2013|2014)',
],
'defaults' => [
'controller' => 'super-bowl-archives',
'action' => 'index',
],
],
],
'super-bowl-standard' => [
'type' => 'segment',
'options' => [
'route' => '/[:year]-super-bowl',
'constraints' => [
'year' => '\d{4}'
],
'defaults' => [
'controller' => 'super-bowl-standard',
'action' => 'index',
],
],
],
],
],
],
],
I'm struggling with the archive layouts. I'd like to capture certain years and point them to a different controller. The archives have a sub route as well that I'm not sure how to achieve.
There are two problems in that configuration.
First: matching rule.
Since the matching isn't completely regex based, the correct "pattern" for year is '2012|2013|2014'
Second: matching order.
According to Zend router documentation:
Routes will be queried in a LIFO order, and hence the reason behind the name RouteStack
Last route will be matched first. Since 2012 is matched with \d{4}, you have to first test those "exceptions".
Simply put super-bowl-archives route after super-bowl-standard and it'll work
'router' => [
'routes' => [
'events' => [
'type' => 'literal',
'options' => [
'route' => '/events',
'defaults' => [
'controller' => 'events',
'action' => 'index'
]
],
'may_terminate' => true,
'child_routes' => [
'super-bowl' => [
'type' => 'segment',
'options' => [
'route' => '/super-bowl',
'defaults' => [
'action' => 'superBowl'
]
]
],
'super-bowl-standard' => [
'type' => 'segment',
'options' => [
'route' => '/[:year]-super-bowl',
'constraints' => [
'year' => '\d{4}'
],
'defaults' => [
'controller' => 'super-bowl-standard',
'action' => 'index'
]
]
],
'super-bowl-archives' => [
'type' => 'segment',
'options' => [
'route' => '/[:year]-super-bowl[/:detail]',
'constraints' => [
'year' => '2012|2013|2014'
],
'defaults' => [
'controller' => 'super-bowl-archives',
'action' => 'index'
]
]
]
]
]
]
],
I'm having trouble adding an optional parameter to my home route.
This is my current router:
'routes' => [
'home' => [
'type' => Segment::class,
'options' => [
'route' => '/[:salon/]',
'constraints' => [
'salon' => '[a-zA-Z][a-zA-Z0-9_-]*'
],
'defaults' => [
'controller' => 'Application\Controller\Index',
'action' => 'index',
'salon' => 'test'
],
],
],
'application' => [
'type' => Segment::class,
'options' => [
'route' => '/application[/:controller[/:action]]',
'constraints' => [
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*'
],
'defaults' => [
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Application\Controller\Index',
'action' => 'index',
],
],
'may_terminate' => true,
'child_routes' => [
'default' => [
'type' => 'wildcard'
]
]
],
],
My Controller:
<?php
namespace Application\Controller;
class IndexController extends AbstractController
{
public function indexAction()
{
var_dump($this->params('salon'));
die;
}
}
domain.ltd/
This works and I'm getting default value for salon paramter which is 'test'
domain.ltd/test123
Expected value would be 'test123' but this displays me 404 error: The requested URL could not be matched by routing.
This is how I defined route for my api. It is prefixed with /api/v1. But now few new modules are added in api v2 and all v1 apis are remains same and available in v2. How can i modify this routes that will serve all routes belongs to /api/v1 and when /api/v1 is called and it should serve both /api/v2 and /api/v1 when /api/v2 is called?
module.config.php
'product' => array(
'type' => 'Zend\Router\Http\Segment',
'options' => array(
'route' => '/api/v1/categories[/:id]',
'defaults' => array(
'controller' => CategoryController::class,
),
),
),
'products' => array(
'type' => 'Zend\Router\Http\Segment',
'options' => array(
'route' => '/api/v1/products[/:id]',
'defaults' => array(
'controller' => ProductsController::class,
),
),
),
// ... at lots of v1 apis
//these are introduced in v2
'trends' => array(
'type' => 'Zend\Router\Http\Segment',
'options' => array(
'route' => '/api/v2/trends[/:id]',
'defaults' => array(
'controller' => TrendsController::class,
),
),
),
You can move those common v1 and v2 to a single parent route and v2-only ones to another. Below is sample (not tested) code that should help you understand the idea.
return [
// in Config.router.routes
'api' => [
'child_routes' => [
'v1' => [
'child_routes' => [
// your API 1-and-2 routes
'product' => [/* … */],
'products' => [/* … */]
],
'may_terminate' => false,
'options' => [
'constraints' => ['version' => 'v1|v2'],
'route' => '/:version'
],
'type' => Segment::class
],
'v2' => [
'child_routes' => [
// your API 2 routes
'trends' => [/* … */]
],
'may_terminate' => false,
'options' => ['route' => '/v2'],
'type' => Literal::class
]
],
'may_terminate' => false,
'options' => ['route' => '/api'],
'type' => Literal::class
]
];
If you prefer to not use child routes, you can simply add a route parameter/constraint instead of /v1:
return [
'product' => [
'options' => [
'constraints' => [
'id' => '…',
'version' => 'v1|v2'
],
'defaults' => ['controller' => CategoryController::class],
'route' => '/api/:version/categories[/:id]'
],
'type' => Segment::class
]
];
I know this is late, but I just found this question.
Whilst #gsc's answer is somewhat ok, this is not the correct answer.
This is the correct answer, and this is how I use it:
'api' => [
/** Our main route is /api **/
'may_terminate' => true,
'options' => ['route' => '/api'],
'type' => Literal::class,
'child_routes' => [
/** Since our main route is /api, this will become /api/v1/YOUR_ACTIONS **/
'v1' => [
'type' => Segment::class,
'options' => [
'route' => '/v1[/:action]',
'constraints' => [
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
],
'defaults' => [
'controller' => Controller\ApiV1Controller::class,
'action' => 'index',
],
],
],
/** Since our main route is /api, this will become /api/v2/YOUR_ACTIONS **/
'v2' => [
'type' => Segment::class,
'options' => [
'route' => '/v2[/:action]',
'constraints' => [
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
],
'defaults' => [
'controller' => Controller\ApiV2Controller::class,
'action' => 'index',
],
],
],
/** Add as many "versions" as you want, all with different controllers. **/
],
],
This allows you to use different "versions" of your controller and is shorter, better understandable and complies to standards.
Enjoy!
In ZF3 I want to get default parameter from route. I'm getting parameters in this way in controller:
$params = $this->params()->fromRoute('crud');
My urls looks like this:
1: somedomain/admin/color/add
2: somedomain/admin/color
In 1) I'm getting add in my $params variable.
In 2) I'm getting null but I'm expecting default (in this case view)
I think this is problem with bad router configuration.
'admin' => [
'type' => Segment::class,
'options' => [
'route' => '/admin/:action',
'defaults' => [
'controller' => Controller\AdminController::class,
'action' => 'index',
],
],
'may_terminate' => true,
'child_routes' => [
'color' => [
'type' => Segment::class,
'options' => [
'route' => '/:crud',
'constraints' => [
'crud' => 'add|edit|delete|view',
],
'defaults' => [
'controller' => Controller\AdminController::class,
'crud' => 'view',
],
],
],
],
],
In your route definition, you didn't says the router that your crud parameter is optionnal. So when you call somedomain/admin/color, it is the route /admin/:action which is selected.
To specify a optional parameter, use the bracket notation (assuming you use the same action):
'admin' => [
'type' => Segment::class,
'options' => [
'route' => '/admin/:action[/:crud]',
'defaults' => [
'controller' => Controller\AdminController::class,
'action' => 'index',
'crud' => 'view',
],
'constraints' => [
'crud' => 'add|edit|delete|view',
],
],
],
I want my url route to have a dynamic part and to end up on the same page not matter if whatever I have in the middle part of my URL.
E.g.:
/en/the-old-category/the-old-name/pid/123123123
/en/the-new-category/now-in-a-sub-category/the-new-name/pid/123123123
Should both get caught by the same controller/action (which will issue the pertinent 301/302 if necessary).
My current router contains:
'router' => [
'routes' => [
'blog' => [
'type' => 'segment',
'options' => [
'route' => "/[:language]",
'constraints' => [
'language' => '[a-z]{2}'
],
'defaults' => [
'controller' => 'Blog\Controller\List',
'action' => 'index',
'language' => 'en'
],
'may_terminate' => true,
'child_routes' => [
'detail' => 'segment',
'options' => [
'route' => '/:path/pid/:postid',
'constraints' => [
'path' => '.+',
'postid' => '\d{1,10}'
],
'defaults' => [
'controller' => 'Blog\Controller\List',
'action' => 'detail'
]
]
]
]
]
]
]
But it's not working.
/ and /en are being caught properly, but subroutes like the ones I proposed earlier, are not.
Am I in the right path to do what I want to do? Should I write a regex route instead?
.+ won't match / because segment routes split the path on / before applying constraints. To make your route work you'll need something like /:path/:foo/pid/:postid. A regex route might also work.
Since between the first and the last part of my URL I need to have a variable number of segments, I can't do this with a segment route, but I was able to manage it with a regex route, configured as follows:
'router' => [
'routes' => [
'blog' => [
'type' => 'regex',
'options' => [
'regex' => "/(?<language>[a-z]{2})?",
'spec' => "/%language%",
'defaults' => [
'controller' => 'Blog\Controller\List',
'action' => 'index'
],
'may_terminate' => true,
],
'child_routes' => [
'detail' => [
'type' => 'regex',
'options' => [
'regex' => '/(?<path>.+)/pid/(?<postid>\d+)$',
'spec' => '/%path%/pid/%postid%',
'defaults' => [
'controller' => 'Blog\Controller\List',
'action' => 'detail'
]
]
]
]
]
]
]