Laravel Query Builder能否应用全局或本地作用域?
在Laravel Query Builder中实现作用域(类似Eloquent)
当然可以在Query Builder中实现类似Eloquent的全局/本地作用域,以下是针对软删除场景的具体实现方式:
一、本地作用域(可复用查询片段)
Query Builder没有Eloquent的scopeXXX自动识别机制,但可以通过**自定义宏(Macro)**实现可复用的查询逻辑:
- 在
App\Providers\AppServiceProvider的boot方法中定义宏:
use Illuminate\Database\Query\Builder; public function boot() { // 定义仅查询未软删除数据的宏 Builder::macro('withoutTrashed', function () { return $this->whereNull('deleted_at'); }); // 定义查询包含软删除数据的宏 Builder::macro('withTrashed', function () { return $this->whereNotNull('deleted_at')->orWhereNull('deleted_at'); }); // 自定义业务作用域:查询活跃且未删除的用户 Builder::macro('activeAndNotDeleted', function () { return $this->where('is_active', 1)->withoutTrashed(); }); }
- 使用方式:
// 查询未删除的用户 DB::table('users')->withoutTrashed()->get(); // 查询活跃且未删除的用户 DB::table('users')->activeAndNotDeleted()->get();
二、全局作用域(自动应用到所有Query Builder查询)
如果希望所有Query Builder查询默认自动排除软删除数据,可通过以下两种方式实现:
方式1:重写Query Builder默认查询逻辑
在AppServiceProvider的boot方法中修改Builder的默认行为:
use Illuminate\Database\Query\Builder; public function boot() { // 保存原生newQuery方法 $originalNewQuery = Builder::getMacro('newQuery'); Builder::macro('newQuery', function () { // 调用原生方法后自动添加软删除约束 return $originalNewQuery()->whereNull('deleted_at'); }); // 提供取消全局约束的方法 Builder::macro('withTrashed', function () { // 移除deleted_at的null约束 $this->wheres = collect($this->wheres)->reject(function ($where) { return $where['column'] === 'deleted_at' && $where['operator'] === 'null'; })->values()->all(); return $this; }); }
此后所有DB::table('xxx')的查询都会自动带上whereNull('deleted_at'),需要包含软删除数据时调用withTrashed()即可。
方式2:自定义Query Builder类
创建继承自原生Builder的自定义类,在构造方法中默认添加软删除约束:
namespace App\Database\Query; use Illuminate\Database\Query\Builder as BaseBuilder; class SoftDeleteBuilder extends BaseBuilder { public function __construct($connection, $grammar = null, $processor = null) { parent::__construct($connection, $grammar, $processor); // 默认添加软删除约束 $this->whereNull('deleted_at'); } // 取消软删除约束,查询所有数据 public function withTrashed() { $this->wheres = collect($this->wheres)->reject(function ($where) { return $where['column'] === 'deleted_at' && $where['operator'] === 'null'; })->values()->all(); return $this; } // 仅查询软删除的数据 public function onlyTrashed() { $this->withTrashed(); return $this->whereNotNull('deleted_at'); } }
在AppServiceProvider的register方法中绑定自定义Builder:
use App\Database\Query\SoftDeleteBuilder; use Illuminate\Database\Connection; public function register() { $this->app->resolving(Connection::class, function (Connection $connection) { $connection->setQueryBuilder(new SoftDeleteBuilder( $connection, $connection->getQueryGrammar(), $connection->getPostProcessor() )); }); }
使用方式与原生Query Builder完全一致:
// 默认查询未删除数据 DB::table('users')->get(); // 查询包含软删除的数据 DB::table('users')->withTrashed()->get(); // 仅查询软删除的数据 DB::table('users')->onlyTrashed()->get();
内容的提问来源于stack exchange,提问作者Shahzad Ali
相关产品推荐
相关产品推荐

