Automatically deleting related rows in Laravel (Eloquent ORM)

后端 未结 13 1721
半阙折子戏
半阙折子戏 2020-11-22 17:03

When I delete a row using this syntax:

$user->delete();

Is there a way to attach a callback of sorts, so that it would e.g. do this auto

相关标签:
13条回答
  • 2020-11-22 17:47

    Note: This answer was written for Laravel 3. Thus might or might not works well in more recent version of Laravel.

    You can delete all related photos before actually deleting the user.

    <?php
    
    class User extends Eloquent
    {
    
        public function photos()
        {
            return $this->has_many('Photo');
        }
    
        public function delete()
        {
            // delete all related photos 
            $this->photos()->delete();
            // as suggested by Dirk in comment,
            // it's an uglier alternative, but faster
            // Photo::where("user_id", $this->id)->delete()
    
            // delete the user
            return parent::delete();
        }
    }
    

    Hope it helps.

    0 讨论(0)
  • 2020-11-22 17:48

    There are 3 approaches to solving this:

    1. Using Eloquent Events On Model Boot (ref: https://laravel.com/docs/5.7/eloquent#events)

    class User extends Eloquent
    {
        public static function boot() {
            parent::boot();
    
            static::deleting(function($user) {
                 $user->photos()->delete();
            });
        }
    }
    

    2. Using Eloquent Event Observers (ref: https://laravel.com/docs/5.7/eloquent#observers)

    In your AppServiceProvider, register the observer like so:

    public function boot()
    {
        User::observe(UserObserver::class);
    }
    

    Next, add an Observer class like so:

    class UserObserver
    {
        public function deleting(User $user)
        {
             $user->photos()->delete();
        }
    }
    

    3. Using Foreign Key Constraints (ref: https://laravel.com/docs/5.7/migrations#foreign-key-constraints)

    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    
    0 讨论(0)
  • 2020-11-22 17:48

    As of Laravel 5.2, the documentation states that these kinds of event handlers should be registered in the AppServiceProvider:

    <?php
    class AppServiceProvider extends ServiceProvider
    {
        /**
         * Bootstrap any application services.
         *
         * @return void
         */
        public function boot()
        {
            User::deleting(function ($user) {
                $user->photos()->delete();
            });
        }
    

    I even suppose to move them to separate classes instead of closures for better application structure.

    0 讨论(0)
  • 2020-11-22 17:50

    Relation in User model:

    public function photos()
    {
        return $this->hasMany('Photo');
    }
    

    Delete record and related:

    $user = User::find($id);
    
    // delete related   
    $user->photos()->delete();
    
    $user->delete();
    
    0 讨论(0)
  • 2020-11-22 17:51

    You can use this method as an alternative.

    What will happen is that we take all the tables associated with the users table and delete the related data using looping

    $tables = DB::select("
        SELECT
            TABLE_NAME,
            COLUMN_NAME,
            CONSTRAINT_NAME,
            REFERENCED_TABLE_NAME,
            REFERENCED_COLUMN_NAME
        FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
        WHERE REFERENCED_TABLE_NAME = 'users'
    ");
    
    foreach($tables as $table){
        $table_name =  $table->TABLE_NAME;
        $column_name = $table->COLUMN_NAME;
    
        DB::delete("delete from $table_name where $column_name = ?", [$id]);
    }
    
    0 讨论(0)
  • 2020-11-22 17:56

    I believe this is a perfect use-case for Eloquent events (http://laravel.com/docs/eloquent#model-events). You can use the "deleting" event to do the cleanup:

    class User extends Eloquent
    {
        public function photos()
        {
            return $this->has_many('Photo');
        }
    
        // this is a recommended way to declare event handlers
        public static function boot() {
            parent::boot();
    
            static::deleting(function($user) { // before delete() method call this
                 $user->photos()->delete();
                 // do the rest of the cleanup...
            });
        }
    }
    

    You should probably also put the whole thing inside a transaction, to ensure the referential integrity..

    0 讨论(0)
提交回复
热议问题