Home > Enterprise >  Deleting a model and all references to it in his relationships in Laravel
Deleting a model and all references to it in his relationships in Laravel

Time:06-10

I'm still new to Laravel and Eloquent but joining on a project previously built.

I have a User model that have many relationships like for example Actions(HasMany), Roles(BelongsToMany), Type(BelongsTo),..and many others...

What I want to do is to delete an User model and it's data and when I'm doing it, deleting all traces of him in his relations but not the content itself, basically I want to keep his relations models (Actions, Roles, Type,...) in my database but deleting his FK so that it cannot be linked to my user anymore while keeping the entry previously associated to him.

I tried a few things without success like

$user = User::findOrFail($id)
$user->delete();
// This one giving me a SQLSTATE[23000] The DELETE statement conflicted with the REFERENCE constraint 

$user->actions()->detach()
// or
$user->actions()->dissociate()
// But undefined for HasMany relations

and I was wondering if there was a "clean" and simple way to do it other than updating all those Foreign_Keys to a "NULL" value in each of the relationships

$user->userActions()->update(['id_user' => null]);
$user->userRoles()->update(['id_user' => null]);
//...and on and on... before being able to do a 
$user->delete();

I hope I was clear enough.

Thanks.

CodePudding user response:

If you are using Hard Delete, I recommand using the ondelete set null :

Schema::table('roles', function (Blueprint $table) {
    $table->unsignedInteger('id_user')->nullable();
    $table->foreign('id_user')->references('id')->on('users')->onDelete('set null');
});

Schema::table('actions', function (Blueprint $table) {
    $table->unsignedInteger('id_user')->nullable();
    $table->foreign('id_user')->references('id')->on('users')->onDelete('set null');
});

No need for model event or managing it yourself, mysql is managing everything for you

CodePudding user response:

You must delete all related records first , then delete the record itself :

$user = User::findOrFail($id);

$user->actions()->detach();

$user->delete();

or you may register closures that execute when various model events are dispatched. Typically, you should register these closures in the booted method of your model :

<?php
 
namespace App\Models;
 
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    protected static function booted()
    {
        static::deleting(function ($user) {
            $user->actions()->detach();
        });
    }
}

Reference

CodePudding user response:

You can delete the user as:

$user = User::findOrFail($id)
$user->delete();

The problem here is that, you don't want to delete all the information from the user in the other tables. In SQL you define Foreign Keys specially for this purpose so you don't have data in the table that is "lost in space" because it does not relate to anything. This builds (space) the tables with information that is difficult to access because it's not related to nothing.

For that purpose usually people use "ON DELETE CASCADE" to delete all reference (related by FK) in the other tables. If you don't have this you have to manually delete the information in other tables before deleting the user.

My recommendation is rethink why you want to remove the user and keep the data, if you want to keep the data just disable the user, at the end of the day you will want to know the information of the user for the data in the other tables.

I hope this can help and clarify your issue.

  • Related