Search code examples
phplaraveleloquenteloquent-relationship

How to detach parents from child before deleting the child? (Laravel Eloquent)


I have a parent child relation in users.

I want to delete a child. But before that, I need to remove all references from the parents to the child.

I was expecting this to work - but is not:

$child->superiorUsers()->detach($child->id);

$child->delete();

The superiorUsers() looks like this:

public function superiorUsers()
{
    return $this->belongsToMany(
        'App\Models\User',
        'user_user',
        'user_id',
        'superior_id'
    );
}

Any idea what I am doing wrong please?

Edit: I am writing unitTests to delete the user and I am getting the error that the relation is still there.

SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (user_user, CONSTRAINT user_user_user_id_foreign FOREIGN KEY (user_id) REFERENCES users (id)) (SQL: delete from users where id = xxx)


Solution

  • Create a new migration to alter the foreign key constraint

    Schema::table('user_user', function (Blueprint $table) {
        $table->dropForeign(['user_id']);
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    });
    

    This will mean that if a user is deleted, any records on user_user with the deleted user_id will be deleted as well.

    Another option is onDelete('set null') so the field is only changed to be null.


    Another option is to use the User's deleting event.

    # User model
    
    protected static function booted()
    {
        static::deleting(function ($user) {
            $user->superiorUsers()->sync([]);
            $user->inferiorUsers()->sync([]);
        });
    }
    
    public function superiorUsers()
    {
        return $this->belongsToMany(
            'App\Models\User',
            'user_user',
            'user_id',
            'superior_id'
        );
    }
    
    public function inferiorUsers()
    {
        return $this->belongsToMany(
            'App\Models\User',
            'user_user',
            'superior_id',
            'user_id'
        );
    }
    

    But in my opinion, if you're not using soft deletes this kind of logic is better left to the database.