Thursday 10 April 2008

HABTM Relationship building in CakePHP

Yeah, I know its not as good as rails, but i'm trying to get to grips with it anyway: CakePHP. I'm gonna start using this blog as a way of keeping a note of things I learn as I build my first apps - mainly for my own benefit, but also to help the active and very friendly CakePHP community. Documentation for 1.2 is currently shocking, so it takes a lot of trawling to get what you need - so I need my own reference.

That said, heres my first nugget of gold.

Has And Belongs To Many (HABTM) relationships are great, but manipulating those relationships is hard. If you want to create a new object, and save relationships to it a the moment of creation, I found it hard to work out how to do both at the same time. Turns out its all about how you push data into $this->data and then pass this to be saved.

I needed to create a new Bulletin object, tie the current logged in user to it, and fill it with 5 (currently random) news stories which already exist. First I found the user_id of the current user and added that relationship to the Bulletin object using...

$this->Bulletin->create();
$user = $this->Auth->user('id');
$this->data->Bulletin->user_id = $user;

Then I got an array of the stories I wanted to attach (currently 5 random ones). Then, heres the tricky part, I had to extract their arrays, as the data findAll() returns can't be shoved into $this->data. Instead, $this->data wants an array of IDs which it can save. To do this, I did it messily....

$stories=array();
$this->Bulletin->Story->recursive = 0;
$stories = $this->Bulletin->Story->findAll(null, null, 'RAND()', 5);
$story_ids = array();
foreach($stories as $story){
$story_ids[] = $story["Story"]['id'];
}
$this->data->Story->Story = $story_ids;

Now that $this->data contains everything we want, we can just save it as normal by passing $this->data to the $this->save() method.

if($this->Bulletin->save($this->data)){
$this->Session->setFlash('A new bulletin has been generated for you');
$this->redirect('/bulletins/view/'.$this->Bulletin->id);
}else{
$this->Session->setFlash("There was an error building your bulletin");
$this->redirect('/bulletins');
}

Voila. This works nice. I hit a url like /bulletin/generate, and the system generates a random Bulletin object for me, and redirects me to its view page. Its a bit hacky tho, so any suggestions would be greatfully received.

No comments: