Andrea
Andrea

Reputation: 20503

Working with related model in CakePHP

This is a fairly basic question about CakePHP, but since my knowledge of this framework is rather rusty, it is making me lose a lot of time.

I have a ManyToMany relation between Guest and Present. Whenever a new Guest is created and associated with a present, I would like to mark the Present as taken. If the present is already taken, some error should arise. The reason why I am not just declaring that a Guest hasMany Presents is because in the future things may change and more than one guest could associate to a present, so I prefer to avoid a Db migration.

My Guest::add() action looks like follows. It is called with a POST with the data of a new Guest and the id of an existing Present.

public function add() {
    if ($this->request->is('post')) {
        $id = $this->request->data['Present']['id'];
        $this->Guest->create();
        $present = $this->Guest->Present->findById($id);
        if ($present['Present']['taken']) {
            throw new ForbiddenException();
        }

        if ($this->Guest->save($this->request->data)) {
            if ($this->Guest->Present->saveField('taken', true)) {
                 // Give the guest a uuid and proceed with a welcome message
                 $this->Guest->read();
                 $this->set('uuid', $this->Guest->data['Guest']['uuid']);
            }
        }

    }
    else {
        throw new ForbiddenException();
    }
}

What happens is that a new Guest is created (correct) and associated with the given present (correct) but when I save the taken field a new present is created instead of modifying the given one.

What is the correct way to proceed to update the current Present?

If it is of any help, I am using CakePHP 2.0

Upvotes: 1

Views: 106

Answers (2)

Joni
Joni

Reputation: 111389

For obtaining the model data by the primary key it's better to use theIn addition read method:

    $present = $this->Guest->Present->read(null, $id);

The read method sets the model's id attribute so that further calls to other methods affect the same data record, rather than creating a new one. This should solve the problem you are having.

Model callbacks tend to be better suited for these situations. You could add a beforeSave callback to the Guest class to checks if the present is already taken, and not allow the creation if it is. This way the model logic is left in the model layer and you don't need to do any extra work e.g. if the constraint has to be enforced also when existing Guests are saved, or created from different controllers or actions.

Upvotes: 2

Chuck Burgess
Chuck Burgess

Reputation: 11575

It sounds like the ID of the model you are trying to save is losing scope. You should be able to resolve your issue by updating your code:

...
if ($this->Guest->save($this->request->data)) {
    $this->Guest->Present->id = $id;
    if ($this->Guest->Present->saveField('taken', true)) {
...

Upvotes: 1

Related Questions