2

I am using Laravel 4.1 and am attempting a cascading delete. I am doing this as some of the delete methods remove associated assets stored on S3, so relying on DB cascade delete is not suitable.

Say I have an Entry model which itself has an image and many associated Option's which also have images as shown below (cut down for brevity).

class Entry extends Eloquent {
    public function image()
    {
        return $this->morphOne('Image', 'imageable');
    }

    public function options()
    {
        return $this->hasMany('Option');
    }

    protected static function boot() {
        parent::boot();

        static::deleting(function($entry) {
            $image = $entry->image;
            if($image !== null) {
                $image->delete();
            }

            $entry->options()->delete()
            //Option::where('entry_id', $entry->id)->delete(); This also doesn't work
        });
    }
}

class Option extends Eloquent {

    public function entry()
    {
        return $this->belongsTo('Entry');
    }

    public function image()
    {
         return $this->morphOne('Image', 'imageable');
    }

    protected static function boot() {
        parent::boot();

        static::deleting(function($option) {
            Log::info('Trying to delete an option object');
            $image = $option->image;

            if($image !== null) {
                $image->delete();
            }
        });
    }
}

Note : I am doing the delete as recommended in this answer.

When I call $entry->delete() it will delete the image and the entry itself however the delete handler is never called on the options (I don't see it output to the log). However if instead I use the following in the Entries deleting function everything works fine.

foreach($entry->options as $option) {
    $option->delete();
}

Why doesn't $entry->options()->delete() work? Is this a bug in Laravel or have I made a mistake.

Community
  • 1
  • 1
cubiclewar
  • 1,569
  • 3
  • 20
  • 37

2 Answers2

2
class Entry extends Eloquent {
    public function image()
    {
        return $this->morphOne('Image', 'imageable');
    }

    public function options()
    {
        return $this->hasMany('Option');
    }

    protected static function boot() {
        parent::boot();

        static::deleting(function($entry) {
            $image = $entry->image;
            if($image !== null) {
                $image->delete();
            }

            $entry->options->each(function($option) {
                $option->delete();
            });
            //Option::where('entry_id', $entry->id)->delete(); This also doesn't work
        });
    }
}

you can use "each" http://laravel.com/docs/eloquent#collections

alioygur
  • 5,324
  • 5
  • 35
  • 37
  • I have tried using each however I don't think it is much different from using a foreach, you still need to iterate through each object. I am more curious as to why the $entry->options()->delete does not work – cubiclewar Mar 28 '14 at 22:03
0

There is a good package that handles this as an alterantive to the Boot method above and for soft delete.

Write Up: https://medium.com/asked-io/cascading-softdeletes-with-laravel-5-a1a9335a5b4d

Laravel/Lumen Soft Cascade Delete & Restore https://github.com/Askedio/laravel-soft-cascade

ejntaylor
  • 1,900
  • 1
  • 25
  • 43