Cameron
Cameron

Reputation: 28843

CakePHP: Friendly urls using inflector and no id

I have built a simple portfolio using CakePHP and it has urls like: domain.com/portfolio/82/This_is_an_item

What I want to do is remove the ID from the url. How would I do this?

Here is my controller code for the view:

function view ( $id, $slug )
{
    $post = $this->Portfolio->read(null, $id));

    $this->set(compact('post'));
}

and here is the link generator:

<?php echo $this->Html->link($post['Portfolio']['title'],
        array('admin' => false, 'controller' => 'portfolio', 'action' => 'view', $post['Portfolio']['id'], Inflector::slug($post['Portfolio']['title'])),
        array('title' => $post['Portfolio']['title'])); ?>

I'm guessing I need to change the controller method to do some sort of find on the title?

Any help would be much appreciated. Thanks

Upvotes: 1

Views: 2656

Answers (2)

Anh Pham
Anh Pham

Reputation: 5481

You can eliminate the id completely, but you'll have to make sure the slugs are unique (specify inUnique validation rule is a option). When saving the post, use Inflector::slug() on the 'title' field (you might want to save it to a 'slug' field, if you want to keep the title intact:

$this->data['Portfolio']['slug'] = Inflector::slug($this->data['Portfolio']['title'])

function view ($slug ){
   $post = $this->Portfolio->find('first', array('conditions'=>array('Portfolio.slug'=>$slug))));
   $this->set(compact('post'));
}

and for the link:

<?php echo $this->Html->link($post['Portfolio']['title'],
    array('admin' => false, 'controller' => 'portfolio', 'action' => 'view', $post['Portfolio']['slug']),
    array('title' => $post['Portfolio']['title']));

Upvotes: 1

Arjan
Arjan

Reputation: 9884

I would save the slug in the database, along with the title. That way you only have to create it once. Also you may or may not be able to get a unique link from slug to title, so it's best not to try.

For easy processing you can use the Sluggable behaviour, see https://gist.github.com/338096 (or just Google).

Update

If you use the sluggable behaviour from https://gist.github.com/338096 (save as sluggable.php in app/model/behaviors), you would only need to do a few steps:

In your Profile model class add var $actsAs = array('Sluggable'); or

var $actsAs = array(
    'Sluggable' => array(
        'fields' => 'title',
        'scope' => false,
        'conditions' => false,
        'slugfield' => 'slug',
        'separator' => '-',
        'overwrite' => false,
        'length' => 256,
        'lower' => true
    )
);

if you want to override settings

In the database, add a column slug in the profiles table.

When you save a profile, it will automagically add fill in the slug field, you do not need to take any special actions.

Upvotes: 2

Related Questions