Laravel 5.5:如何为所有带时间戳模型创建全局查询作用域
刚好我之前也解决过类似的问题,Laravel里实现全局查询构造器方法有两种常用方案,都能帮你摆脱重复粘贴代码的冗余问题,咱们一步步来看:
方案一:自定义查询构造器基类
这种方法适合你需要统一管理多个全局查询方法,或者后续要扩展更多相关功能的场景,核心思路是让所有模型共用一个自定义的查询构造器:
- 创建自定义查询构造器类
在App\Builders目录下新建BaseQueryBuilder.php(如果没有Builders目录就自己创建),继承Laravel的基础查询构造器,然后添加你需要的全局方法:
<?php namespace App\Builders; use Illuminate\Database\Eloquent\Builder; class BaseQueryBuilder extends Builder { // 获取今日数据,默认使用created_at字段,可传参指定其他字段 public function today($column = 'created_at') { return $this->whereDate($column, today()); } // 获取昨日数据,同样支持自定义字段 public function yesterday($column = 'created_at') { return $this->whereDate($column, yesterday()); } }
- 创建基础模型类
在App\Models目录下新建BaseModel.php,让它继承Laravel的Model,然后重写newEloquentBuilder方法,返回咱们刚才自定义的查询构造器:
<?php namespace App\Models; use App\Builders\BaseQueryBuilder; use Illuminate\Database\Eloquent\Model; class BaseModel extends Model { /** * 替换默认的查询构造器为自定义版本 */ public function newEloquentBuilder($query) { return new BaseQueryBuilder($query); } }
- 让业务模型继承基础模型
以后你所有需要使用这些全局方法的模型,都继承BaseModel而不是直接继承Model就行:
<?php namespace App\Models; // 这里继承BaseModel class Post extends BaseModel { // 你的模型代码... }
使用方式
现在不管哪个模型,都能直接调用这些方法:
// 获取今日创建的文章 $todayPosts = Post::today()->get(); // 获取昨日更新的用户 $yesterdayUpdatedUsers = User::yesterday('updated_at')->get();
方案二:使用查询构造器宏(更轻量)
如果不想修改模型的继承关系,这种方法更适合你——直接给Laravel的查询构造器“打补丁”,注册全局宏:
- 在服务提供者里注册宏
打开App\Providers\AppServiceProvider.php,在boot方法里添加宏定义:
<?php namespace App\Providers; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { public function boot() { // 注册today宏 Builder::macro('today', function ($column = 'created_at') { return $this->whereDate($column, today()); }); // 注册yesterday宏 Builder::macro('yesterday', function ($column = 'created_at') { return $this->whereDate($column, yesterday()); }); } // ... 其他代码 }
使用方式
注册完成后,所有Eloquent模型(包括关联查询)都能直接用这些方法,完全不需要改模型代码:
// 获取今日的订单 $todayOrders = Order::today()->get(); // 获取某篇文章昨日的评论 $yesterdayComments = Post::find(123)->comments()->yesterday()->get();
两种方案对比
- 方案一(基类):适合需要集中管理大量全局查询方法,或者后续要给查询构造器添加更多复杂逻辑的场景,结构更清晰。
- 方案二(宏):轻量快捷,不需要修改模型继承,适合快速添加少量全局方法的场景。
两种方案都能完美解决你代码冗余的问题,根据自己的需求选就行~
内容的提问来源于stack exchange,提问作者norr
相关产品推荐
相关产品推荐

