Laravel父模型删除不会启动子模型删除事件

时间:2018-05-20 11:32:05

标签: laravel events model laravel-5.4

我正在使用laravel 5.4。我有一个项目模型作为父项目和project_images模型作为子项,这里是子模型:

Schema::create('project_images', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('project_id')->unsigned();
            $table->foreign('project_id')->references('id')->on('projects')->onDelete('cascade');
            $table->string('file', 100);
            $table->timestamps();
        });

所以,每当我删除一个项目时,它的所有图像记录都将被删除。然后我在图像模型中创建了一个删除事件,如下所示:

protected $events = [
    'deleted' => ProjectImageDeleting::class
];

如果我删除图像本身,那么这个事件也会激活,但是如果我删除了该项目,那么没有。

我的问题

我应该如何使这个工作当我删除父项时,子事件也会启动?我错过了什么吗? (我已经有了事件和监听器,当我删除图像时,侦听器中的代码可以工作)

更新

我在迁移中删除了该行,并将项目模型更改为:

namespace AliMHZ;

use Illuminate\Database\Eloquent\Model;

class Project extends Model
{
    public function images()
    {
        return $this->hasMany(ProjectImage::class);
    }

    protected static function boot()
    {
        parent::boot();
        static::deleting(function($project) {
            $project->images()->delete();
        });
    }
}

这是我的形象模型:

namespace AliMHZ;

use Illuminate\Database\Eloquent\Model;
use AliMHZ\Events\ProjectImageDeleting;

class ProjectImage extends Model
{
    protected $events = [
        'deleting' => ProjectImageDeleting::class
    ];
    public function project()
    {
        return $this->belongsTo(Project::class);
    }
}

和事件:

namespace AliMHZ\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use AliMHZ\ProjectImage;

class ProjectImageDeleting
{
    use Dispatchable,
        InteractsWithSockets,
        SerializesModels;

    public $image;
    public function __construct(ProjectImage $image)
    {
        $this->image = $image;
    }
    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}

最后这里是听众:

namespace AliMHZ\Listeners;

use AliMHZ\Events\ProjectImageDeleting;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class ProjectImageDeletingListener
{
    public function __construct()
    {
        //
    }
    public function handle(ProjectImageDeleting $event)
    {
        \Log::info("File to be deleted: " . $event->image->file);
    }
}

在这些更改之后,当我删除项目时,其所有图像也将被删除,但图像事件仍然不会启动,但如果仅删除图像,则事件有效。我正在用laravel修补器进行测试,每当我改变任何模型时,我都会退出修补匠并再次吃午饭。

1 个答案:

答案 0 :(得分:1)

当您使用$table->foreign('project_id')->references('id')->on('projects')->onDelete('cascade');时,删除操作在数据库级别完成,因此模型事件不会被触发。

要触发所有相关的模型事件,您必须手动在模型中为此编写代码。

<?php

class Project extends Eloquent
{
    public function images()
    {
        return $this->has_many('Image');
    }

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

        static::deleting(function($project) {
             // This will trigger the ProjectImageDeleting event.
             $project->images()->delete();
        });
    }
}

编辑回答问题的已编辑部分

您可以尝试以下

namespace AliMHZ;

use Illuminate\Database\Eloquent\Model;

class Project extends Model
{
    public function images()
    {
        return $this->hasMany(ProjectImage::class);
    }

    protected static function boot()
    {
        parent::boot();
        static::deleting(function($project) {
            $project->images()->get()->each(function ($image) {
                  $image->delete();
            });
        });
    }
}

如果您想详细了解原因,可以在this issue on GitHub上阅读。