Wednesday, February 2, 2011

Re: how to automatically generate a url when creating an object

On Tue, Feb 1, 2011 at 8:21 PM, barricades <davowave@googlemail.com> wrote:
> Hi,
>
> I'm using trying to learn php using cakephp (I know, I know).

You're either very self-confident, or foolish. ;-)

> I want to be able to allow users to create a page (which I call a
> 'campaign') that will end up at a url that consists of my domain +
> their first and last names. I've got an application all set up with
> regards users and campaigns and have all my tables and associations
> and everything set up and working I'm just having problems with this
> bit.
>
> So I've got a baked add function in my campaign_controller with the
> relevant view which consists of the form to enter all the details.
>
> How do I make one of those form fields end up as the above described
> url in the database while at the same time creating a page which you
> can go to if you clicked that url?

You need to use a slug, which is a hyphen- or underscore-separated
list of words made from a title and used in a URL. You'll see these a
lot on blogs.

So, the very simplest way to do it would be to have a Campaign.title
field. In the Campaign model:

public $actsAs = array(
'Sluggable' => array(
'translation' => 'utf-8',
'separator' => '-',
'label' => 'title',
'length' => 64,
'overwrite' => true
)
);

This loads SluggableBehavior, which will automatically translate your
title field to a slug (you'll also require a slug column in the DB, of
course).

In your form:

echo $this->Form->input('Campaign.title', array('label' => 'first and
last names'));

I figure there's little point in mucking about with an associated User
model and trying to create Campaign.slug from the User first & last
names, as you'll only be able to have a single User asociated with a
single Campaign, anyway.

In your CampaignsController:

public function view($slug = null) { ... }

You'd then run your find with 'conditions' => array('Campaign.slug' =>
$slug), of course.

The tricky part is that you don't want to have any qualifier in the
URL except the slug. By that, I mean something like:

http://foo.org/campaigns/foo-bar/

To do this without the 'campaigns' (or some other word) part:

Router::connect(
'/:slug',
array(
'controller' => 'campaigns',
'action' => 'view'
),
array(
'slug' => '[-a-z]+',
'pass' => array('slug')
)
);

Because the route begins with a slug, and the route will need to use a
regexp, this route will need to be the very last in routes.php.
Otherwise, it would match on just about any other request. There is
another way to do it, involving caching all the possible slugs and
loading a specific route for each, but I don't think you should go
there.

To create a link (let's say you've got a list of Campaign titles in $data):

foreach ($data as $d)
{
// other HTML ...
echo $this->Html->link(
$d['Campaign']['title'],
array(
'controller' => 'campaigns',
'action' => 'view'
'slug' => $d['Campaign']['slug']
),
array('title' => '...')
);
}

Notice that the slug is passed in the same array as the controller &
action, unlike with defining the route itself.

Good luck.

--
Our newest site for the community: CakePHP Video Tutorials http://tv.cakephp.org
Check out the new CakePHP Questions site http://ask.cakephp.org and help others with their CakePHP related questions.


To unsubscribe from this group, send email to
cake-php+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/cake-php

No comments: