不要在模型 Trait 里写 boot () 方法

TL;DR 在一个 trait 模型中使用 bootNameOfTrait() 代替 boot() 来避免被基础模型的 boot() 方法覆盖。

通过一个 boot 方法添加行为

打比方对于每个模型你有一个 HasImage trait ,与一个图片相关:

trait HasImage
{
    public function image()
    {
        return $this->belongsTo(Image::class);
    }
}

并且你需要确保模型删除的时候,图片被删除,所以你在 trait 中添加了一个 boot() 方法。

无论模型何时初始化,静态 boot() 方法自动执行,所以它是一个添加行为或者绑定事件的理想所在。比如,在我们当前的案例中,模型中发生删除事件时自动删除一个相关图片。

public static function boot()
{
    // 如果存在的话,删除关联图片
    static::deleting(function ($model) {
        $model->image->delete();
    });
}

然而,如果父模型也含有 boot() 方法的话,trait 方法会被覆盖。

解决方案? 使用 bootHasImage() 代替 boot()

一个更好的办法

trait HasImage
{
    public static function bootHasImage()
    {
        // 如果存在,删除关联图片
        static::deleting(function($model) {
            $model->image->delete();
        });
    }

    public function image()
    {
        return $this->belongsTo(Image::class);
    }
}

如此行之有效是因为来自 Eloquent’s Model.php 的一小段.

protected static function boot()
{
    static::bootTraits();
}

/**
 * 启动模型的所有可启动 trait
 *
 * @return void
 */
protected static function bootTraits()
{
    $class = static::class;

    foreach (class_uses_recursive($class) as $trait) {
        if (method_exists($class, $method = 'boot' . class_basename($trait))) {
            forward_static_call([$class, $method]);
        }
    }
}

现在我们气贯长虹,找到了在模型事件中,在特定的 trait 中,加入钩子的方法。

希望你能喜欢!

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://tighten.co/blog/laravel-tip-boot...

译文地址:https://learnku.com/laravel/t/40950

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 4
Summer

相见恨晚的功能!

4年前 评论
XiaohuiLam 4年前
jamxio 4年前
Horizon 2年前

这个之前 use SoftDeletes; 时知道了

4年前 评论

也可以 在boot方法中 parent::boot();

3年前 评论

这个很实用,不用 parent::boot () 了

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!