覆盖Laravel get和first方法

时间:2019-04-15 13:39:30

标签: laravel

我需要重写上述方法以跳过一些数据库记录。不能选择使用where,因为我必须每次都使用它,因为数据库中有很多记录我不需要大部分时间,并且不允许将它们从数据库中删除。这是我这样做的尝试:

class SomeTable extends BaseModel { 

    public static function first() {
       $query = static::query();
       $data = $query->first();
       if($data && $data->type == 'migration_type') return null;

       return $data;
    }

    public static function get() {
       $query = static::query();
       $data = $query->get();
       foreach($data as $key => $item) {
           if($item->type == 'migration_type') unset($data[$key]); 
       }

       return $data;
    }
}

此代码的问题在于它仅在直接调用模型时才有效。如果我在whereget方法之前使用其他功能,例如first,它会跳过我的重写方法。 什么是正确的方法,我应该将此代码放在模型中吗?

我的问题不是重复的,因为提到的问题的答案是这样的:

  

通过模型扩展您的CustomModel进行的所有查询都将获得此新方法

我只需要为特定模型覆盖这两个函数,而不是为应用程序中的每个模型覆盖这两个函数,因为并非所有表都具有type列。这就是为什么我在模型类中编写它们的原因。

3 个答案:

答案 0 :(得分:4)

  

我需要重写上述方法以跳过一些数据库记录。

考虑模型的全局查询范围。

https://laravel.com/docs/5.8/eloquent#global-scopes

  

全局作用域允许您向给定模型的所有查询添加约束。 Laravel自己的软删除功能利用全局作用域仅从数据库中提取“未删除”模型。编写自己的全局范围可以提供一种简便的方法,以确保针对给定模型的每个查询都受到某些约束。

答案 1 :(得分:0)

因为在调用您要与数据库构建器打交道的地方之后,并且未在模型中调用这些方法..关于该问题,您可以通过直接使用select而不是first来解决该问题所以将与建造者打交道..

示例:

SomeTable::select('col1','col2')->take(1)->get();

如果您与同一个项目的其他开发人员一起工作,则覆盖此类方法的另一件事不是一个好主意。

祝你好运

答案 2 :(得分:0)

这里的问题是模型上的where()方法返回一个QueryBuilder实例,而get()将返回一个Collection实例。

您应该能够通过在其位置添加一个宏来覆盖collection的默认方法,并且可以这样做...

Collection::macro('toUpper', function () {
    return $this->map(function ($value) {
        return Str::upper($value);
    });
});

扩展查询生成器实例并不容易,但是存在一个不错的教程here,其中涉及到覆盖应用程序的默认连接类,这在以后的升级中不是很好。