当我使用以下语法删除一行时:

$user->delete();

是否有一种方法来附加一个类型的回调,这样它就会自动这样做:

$this->photo()->delete();

最好是在模型类内部。


当前回答

是的,但是正如@supersan在上面的评论中所说,如果你在QueryBuilder上删除(),模型事件将不会被触发,因为我们没有加载模型本身,然后在该模型上调用delete()。

只有在模型实例上使用delete函数时,才会触发事件。

所以,有人说:

if user->hasMany(post)
and if post->hasMany(tags)

为了在删除用户时删除post标签,我们必须遍历$user->个帖子,并调用$post->delete()

Foreach ($user->posts as $post) {$post->delete();} ->这将在Post上触发删除事件

VS

$user->posts()->delete() ->这将不会在post上触发删除事件,因为我们实际上没有加载post模型(我们只运行SQL: delete *从user_id = $user->id的帖子,因此,post模型甚至没有加载)

其他回答

有3种方法可以解决这个问题:

1. 在模型引导上使用雄辩事件(参考:https://laravel.com/docs/5.7/eloquent#events)

class User extends Eloquent
{
    public static function boot() {
        parent::boot();

        static::deleting(function($user) {
             $user->photos()->delete();
        });
    }
}

2. 使用雄辩的事件观察者(参考:https://laravel.com/docs/5.7/eloquent#observers)

在你的AppServiceProvider中,像这样注册观察者:

public function boot()
{
    User::observe(UserObserver::class);
}

接下来,添加一个Observer类,如下所示:

class UserObserver
{
    public function deleting(User $user)
    {
         $user->photos()->delete();
    }
}

3.使用外键约束(参考:https://laravel.com/docs/5.7/migrations#foreign-key-constraints)

$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

我将遍历集合,在删除对象本身之前分离所有内容。

这里有一个例子:

try {
        $user = User::findOrFail($id);
        if ($user->has('photos')) {
            foreach ($user->photos as $photo) {

                $user->photos()->detach($photo);
            }
        }
        $user->delete();
        return 'User deleted';
    } catch (Exception $e) {
        dd($e);
    }

我知道这不是自动的,但很简单。

另一种简单的方法是为模型提供一个方法。是这样的:

public function detach(){
       try {
            
            if ($this->has('photos')) {
                foreach ($this->photos as $photo) {
    
                    $this->photos()->detach($photo);
                }
            }
           
        } catch (Exception $e) {
            dd($e);
        }
}

然后你可以简单地在你需要的地方调用它:

$user->detach();
$user->delete();

要详细说明所选的答案,如果关系也有必须删除的子关系,则必须首先检索所有子关系记录,然后调用delete()方法,以便正确地触发它们的删除事件。

您可以使用更高阶的消息轻松实现这一点。

class User extends Eloquent
{
    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    public static function boot() {
        parent::boot();

        static::deleting(function($user) {
             $user->photos()->get()->each->delete();
        });
    }
}

你也可以通过只查询关系ID列来提高性能:

class User extends Eloquent
{
    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    public static function boot() {
        parent::boot();

        static::deleting(function($user) {
             $user->photos()->get(['id'])->each->delete();
        });
    }
}

用户模型中的关系:

public function photos()
{
    return $this->hasMany('Photo');
}

删除相关记录:

$user = User::find($id);

// delete related   
$user->photos()->delete();

$user->delete();
$table->foreignId('user_id')->constrained('user')->cascadeOnDelete();

or

$table->foreignId('user_id')->constrained()->cascadeOnDelete();