7

Is this even possible? In every tutorial that I read there is nothing about deleting, only selecting and inserting related models.

This is my problem:

I have three levels of nesting. I have classes Package, Level, Lesson and Phase, and their models are below. First one - packages:

class Package extends Eloquent  {

protected $table = 'packages';
public $timestamps = false;

public function levels(){
    return $this->hasMany('Level', 'package_id');
}

}

Levels:

class Level extends Eloquent  {

protected $table = 'levels';

public function lessons(){
    return $this->hasMany('Lesson', 'level_id');
}

public function package(){
    return $this->belongsTo('Package', 'package_id');
}

}

Lessons:

class Lesson extends Eloquent {

protected $table = 'lessons';

public function phases(){
    return $this->hasMany('Phase', 'lesson_id');
}

public function level(){
    return $this->belongsTo('Level', 'level_id');
}

}

What I'm trying to do here is to when deleting one package i delete all levels related to it and also to delete all lessons related to those levels.

I have tried couple of options and they were all wrong, I just don't know how to do this without making a bunch of queries in foreach loop. Please, give some advice I'm so desperate I'm thinking about tweet to Jeffrey Way and ask him for the solution :) Thanks in advance

Nikola Sicevic
  • 73
  • 1
  • 1
  • 6

2 Answers2

8

You can approach this in two ways:

  1. Leverage the database to do the deleting for you. You'd add something like this to your migrations for the lessons, levels and packages, respectively:

     $table->foreign('level_id')->references('id')->on('levels')->onDelete('cascade');
    
     $table->foreign('lesson_id')->references('id')->on('lessons')->onDelete('cascade');
    
     $table->foreign('package_id')->references('id')->on('packages')->onDelete('cascade');
    
  2. You can overwrite the delete method on each model to delete all of its relationships:

    class Lesson extends Eloquent {
    
        protected $table = 'lessons';
    
        public function phases(){
            return $this->hasMany('Phase', 'lesson_id');
        }
    
        public function level(){
            return $this->belongsTo('Level', 'level_id');
        }
    
        public function delete()    
        {
            DB::transaction(function() 
            {
                $this->level()->delete();
                $this->phases()->delete();
                parent::delete();
            });
        }
    
    }
    
edpaez
  • 1,593
  • 1
  • 12
  • 22
  • One thing to take into consideration about the second approach: it might be wise to wrap the call to `delete()` in a transaction, to avoid having inconsistencies if any of the queries fail. – Bogdan Dec 03 '14 at 14:45
  • Definitely a good idea **@Bogdan**. Edited to include the transaction – edpaez Dec 03 '14 at 15:02
  • 1
    Worth noting: 1st option won't work with `softDeletes` at all, and 2nd won't use `softDeletes` (it will run raw delete). – Jarek Tkaczyk Dec 03 '14 at 16:14
  • Thank you @edopaez I used your solution. First i had to dive into migrations a bit and thank you for that also because I know more now that before your post :) sorry I'm late with response btw – Nikola Sicevic Dec 17 '14 at 15:48
0

I think you can use foreign keys with drop cascade in your case. I haven't worked with Laravel's ORM yet, but there is a section in documentation that describes how to create foreign keys in migration.

Or you can try the technique suggested in this answer. The idea is to override the delete method and force the deletion of related objects.

Community
  • 1
  • 1
Alexander Guz
  • 1,334
  • 12
  • 31