views:

54

answers:

3

When I save data in one model, I'd like to create some data in another model and save that too. Because I can't do this using beforeSave(), I eventually decided to use afterSave() to create new data items in my second model. I'm not writing a blog application, but to use the blog analogy it's equivalent to automatically creating a series of comments for every blog post that is added and, when a post is edited, deleting all comments and re-adding new comments:

class Post extends AppModel {
    function afterSave() {
        ClassRegistry::init('Comments')->deleteAll(array('Post.id' => $this->id));
        ClassRegistry::init('Comments')->saveAll($comments); // comments contains the comments to be added
    }
}

This works fine, apart from the fact that the afterSave() function causes the redirection from my controller's add/edit actions (to /posts/index) to be overruled, and I get redirected back to the add/edit form instead (if I comment out the entire afterSave() method, the redirection works as intended).

If you're wondering why I didn't put the logic in the controller, I did originally, but I want it to work for both add and edit actions, and also for a "batch" add action I use to add multiple "posts" at once.

I guess I have two questions:

  • Is there a better way to achieve this kind of result?

  • How can I make the redirection work?

Thanks for reading this far and if I haven't explained it clearly I hope you can use your imagination to see what I'm trying to do.

A: 

I think you need to include return true at the end of your afterSave() function. This seems like a decent approach if you don't want to put it in the controller. Although I would think about whether you will always want to add these comments (or whatever they are) after every save, even single-field updates.

handsofaten
thanks for the suggestion, but including return true doesn't change anything.
Tomba
A: 

In the (somewhat unlikely) event that someone else has the same problem, I eventually found that setting

'atomic' => false

in the saveAll() options solves the problem with the redirect. I have no idea why.

Tomba
(all my database tables are InnoDB)
Tomba
I may end up putting the logic back in the controller eventually, but for the moment I'm leaving it in the model afterSave() function as described here, and it's all working fine. If I move it to the controller I might change the accepted answer.
Tomba
A: 

You can't do?:

<?php
function edit_post($id = null) {
    if (!$id && empty($this->data)) {
        // error...
    }       
    if (!empty($this->data)) {
        if ($this->Post->save($this->data)) {
            ClassRegistry::init('Comments')->deleteAll(array('Post.id' => $this->Post->id));
            ClassRegistry::init('Comments')->saveAll($comments); // comments contains the comments to be added
        } else {
            // error...
        }
    }       
    if (empty($this->data)) {
        $this->data = $this->Post->read(null, $id);
    }
}
?>
Cristian Deluxe
I could do it in the controller (I've tested it and it works) but I'd rather put it in the model, for various reasons including avoiding duplication of code for add/edit/batch add actions.
Tomba
You can also put it in the model, just replace $this->Post->save() for $this->save() and put in in your model add/edit/batch function.
Cristian Deluxe