Cameron
Cameron

Reputation: 28843

CakePHP Using both Id and Title in URL

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

Answers (4)

deceze
deceze

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

Cameron
Cameron

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

mark
mark

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

Ram
Ram

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

Related Questions