CakePHP Routing - [home]/slug as URL - cakephp

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.

Related

How to redefine the URLs generation without changes at the HtmlHelper#link(...) calls in CakePHP?

I have a CakePHP website with many internal links, that are build with the HtmlHelper:
/app/View/MyController/myaction.ctp
<?php
echo $this->Html->link(
$item['Search']['name'],
array(
'controller' => 'targetcontroller',
'action' => 'targetaction',
$profileId,
$languageId
)
);
?>
It works fine with the default route:
/app/Config/routes.php
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
The generated links look like that: /mycontroller/myaction/$profileId/$languageId.
Now I want to use search engine friendly URLs (with profile names and ISO-639-1 language codes instead of IDs) for a part of the website and added a new Route:
/app/Config/routes.php
Router::connect(
'/:iso6391/:name.html',
array('controller' => 'mycontroller', 'action' => 'myaction'),
array(
'iso6391' => '[a-zA-Z]+',
'name' => '[0-9a-zA-ZäöüßÄÖÜ\-]+',
)
);
And it also works fine and the incomming URIs like /producer/en/TestName.html are interpreted correctly.
But the HtmlHelper is still generating the old URIs like /mycontroller/myaction/1/1.
The docu says:
Reverse routing is a feature in CakePHP that is used to allow you to easily change your URL structure without having to modify all your code. By using routing arrays to define your URLs, you can later configure routes and the generated URLs will automatically update.
Well, the HtmlHelper gets a routing array as input, that means: I'm using the reverse routing.
Why does it not work? How to make the HtmlHelper generate the new URLs (without changing the HtmlHelper#link(...) calls)?
Bit of explanation first
You are technically not using reverse routing. You see, the output link, /mycontroller/myaction/1/1 definitively doesn't match /iso/name.html. Like, in no way. So, the routing skips that rule because it doesn't apply.
Code
Try this
echo $this->Html->link(
$item['Search']['name'],
array(
'controller' => 'targetcontroller',
'action' => 'targetaction',
'iso6391' => $someStringWithIso,
'name' => $someName
)
);
But for that, you have to change your routing a bit, because you are not passing the parameters (check the docs for examples)
Router::connect(
'/:iso6391/:name.html',
array('controller' => 'mycontroller', 'action' => 'myaction'),
array(
'pass' => array('iso6391', 'name'),
'iso6391' => '[a-zA-Z]+',
'name' => '[0-9a-zA-ZäöüßÄÖÜ\-]+',
)
);
And you have to mind the first string match /:iso6391/:name.html. Do you want to match this route to every controller and action in your project, or just the one controller and the one view. If it is for all projects, just for precaution, use this
/:controller/:action/:iso6391/:name.html
if is just for, say, Controller1 and action "view", use
/controller1/view/:iso6391/:name.html
The detail you need to consider is the extension you use .html, is that really necessary in the url? If it is, add it as a parameter in the Html#link
echo $this->Html->link(
$item['Search']['name'],
array(
'controller' => 'targetcontroller',
'action' => 'targetaction',
'iso6391' => $someStringWithIso,
'name' => $someName
'ext' => 'html'
)
);
and also add parseExtensions to the routing file. Read this. Would be easier if you don't add the extension, but that's up to you.
In the end, you still have to change your calls to Html->link...

CakePhp Routes with Controller wildcard

I'd like reroute all domainname.com/affiliateXYZ visits to an AffController reroute action. But how?
The route element substring of 'affiliate' will be consistent and substring 'XYZ' will vary.
I would've preferred project requirements that had allowed domainname.com/aff/reroute/XYX (or domainname.com/aff/reroute/CigarKing) in the controller/action/parameter format, but alas.. tis not the case.
Initially I tried the following unsuccessfully:
Router::connect('/affiliate*', array('controller' => 'aff', 'action' => 'reroute'));
Router::connect('/affiliate**', array('controller' => 'aff', 'action' => 'reroute'));
Router::connect('/:controller*', array('controller' => 'aff', 'action' => 'reroute'), array('controller'=>'(affiliate)');
Once in the controller reroute action I will explode the affiliateXYZ into just 'XYZ' and then proceed with things I know how to do. My issue is routing to the controller with affiliateXYZ as the first routing element and at the same time not messing up current functionality.
I'd used Router::connect('/:affiliate', array('controller' => 'aff', 'action' => 'reroute'),array('pass'=>array('affiliate'))); to get to the info into the controller, until I saw the negative impact on preexisting controllers (I assume because I didn't explicitly list all other controllers, which I don't think I should have to do.).
How to route w/prefix ( more accurately a substring of 'affiliate' )?
I know prefix is the wrong terminology.
Thx, in advance.
You are looking for regular expression matching, with the help of this functionality you can define how specific route elements are matched.
This option is available for the third parameter of Router::connect().
You define it in element => regex format:
Router::connect(
'/:affilate',
array(
'controller' => 'aff',
'action' => 'reroute'
),
array(
'pass' => array('affilate'),
'affilate' => 'affilate[^/]+'
)
);
This would match any URL that starts with affilate, followd by 1 or more characters that are not a /.
See also http://book.cakephp.org/2.0/en/development/routing.html#route-elements

want to remove action name from url CakePHP

i am working on a Cakephp 2.x.. i want to remove the action or controller name from url ... for example i am facing a problem is like that
i have a function name index on my Messages controller in which all the mobile numbers are displaying
the url is
www.myweb.com/Messages
now in my controller there is a second function whose name is messages in which i am getting the messages against the mobile number
so now my url becomes after clicking the number is
www.myweb.com/Messages/messages/823214
now i want to remove the action name messages because it looks weired...
want to have a url like this
www.myweb.com/Messages/823214
When connecting routes using Route elements you may want to have routed elements be passed arguments instead. By using the 3rd argument of Router::connect() you can define which route elements should also be made available as passed arguments:
// SomeController.php
public function messages($phoneNumber = null) {
// some code here...
}
// routes.php
Router::connect(
'/messages/:id', // E.g. /messages/number
array('controller' => 'messages', 'action' => 'messages'),
array(
// order matters since this will simply map ":id"
'id' => '[0-9]+'
)
);
and you can also refer link above given by me, hope it will work for you.
let me know if i can help you more.
REST Routing
The example in the question looks similar to REST routing, a built in feature which would map:
GET /recipes/123 RecipesController::view(123)
To enable rest routing just use Router::mapResources('controllername');
Individual route
If you want only to write a route for the one case in the question
it's necessary to use a star route:
Router::connect('/messages/*',
array(
'controller' => 'messages',
'action' => 'messages'
)
);
Usage:
echo Router::url(array(
'controller' => 'messages',
'action' => 'messages',
823214
));
// /messages/823214
This has drawbacks because it's not possible with this kind of route to validate what comes after /messages/. To avoid that requires using route parameters.
Router::connect('/messages/:id',
array(
'controller' => 'messages',
'action' => 'messages'
),
array(
'id' => '\d+',
)
);
Usage:
echo Router::url(array(
'controller' => 'messages',
'action' => 'messages',
'id' => 823214 // <- different usage
));
// /messages/823214
in config/routes.php
$routes->connect('/NAME-YOU-WANT/:id',
['controller' => 'CONTROLLER-NAME','action'=>'ACTIOn-NAME'])->setPass(['id'])->setPatterns(['id' => '[0-9]+']
);
You can use Cake-PHP's Routing Features. Check out this page.

Cakephp route and prefix

I have a problem with Routes in CakePHP. Let me explain.
I'm using authentication through the Auth component. I have a routing prefix called account.
When I want to edit a user, I'm calling the users controller which gives me a URL like:
/account/users/edit/5
What I want is to have a URL like:
/account/edit/5
So I changed my router like this:
Router::connect('/:prefix/edit/:id',
array('controller' => 'users', 'action' => 'edit'),
array('pass' => array('id'), 'id' => '[0-9]+')
);
which worked when I try to access /account/edit/5
My problem is located in my view. How can I access this route using the Html->link helper?
So far, I'm just doing it like this:
'/'.$this->Session->read('Auth.User.role').'/edit/'.$this->Session->read('Auth.User.id')
But it's not really clean in my opinion. I want to use the helper.
Thanks a lot for your help
Using a prefix "account" would mean needing an action like "account_edit" in your controller. That's probably not what you want. Also why put the "id" in url when it's already there in the session? Why not just use url "/account" for all users and get the id (and role if required) from session in the action?
Router::connect('/account',
array('controller' => 'users', 'action' => 'edit')
);
This would be the clean way to generate required url:
$this->Html->link('Account', array(
'controller' => 'users',
'action' => 'edit'
));
// Will return url "/account"
In general always use array form to specify url to benefit from reverse routing.
everything is just fine except router. it should be
Router::connect('/account/*',
array('controller' => 'users', 'action' => 'edit')
);
and creating anchor link in various way using Helper you can CHECK HERE

Cakephp, Route old google search results to new home page

I have created a new website for a company and I would like all the previous search engine results to be redirected. Since there were quite a few pages and most of them where using an id I would like to use something generic instead of re-routing all the old pages.
My first thought was to do that:
Router::connect('/*', array('controller' => 'pages', 'action' => 'display', 'home'));
And put that at the very end of the routes.php file [since it is prioritized] so that all requests not validating with previous route actions would return true with this one and redirect to homepage.
However this does not work.
When I use a different path on the Router it redirects successfully. For example if I give it:
Router::connect('/*', array('controller' => 'projects', 'action' => 'browser'));
it works fine. The problem arises when the controller used is pages, action display etc.
I'm pasting my routes.php file [since it is small] hoping that someone could give me a hint:
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::connect('/company/*', array('controller' => 'articles', 'action' => 'view'));
Router::connect('/contact/*', array('controller' => 'contacts', 'action' => 'view'));
Router::connect('/lang/*', array('controller' => 'p28n', 'action' => 'change'));
Router::connect('/eng/*', array('controller' => 'p28n', 'action' => 'shuntRequest', 'lang' => 'eng'));
Router::connect('/gre/*', array('controller' => 'p28n', 'action' => 'shuntRequest', 'lang' => 'gre'));
Router::parseExtensions('xml');
Instead of trying to handle everything within the cakePHP route file, I would recommend that you use the .htaccess file to 301 redirect pages as necessary.
What you have above will not transfer the rankings over because as far as i can see there is no 301 redirect being outputted in any of the routes.php based solutions you proposed.
The bigger problem is that a Route doesn't redirect, it connects URLs with responses. In other words, it makes sure that your now invalid URLs still yield a valid page. Which is exactly the opposite of what you want to achieve.
You want to tell visitors that a URL that used to be valid isn't anymore. You do this by issuing appropriate HTTP response codes, 301 Moved Permanently in this case. Without doing this the URLs will still appear valid to search engines and they won't update their index.
You'd either have to connect all the invalid URLs via Routes to some controller action that'll issue a $this->redirect('...', 301) or you could use some .htaccess rules to redirect. Which one to use depends on the complexity of the redirect, but you'll probably be able to use simple .htaccess mod_rewrite rules.
There are enough examples on SO: https://stackoverflow.com/search?q=htaccess+301+redirect

Resources