CakePHP use Regex variable capture in routes? - cakephp

In my CakePHP app I have static pages set up like this:
Router::connect(
'/terms',
array('controller' => 'pages', 'action' => 'display', 'terms')
);
This will rewrite /terms to /pages/display/terms To make prettier shorter URLs.
Now If I wanted to do this for all my static pages, it would get quite redundant:
Router::connect(
'/terms',
array('controller' => 'pages', 'action' => 'display', 'terms')
);
Router::connect(
'/privacy',
array('controller' => 'pages', 'action' => 'display', 'privacy')
);
Router::connect(
'/about',
array('controller' => 'pages', 'action' => 'display', 'about')
);
With regular mod_rewrite you can do something like this:
/(terms|privacy|about) /pages/display/$1
So I naturally attempted this:
Router::connect(
'/(terms|privacy|about)',
array('controller' => 'pages', 'action' => 'display', '$1')
);
It does not work. Is there support for something like this, if so how do you do it?

Just off the top of my head, this may solve the issue. To perform a regex match on a portion you need to do so like this:
Router::connect(
'/:page',
array(
'controller' => 'pages',
'action' => 'display',
),
array(
'page' => '(terms|privacy|about)',
'pass' => array('page')
)
);
Notice how the page placeholder in the URL gets extrapolated on in the third parameter, the array. In there we say that it must match the provided regular expression. Also of note is that it also says to pass the page placeholder to the action method. That way it knows which page to render.

Related

CakePHP 3 use default routing in some cases

I have a CakePHP 3.5 website. It was necessary to set slugs without any url prefixes like /pages/slug, so I wrote the following rule:
$routes->connect(
'/:slug',
['controller' => 'Pages', 'action' => 'redirectPage']
)
->setMethods(['GET', 'POST'])
->setPass(['slug'])
->setPatterns([
'slug' => '[a-z0-9\-_]+'
]);
It works nice, but in some cases I want cakePHP to route as default (Controller/Action/Params). For example, I want /admin/login to call 'login' action in 'AdminController'.
I have two ideas that doesn't need exact routings, but I can't make any of them to work:
Filtering some strings by pattern: It would be nice if I could filter some strings, that if slug doesn't match pattern, it will simply skip the routing rule.
Create a '/admin/:action' routing rule, but then I cant use :action as an action variable. It causes errors.
$routes->connect(
'/admin/:action',
['controller' => 'Admin', 'action' => ':action']
)
Any ideas?
Thanks
You can use prefix for admin restricted area.
Example:
Router::prefix('admin', function ($routes) {
$routes->connect('/', ['controller' => 'Users', 'action' => 'login']);
$routes->fallbacks(DashedRoute::class);
});
$routes->connect('/:slug' , [
'controller' => 'Pages',
'action' => 'display',
'plugin' => NULL
], [
'slug' => '[A-Za-z0-9/-]+',
'pass' => ['slug']
]);
Now, for example, path /admin/dashboard/index will execute method in Admin "subnamespace" \App\Controller\Admin\DashboardController::index()
Its nicely described in docs: https://book.cakephp.org/3.0/en/development/routing.html#prefix-routing
Try this:
$routes->connect(
'/admin/:action',
['controller' => 'Admin'],
['action' => '(login|otherAllowedAction|someOtherAllowedAction)']
);
Also, your slug routes seems to not catch /admin/:action routes, b/c dash is not allowed there: [a-z0-9\-_]+

CakePHP - How to make routes with custom parameters?

My Cake URL is like this:
$token = '9KJHF8k104ZX43';
$url = array(
'controller' => 'users',
'action' => 'password_reset',
'prefix' => 'admin',
'admin' => true,
$token
)
I would like this to route to a prettier URL like:
/admin/password-reset/9KJHF8k104ZX43
However, I would like the token at the end to be optional, so that in the event that someone doesn't provide a token it is still routed to:
/admin/password-reset
So that I can catch this case and redirect to another page or display a message.
I've read the book on routing a lot and I still don't feel like it explains the complex cases properly in a way that I fully understand, so I don't really know where to go with this. Something like:
Router::connect('/admin/password-reset/:token', array('controller' => 'users', 'action' => 'password_reset', 'prefix' => 'admin', 'admin' => true));
I don't really know how to optionally catch the token and pass it to the URL.
You'll want to use named parameters. For an example from one of my projects
Router::connect('/:type/:slug',
array('controller' => 'catalogs', 'action' => 'view'),
array(
'type' => '(type|compare)', // regex to match correct tokens
'slug' => '[a-z0-9-]+', // regex again to ensure a valid slug or 404
'pass' => array(
'slug', // I just want to pass through slug to my controller
)
));
Then, in my view I can make a link which will pass the slug through.
echo $this->Html->link('My Link', array('controller' => 'catalogs', 'action' => 'view', 'type' => $catalog['CatalogType']['slug'], 'slug' => $catalog['Catalog']['slug']));
My controller action looks like this,
public function view($slug) {
// etc
}

CakePHP Routing: Changing pretty URLs site-wide

Let's say I want a page to have a pretty URL:
Config/routes.php
Router::connect('/profile', array('controller' => 'users', 'action' => 'profile'));
If I want to send visitors to that page, I can use the URL like:
$this->redirect('/profile');
$this->Html->link('Your Profile', '/profile');
But let's say I change my mind and I now want the URL to be:
/account
How can I change the entire site without changing every instance of /profile to /account?
Alternatively...
Another way to ask my question would be how can I properly code all URLs using Cake array syntax (which I prefer to do rather than hardcode anything):
$this->redirect(array('controller' => 'users', 'action' => 'profile'));
$this->Html->link('Your Profile', array('controller' => 'users', 'action' => 'profile'));
And then ensure that any time that controller/action combination is called, it sends people to the URL:
/profile
And have this rule in one place that can be changed. Something like:
Router::connect(array('controller' => 'users', 'action' => 'profile'), '/profile');
// Later change to
Router::connect(array('controller' => 'users', 'action' => 'profile'), '/account');
Is there any way to do that, and also allow further request parameters to be passed along to be added to the URL?
Have a look at the routing documentation: http://book.cakephp.org/2.0/en/development/routing.html
In your app/routes.php add:
Router::connect('/profile', array('controller' => 'users', 'action' => 'profile'));
Now you can create your links like this:
echo $this->Html->link('Link to profile', array('controller' => 'users', 'action' => 'profile'));
Or if you want to allow additional parameters:
// When somebody comes along without parameters ...
Router::connect('/profile', array('controller' => 'users', 'action' => 'profile'));
// When somebody parses parameters
Router::connect('/profile/*', array('controller' => 'users', 'action' => 'profile'));
And then you will be able to do something like:
$userId = 12;
echo $this->Html->link('Link to other profile', array('controller' => 'users', 'action' => 'profile', $userId));
The $userId will then be available in the controller via:
echo $this->request->params['pass'][0];
// output: 12
This way you can easily change the url's of your website without having to change every single view/redirect or what so ever. Please bare in mind that you should not change your controller names! Because that will mess up a lot. Choose wisely ;-)
http://book.cakephp.org/2.0/en/development/routing.html
http://book.cakephp.org/2.0/en/core-libraries/helpers/html.html

CakePHP 2.x i18n route

There is some solution for using CakePHP route with params only when are not empty?
Now I code below, but I would like some better:
if(Configure::read('Config.language') !== 'en') { // en is default language
$language = '/:language';
} else {
$language = '';
}
Router::connect($language .'/'. __('register', true), array(
'controller' => 'users',
'action' => 'register'));
This code works perfectly, but I still must set language in AppHelper by url() method.
In older apps I was always duplicate Router::connect:
Router::connect('/:language/'. __('register', true), array(
'controller' => 'users',
'action' => 'register')); // for all languages without default language
Router::connect('/'. __('register', true), array(
'controller' => 'users',
'action' => 'register')); // only for default language (en)
Maybe there is simplest solutions?
You need to use 2 routes but add the 'persist' option for your language based routes. Adding 'persist' will avoid having to specify 'language' key each time when generating urls.
// for all languages without default language.
Router::connect(
'/:lang/'. __('register', true),
array(
'controller' => 'users',
'action' => 'register'
),
array(
'persist' => array('lang')
)
);
// only for default language (en)
Router::connect(
'/'. __('register', true),
array(
'controller' => 'users',
'action' => 'register'
)
);
You might also want to checkout CakeDC's I18n plugin.
Ok, these things work better, but I still other problem.
I set default language by Configure::write('Config.language'); to en in bootstrap.php
Next i wrote shema for url like this:
Router::connect('/:language/'. __('register', true), array('controller' => 'users', 'action' => 'register'), array('persist' => array('lang')));
Router::connect('/'. __('register', true), array('controller' => 'users', 'action' => 'register'));
And when users change language by beforeFilter in AppController (set new Config.language) will content from static .po and db worsk perfeclty, but links not translated.
Parametr :language works but magic function __() in Router:connect() not works.
Because first loaded is bootstrap.php, next is router.php and last is AppController.php
My question is, how to force router.php to translate links (__())?
Sorry, but still learn english...

How can I pass default values via a route in CakePHP without URL parameter involvement?

I'm trying to pass in a value to my Controller (in this case PagesController) that does not come from the URL. I simply would like to do something like this:
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'), array('foo' => 'bar'));
Then, in PagesController.php, I have:
public function display() {
$path = func_get_args();
error_log(var_export($path,TRUE));
error_log(var_export($this->request->params,true));
}
Which I expect to have my passed parameter 'foo' with the value 'bar' somewhere.
I've tried a number of seemingly promising methods from: http://book.cakephp.org/2.0/en/development/routing.html
But none of them seem to do what I'm after.
What am I missing?
The answer is apparently:
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'foo' => 'bar', 'home'));
It can be retrieved thusly:
error_log($this->request->params['layout']);

Resources