Reputation: 28843
I want to create a link like: /favours/20201/This_is_a_favour
using both the id and the favour title.
I have set up the link like:
<h3><?php echo $this->Html->link($favour['Favour']['title'], array('controller'=>'favours','action'=>'view',$favour['Favour']['id'], Inflector::slug($favour['Favour']['title']))); ?></h3>
and the controller action SO FAR is:
function view ( $id, $title )
{
$favour = $this->Favour->find('first', array(
'conditions' => array('Favour.title' => $title)
));
if (empty($favour))
{
$this->cakeError('error404');
}
$this->set(compact('favour'));
}
Router::connect('/favours/:id/:favourName',array('controller'=>'favours','action'=>'view'),
array(
'favourName'=>'[A-Za-z0-9\._-]+',
'pass'=>array('favourName')
),
array('id' => '[0-9]+')
);
However I get a 404 at the moment?
NOTE: I don't want to use the sluggable plugin or store slugs in the DB!
Upvotes: 2
Views: 2285
Reputation: 522332
First you need to set up your route in routes.php
:
Router::connect('/favours/:id',
array('controller' => 'favors', 'action' => 'view'),
array('id' => '[0-9]+', 'pass' => array('id')));
Router::connect('/favours/:id/:slug',
array('controller' => 'favors', 'action' => 'view'),
array(
'id' => '[0-9]+',
'slug' => '[A-Za-z0-9\._-]+',
'pass' => array('id', 'slug')
));
Then I'd recommend to add a method to your Favour model that handles the creating of the :slug
parameter, since you'll have to use this from different places and you may want to change how exactly it works later:
public static function slug(array $favour) {
// good enough for now, might want to change this later
return Inflector::slug($favour['title']);
}
Then, whenever you make a link, do it like this:
array('controller' => 'favours', 'action' => 'view',
'id' => $favour['Favour']['id'], 'slug' => Favour::slug($favour['Favour']))
Your controller action simply looks like this:
public function view($id, $slug) {
$favour = $this->Favour->find('first', array('conditions' => array('Favour.id' => $id)));
if (!$favour) {
$this->cakeError('error404');
}
if (Favour::slug($favour['Favour']) != $slug) {
$this->redirect(array('id' => $id, 'slug' => Favour::slug($favour['Favour'])));
}
$this->set(compact('favour'));
}
Upvotes: 3
Reputation: 28843
function view ( $id = null, $slug = null )
{
$this->Favour->id = $id;
$this->set('favour', $this->Favour->read());
}
Router::connect('/favours/:id/:slug',array('controller'=>'favours','action'=>'view'),
array(
'pass' => array('id','slug'),
'id' => '[0-9]+'
)
);
<?php echo $this->Html->link($favour['Favour']['title'], array('controller'=>'favours','action'=>'view','id'=>$favour['Favour']['id'], 'slug'=>Inflector::slug($favour['Favour']['title']))); ?>
Upvotes: 0
Reputation: 21743
why so complicated? simply use canonical - thats what it is for
/controller/action/id/some-slugged-title
is the canonical link - but
/controller/action/id/
and
/controller/action/id/some-slugged-ti
and
/controller/action/id/some-slugged-title-blabla
would all work, too. via canonical the search engines know what the correct one is
SEO is fine here. And no additional redirect necessary (less server consuming). Additionally you will not get 404s if the slug/title change. this is a huge risk with many other solutions.
Upvotes: 0
Reputation: 327
Mark Story (core developer of CakePHP) writes up how to do what you want - a few minor tweaks from his article should get you there in good shape (don't be disheartened by the title of his post). http://mark-story.com/posts/view/using-custom-route-classes-in-cakephp
Upvotes: 0