I have following route added to routes.php in the end.
Router::connect('/:sellername/:itemtitle',
array('controller' => 'items', 'action' => 'view_item_detail'),
array(
'pass' => array('sellername','itemtitle'),
'sellername' => '[a-zA-Z0-9_-]+',
'itemtitle' => '[a-zA-Z0-9_-]+',
)
);
So this matches the dynamic urls like http://example.com/john/title-of-an-item
Problem is this also matches every other url like http://example.com/members/signin even though there's a MembersController controller and signin action in it.
I can fix it using following route entry.
Router::connect(
'/members/:action',
array('controller' => 'members')
);
But it's very tedious to add every route like above.
Doesn't existing matching controller names are prioritized while making a match?
Do order of routes in routes.php matter?
Custom Route classes is to help you
Custom route classes allow you to extend and change how individual routes parse requests and handle reverse routing. A route class should extend CakeRoute and implement one or both of match() and/or parse(). parse() is used to parse requests and match() is used to handle reverse routing.
You can use a custom route class when making a route by using the routeClass option, and loading the file containing your route before trying to use it:
Router::connect(
'/:slug',
array('controller' => 'posts', 'action' => 'view'),
array('routeClass' => 'SlugRoute')
);
This route would create an instance of SlugRoute and allow you to implement custom parameter handling.
custome routing class let you impliment anything
But personal opinion is to user a static and meaning full text in the url that diffrenciate it from the rest.
Related
What would be the correct way to reroute all actions from fakeController to controller1 using Cake's routing engine?
I'd like to reroute actions index and any other actions and also parameters.
app/fake/ => app/controller1/
app/fake/action1 => app/controller1/action1
app/fake/action2/any/params => app/controller1/action2/any/params
Is it possible with just one line of code?
Why I am doing this? - because in CakePHP 3 the routes are case-sensitive. I'd like to keep my controllers names UpperCase, but it results in paths like app/Users/login, if I write users it says usersController not found. If there is a way around this, I wouldn't need all this rerouting.
The default route is case-sensitive, yes, however by default there should be fallbacks defined using the InflectedRoute class, which behave as known from 2.x, ie it will inflect users to Users (as of 3.1.0 the default is DashedRoute, which inflects too).
https://github.com/cakephp/app/blob/3.0.4/config/routes.php#L73
If you want this to be the default behavior (note that this is relatively slow) for all routes, then simply set this to be the default via Router::defaultRouteClass()
Router::defaultRouteClass('InflectedRoute');
https://github.com/cakephp/app/blob/3.0.4/config/routes.php#L42
or in order to restrict it to a specific scope, use the fallbacks() method.
$routes->fallbacks('InflectedRoute');
https://github.com/cakephp/app/blob/3.0.4/config/routes.php#L73
Alternatively you could create appropriate routes for all your controllers, similar to as shown in your apps routes.php file:
Router::scope('/', function (\Cake\Routing\RouteBuilder $routes) {
// ...
$routes->connect('/users', ['controller' => 'Users', 'action' => 'index']);
$routes->connect('/users/:action/*', ['controller' => 'Users']);
$routes->connect('/foos', ['controller' => 'Foos', 'action' => 'index']);
$routes->connect('/foos/:action/*', ['controller' => 'Users']);
// and so on...
});
https://github.com/cakephp/app/blob/3.0.4/config/routes.php#L60-L62
See Cookbook > Routing for more information about routing.
I have set up my routes so that most classes are called in the standard controller/action style. However for my front end I don't want users to see the action being called, so all front end pages have their own controller and use the index action. These are my routers in bootstrap:
Route::set('normal', '<controller>(/<action>(/<arguments>))',
array(
'arguments' => '.*'
))
->defaults(array(
'controller' => 'admin',
'action' => 'index',
));
Route::set('default', '(<controller>(/<arguments>))',
array(
'arguments' => '.*',
))
->defaults(array(
'controller' => 'home',
'action' => 'index',
));
I currently have three front end pages, home, about_us and services. They all work great if I don't pass any arguments in through the URL, but the problem occurs if I try to pass an argument in through the URL into arguments. In services there is only action_index() to display the page and it checks for any arguments, and displays results based on the argument. However if I try to browse to /services/1 to pass in 1 as an argument I get this 404 error:
Kohana_HTTP_Exception [ 404 ]: The requested URL services/1 was not found on this server.
It just uses the first route, normal. Once it can't find the action it doesn't even try to use the second route, which would work. If I swap the order of the routes then it works, but all my other classes that use the first controller stop working as all my actions get passed to action_index() as arguments.
How can I get this working? Why when the first route doesn't work does Kohana not go on to the second route?
You do not need to create controller per route. You can create custom routes (route names) and specify controller and action name. Read the documentation for further explanation. Routing
For arguments try this:
Route::set('default', '(<controller>(/<arguments>))',
->defaults(array(
'controller' => 'home',
'action' => 'index',
));
I have two controllers: ArtistsController and RecordsController
I want to order routes logically depending on what the user is doing.
In this case once the user is editing an Artist (/artists/edit/some-artist) he's able to add some records for that artist.
So, I'd like the route to be something like:
"/artists/edit/some/artist/records/add"
And the same thing with the editing function of a record:
"/artists/edit/some-artist/records/edit/some-record"
I've been fighting with it for a while but I've never worked with Routes before on CakePHP and can't find a solution for this. Is this possible? Thanks
In Config/routes.php
Router::connect('/artists/edit/:some_artist', array('controller' => 'artists', 'action' => 'edit'), array('pass' => array('some_artist')));
Router::connect('/artists/edit/:some_artist/:records', array('controller' => 'artists', 'action' => 'edit'), array('pass' => array('some_artist','records')));
and you go on depending how what parameters you want to pass.
rule is simple: is some variable needs to be passed you put colon ":" before it, and add its name in array 'pass'.
I suggest read Routing: Route elements if you want specify type of passing element.
Additionally Artists Controller function should like this
public function edit($some_artist=null,$records = null) {
/**
[...]
*/
}
I'm trying to get to grips with Cake's routing, but I'm having no luck finding a solution to my particular problem.
I want to map www.example.com/slug to www.example.com/venues/view/slug, where slug is the URL friendly name of a record for a particular venue.
I also want to then map www.example.com/slug/events to www.example.com/events/index/venue:slug.
After reading the CakePHP documentation on Routing, a few times over, I'm none the wiser. I understand how I would create these routes for each individual venue, but I'm not sure how to get Cake to generate the routes on the fly.
You want to be careful mapping something to the first path after the domain name. This means that you would be breaking the controller/action/param/param paradigm. You can do this, but it may mean that you need to define every url for your site in your routes file rather than using Cake's routing magic.
An alternative may be to use /v/ for venues and /e/ for events to keep your url short but break up the url for the normal paradigm.
If you still want to do what you requested here, you could do something like the following. It limits the slug to letters, numbers, dashes, and underscores.
Router::connect(
'/:slug',
array(
'controller' => 'venues',
'action' => 'view'
),
array(
'slug' => '[a-zA-Z0-9_-]+'
)
);
Router::connect(
'/:slug/:events',
array(
'controller' => 'events',
'action' => 'index'
),
array(
'slug' => '[a-zA-Z0-9_-]+'
)
);
In your controller, you would then access the slug with the following (using the first route as an example).
function view(){
if(isset($this->params['slug'])){
//Do something with your code here.
}
}
First off, you're not connecting www.example.com/slug to www.example.com/venues/view/slug, you're connecting /slug to a controller action. Like this:
Router::connect('/:slug',
array('controller' => 'venues', 'action' => 'view'),
array('pass' => array('slug'));
To generate the appropriate link, you'd do the same in reverse:
$this->Html->link('Foo',
array('controller' => 'venues', 'action' => 'view', 'slug' => 'bar'))
That should result in the link /bar.
The problem with routing a /:slug URL is that it's a catch-all route. You need to carefully define all other routes you may want to use before this one.
I need to create routes that include a colon to produce URLs like http://app.com/prjct:a9b5c. Obviously it's currently simple to use a slash instead with the default routing.
$SLUG = array('slug' => '[-_A-Za-z0-9]+');
Router::connect('/prjct/:slug', array('controller' => 'projects', 'action' => 'show'), $SLUG);
But routes specifications use the colon character as a special indicator, which interferes with my naive attempt to replace the second slash above with another colon.
How do I use colons in this case for a route?
You can use named parameter as explained in CakePHP Cookbook. Write code below in your app/config/routes.php:
// Parse only the 'prjct' parameter if the current action is 'show' and the controller is 'projects'.
Router::connectNamed(array('prjct' => array('action' => 'show', 'controller' => 'projects')));
// Then set default route to controller 'projects' and action 'show
Router::connect('/', array('controller' => 'projects', 'action' => 'show'));
In your projects_controller.php :
function show(prjct = null) {
// Check if prjct match the pattern
$pattern = '[-_A-Za-z0-9]+';
if(!preg_match($pattern, prjct)){
// Redirect somewhere else
}
// Rest of your code here
}
I think this is indeed out of scope for simple routes. I see two options:
Use a custom route parsing class, as described here. There isn't a whole lot of documentation on the topic, but you can extend the existing class and play around with it to get a hang of what it's doing. Then customize it to your needs.
class MyRoute extends CakeRoute {
public function parse($url) {
debug($url); // input
$route = parent::parse($url);
debug($route); // output
return $route;
}
}
Route these URLs with a catch-all route to a controller, where the parameter will be available as a named parameter in $this->params['named']. Do what you need to do there.