在Laravel 5.4中执行批量删除语句时,如何根据Eloquent'删除'事件执行操作?

时间:2017-07-25 14:06:31

标签: php laravel eloquent

我的项目中有2个Eloquent模型:App\StoredFileApp\StoredImageSize

StoredFile模型负责保留上传的文件信息。如果上传的文件是图像,那么2个缩略图将存储在存储中,其属性将存储在DB(StoredImageSize模型)中。

关系如下:

StoredFile.php:

public function sizes()
{
    return $this->hasMany('App\StoredImageSize');
}

StoredImageSize.php:

public function originalImage()
{
    return $this->belongTo('App\StoredFile');
}

StoredImageSize有一个观察者类(StoredImageSizeObserver),它已通过ServiceProvider注册并运行良好。

问题是我想从数据库中删除后续行时从存储中删除实际文件(在我的情况下是硬盘)。

StoredImageSizeObserver.php:

public function deleting(StoredImageSize $file)
{
    Storage::delete($file->server_url);
}

逻辑是这样的:

$file = StoredFile::find(1);
$file->sizes()->delete();    // it does delete all related rows from 'StoredImageSize' but not files from storage
$file->delete()

实际上它永远不会从deleting类点击StoredImageSizeObserver方法,因为Laravel documentation说:

  

通过Eloquent执行批量删除语句时,不会为已删除的模型触发删除和删除的模型事件。这是因为在执行delete语句时,实际上从未检索过模型。

那么,我该如何应对这种情况呢?任何解决方案或建议将不胜感激。

2 个答案:

答案 0 :(得分:3)

StoredFile模型中添加以下方法,您有两个选择:

  • 第一个:

    protected static function boot() {
        parent::boot();
        static::deleting(function(StoredFile $fileToDelete) {
            foreach ($fileToDelete->sizes as $size)
            {
                $size->delete();
            }
    
            $fileToDelete->delete()
        });
    }
    
  • 第二个:

    protected static function boot() {
        parent::boot();
        static::deleting(function(StoredFile $fileToDelete) {
            $size_ids = $fileToDelete->sizes()->lists('id');
            StoredImageSize::whereIn($size_ids)->delete();
    
            $fileToDelete->delete()
        });
    }
    

或者为StoredFile模型创建一个观察者而不是StoredImageSize,因为正如您所说的那样,删除事件不会为StoredImageSize元素级联!并在deleting的{​​{1}}方法中执行与上述相同的操作:)

答案 1 :(得分:1)

假设App\StoredImageSize引用了磁盘上的物理文件

$file = StoredFile::find(1);
foreach($file->sizes as $size){
    Storage::delete($size->file_location);
}
$file->sizes()->delete();
$file->delete()