wordy
wordy

Reputation: 173

Conditional associated record deletion in afterDelete()

I have the following setup:

Models:

Team
Task
Change
TasksTeam

TasksTeam is a hasManyThrough, that associates teams to tasks. Change is used to record changes in the details of tasks, including when teams are attached/detached (i.e. through records in TasksTeam).

TasksTeam also cascades deletes of Task. If a task is deleted, all related team associations should also be deleted.

When a TasksTeam is deleted, it means a team has left a task, and I'd like to record a Change for that. I'm using the TasksTeam afterDelete() to record teams leaving. In the TasksTeam beforeDelete I save the data to $this->predelete so it'll be available in the afterDelete().

Here is the non-working code in TasksTeam:

public function afterDelete(){
    $team_id = $this->predelete['TasksTeam']['team_id'];
    $task_role_id = $this->predelete['TasksTeam']['task_role_id'];
    $task_id = $this->predelete['TasksTeam']['task_id'];

    // Wanted: only record a change if the task isn't deleted
    if($this->Task->exists($task_id)){
        $this->Task->Change->removeTeamFromTask($task_id, $team_id, $task_role_id);    
    }    
    return true;
}

Problem:

When a task is deleted, the delete cascades to TasksTeam correctly. However, a change will be recorded even if the Task is deleted. From another answer to something similar on SO, I think the reason is that the callbacks are called before Model:del(), meaning the task hasn't yet been deleted when it hits TasksTeam afterDelete()

Question

How can I successfully save a Change only if the task isn't deleted?

Thanks in advance.

Upvotes: 1

Views: 65

Answers (2)

wordy
wordy

Reputation: 173

Using the suggestion from @James Dunne I ended up adding a tinyint field to the Task model called is_deleted and simply set this boolean true in the Task beforeDelete(). I then check for this flag and only save a Change if the flag is boolean false. It seems wasteful to add a field for something that is only affected just before the record is deleted, but for my purposes it works fine. I think a "real solution" would involve the Cake Events System , avoiding the need for chained callbacks.

Upvotes: 0

James Dunne
James Dunne

Reputation: 770

If the callbacks are getting called before the actual delete, I see maintaining an assoc. array of flags with task IDs as keys, or a set of task IDs, which are added when afterDelete is called on Task. Then you could create a method in Task, such as isDeleting or similar, which queries the array, to tell you if the task is in the process of being deleted.

Upvotes: 1

Related Questions