0
votes

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)

2
what you mean with "it does not work"?Giacomo M
I am writing uniTests for deleting the user and when I delete the user, I get the error that the relation still exists. I will update the question thanksalex toader
You'll need to either alter the user_user migration so the to add onDelete('cascade') or onDelete('set null') to the constraint or use the eloquent deleting event.IGP
You have many-to-many relationship, that's why you can not delete the child.Giacomo M

2 Answers

1
votes

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.

1
votes

If you want to delete a child from a relationship without deleting the whole relationship you have to set the Foreing Key column in the parent table as nullable and to set it to null when the child is deleted. You can do this in the Laravel migrations like this:

Schema::create('parents', function (Blueprint $table) {
        $table->id();
        $table->foreignId('child_id')->nullable()->constrained('childs')->onDelete('set null');
        $table->string('name');
    });