5

I am using CakePHP 1.3. I have a Product model. on the DB table among others there are id and slug fields.

If I have a product that is id:37 and slug:My-Product-Title I want the URL for the product to be:

products/37/My-Product-Title

Instead of the standard:

products/view/37

I created a route that looks like this:

Router::connect(
    '/products/:id/:slug',
    array('controller' => 'products', 'action' => 'view'),
    array('pass' => array('id'), 'id' => '[0-9]+')
);

Now I can go to http://server/products/37/My-Product-Title and it takes me to the right place.

But How do I get reverse routing to automatically build the correct URL in $HtmlHelper->link?

When I use:

echo $html->link(
    'Product 37', 
    array('controller'=>'products', 'action' => 'view', 37)
);

It still outputs the standard products/view/37 url.

JD Isaacks
  • 56,088
  • 93
  • 276
  • 422
  • I know this isn't directly relevant, but I suggest having a look at the section on slugs in pseudocoder's cakephp book (http://www.pseudocoder.com/archives/free-cakephp-e-book-super-awesome-advanced-cakephp-tips) if you haven't seen it. – Tomba Feb 25 '11 at 15:11

4 Answers4

5

I don't believe that it's possible to be done auto-magically. The helper is just an "helper" who builds the link from the given parameters.

So the easiest method is to add another parameter in your link like so:

echo $html->link(
    'Product 37', 
    array('controller'=>'products', 'action' => 'view', 37, $slug)
);

where the $slug is the data from the slug field.

Probably it could be done your idea, but you need to break the MVC pattern very badly :)

Edit:

Reading your question again I understood it well. See how should be done:

in your router.php add the following rule:

Router::connect(
    '/product/*',
    array('controller' => 'products', 'action' => 'view')
);

Please note that it's /product/* rather than /products/*

Your link should be done like this:

echo $html->link(
    'Product 37', 
    array('controller'=>'products', 'action' => 'view', 37, 'my-product-title')
);

and the link would look like:

http://yourdomain.com/product/37/my-product-title

For me doing your suggestion is bad practice. Also I don't think it's good from SEO point of view redirecting always the user.

Nik Chankov
  • 6,049
  • 1
  • 20
  • 30
  • Unfortunately this builds the URL as `/products/view/37/my-product-title` I don't want the *view* in there. It does work if I pass `array('controller'=>'products', 'action' => 37, 'my-product-title')` but it feels wrong. – JD Isaacks Feb 25 '11 at 14:07
3

For routing:

Router::connect(
    '/products/:id/:slug',
    array('controller' => 'products', 'action' => 'view'),
    array('pass' => array('id'), 'id' => '[0-9]+')
);

Your links should look like this:

echo $html->link(
    'Product 37', 
    array('controller'=>'products', 'action' => 'view', 'id' => 37, 'slug' => 'my-product-title')
);

You have to add additional (key => value) to your array for each :param in your routing. Then magic will work

  • Actually I'm not sure if that's the answer to the given question, but it's at least exactly what I was looking for =) Thanks! – cbix Jun 13 '12 at 19:24
0

You should look at the following post regarding custom route classes.

The slug data doesn't need to be involved with the database at all - the field is a fake field used to simplify logic and lookups. This solution allows you to reverse route slugs, without needing a slug field in the models table.

http://42pixels.com/blog/slugs-ugly-bugs-pretty-urls

Abba Bryant
  • 4,012
  • 22
  • 18
  • agreed with you that if the urls are in the format used above the slug is just for SEO. – Nik Chankov Feb 25 '11 at 10:56
  • And it is flexible enough to use as a base for using as a base if you want a different format. The thing is, a slug is always a computed field and as such doesn't need to be stored as it can be calculated on the fly. – Abba Bryant Mar 01 '11 at 19:03
-1

I am not sure how bad this is but with the following code in the ProductsController:

function view($id)
{
    if( isset($_SERVER) && stristr($_SERVER["REQUEST_URI"],'view/') )
    {
        $this->Product->id = $id;
        $slug = $this->Product->field('slug');
        $this->redirect($id.'/'.$slug);
    }
    $data = $this->Product->find('first', array('conditions' => array('Product.id' => $id)));
    $this->set("data", $data);
}

If the page is accesses via /view/id it automatically redirects them to the current page using /id/slug

Now I can just use the default link scheme:

echo $html->link(
    'Product 37', 
    array('controller'=>'products', 'action' => 'view', 37)
);

and they will be redirected to the right URL.

Only problem is I am not sure how bad it is to have a redirect happening every time a user visits a product page?

JD Isaacks
  • 56,088
  • 93
  • 276
  • 422