Laravel Eloquent查询构建器默认的Where条件

21

我有一个News模型,当我查询新闻时,我希望默认情况下它可以带来状态为1的新闻。

News::all(); // select * from news where status = 1
News::where('anotherColumn',2)->get(); // select * from news where status = 1 and where category = 2

这是否可能?我想要的功能非常类似于软删除功能(即获取已删除数据,其中deleted_at不为null,如果需要所有数据,则可以使用withTrashed函数)。

我查看了文档,但没有找到任何有用的信息。此外,我试图在新闻模型的构造函数中处理它,但也没有起作用。

谢谢。


你不能只是扩展父类并覆盖where函数吗?(这是您可以添加自定义逻辑的部分...) - Kenny
1
取决于框架版本。对于4.2+,您只需使用“全局作用域”。这正是您所需要的,也是v4.2+中“softDelete”功能的工作方式。 - Jarek Tkaczyk
3个回答

42

我通常会覆盖 newQuery() 来实现这一点。 newQuery() 是 Eloquent 用来构建新查询的方法。

class News extends Eloquent {

    public function newQuery($excludeDeleted = true) {
        return parent::newQuery($excludeDeleted)
            ->where(status, '=', 1);
    }

}

现在你的News::all()只会输出状态为1的新闻。


2
这也会将where子句添加到嵌套的wheres中。为了避免这种情况,我使用以下方式: `public function newQuery($excludeDeleted = true) { $query = parent::newQuery() if(!$this->dirty) { $query->where(status, '=', 1); } return $query; }`这是一种不太正规的处理方式,但我建议使用全局作用域。 - Bilal Gultekin
1
有关如何在关系中使其工作的任何提示吗?我在使用whereHas时遇到了问题。 - Bharat Geleda
你为什么要用 "return parent::newQuery($excludeDeleted = true)->where(status, '=', 1);" 而不是只需要使用 "return parent::newQuery($excludeDeleted)->where(status, '=', 1);"?似乎传递的参数在被覆盖之前已经有值了。 - Emir Herrera
@EmirHerrera 感谢您指出。那实际上是我的错误。已经进行了更新。 - Unnawut

15

虽然已经提到过了,但以下是一个快速示例,使用全局作用域可能是最好的当前解决方案,因为您不必覆盖Eloquent方法,这将产生相同的行为,但可以更好地控制您的模型。

只需将以下内容添加到您的模型中:

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

    static::addGlobalScope('exclude_deleted', function (Builder $builder) {
        $builder->whereNull('deleted_at');
    });
}

你也可以创建一个子Scope类,并将其重复使用于多个模型中。

更多信息,请参考Laravel文档: https://laravel.com/docs/5.6/eloquent#global-scopes


1
不错的干净解决方案!这里是最新文档的链接: https://laravel.com/docs/master/eloquent#anonymous-global-scopes - Arno van Oordt

13

我认为最接近的方法,而不需要实际修改一些核心文件...

就是查询作用域...

作用域允许您在模型中轻松重用查询逻辑。要定义作用域,只需在模型方法前加上scope:

class News extends Eloquent {
   public function scopeStatus($query)
    {
     return $query->where('status', '=', 1);
    }
 }

利用那个范围

 $news  = News::status()->get();
 $news2  = News::status()->where('anotherColumn',2)->get();

虽然与您想要的不完全一样......但肯定比打字要短一点

 News::where('status','=',1)->get();

一遍又一遍


谢谢回答。我知道这个功能,但它并没有真正帮助到我。News/*conditions*/->get()在很多地方都被调用。我不想改变所有这些行。 - Bilal Gultekin
1
你的IDE没有查找/替换功能吗?你可以搜索所有News::实例并更新为News::status()->,这似乎是一个简单的修复。 - Kylie
4
谢谢您的帮助,不冒犯地说,但是我们为什么要使用框架、面向对象编程语言、模型和视图呢?我认为强制使用这样的解决方案可以教给我很多东西,并且在编码时提供了灵活性。你说的对我来说是最后的解决方案。 - Bilal Gultekin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,