Laravel 删除父模型不会触发子模型删除事件

Laravel parent model deletion doesn't fire up child model deleting event

我正在使用 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();
        });

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

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 tinker 中对此进行测试,每次我更改任何模型时,我都会退出 tinker 并再次午餐。

当您使用 $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 上阅读。