应用场景

  • 某些SQL语句需要加某些共同的条件,例如status > 0,如果我们每条SQL语句都加的话显然是很麻烦的,作为一个优雅的框架,当然有相应的解决办法

编写作用域

  • Laravel 应用默认并没有为作用域预定义文件夹,所以你可以按照自己的喜好在 app 目录下创建 Scopes目录并实现接口(Illuminate\Database\Eloquent\Scope)的方法apply

    <?php
    
    namespace App\Scopes;
    
    use Illuminate\Database\Eloquent\Scope;
    use Illuminate\Database\Eloquent\Builder;
    use Illuminate\Database\Eloquent\Model;
    
    
    class StatusScope implements Scope
    {
    
        /**
         * Apply the scope to a given Eloquent query builder.
         *
         * @param \Illuminate\Database\Eloquent\Builder $builder
         * @param \Illuminate\Database\Eloquent\Model $model
         * @return
         */
        public function apply(Builder $builder, Model $model)
        {
        return $builder->where('status', '>', 0);
        }
    }

使用作用域

  • 只需要在你需要使用的模型的"boot启动"方法中使用static::addGlobalScope(new 你的作用域类);

     <?php
                 
         namespace App\Models;
                 
         use App\Scopes\StatusScope;
         use Illuminate\Database\Eloquent\Model;
                 
         class ScopeTest extends Model
         {
              protected static function boot()
              {
                   parent::boot();
                   static::addGlobalScope(new StatusScope());
                 
              }
         }             
    • 添加作用域后,如果使用 ScopeTest::all() 查询则会生成如下 SQL 语句:status>0 就是应用的效果

      select * from `users` where `status` > 0
  • 当然,假如你感觉到上面的方法比较麻,也可以使用匿名的全局作用域

      <?php
      namespace App\Models;
      
      use Illuminate\Database\Eloquent\Builder;
      use Illuminate\Database\Eloquent\Model;
      
      class ScopeTest extends Model
      {
          protected static function boot()
          {
              parent::boot();
              static::addGlobalScope('status', function (Builder $builder){
                  $builder->where('status','>', 1);
              });
          }
      }
  • 有些查询并不想使用作用域,可以通过调用以下方法移除作用域

      ScopeTest::withoutGlobalScope(StatusScope::class)->get();                         //移除指定作用域
      ScopeTest::withoutGlobalScope('status')->get();                                   //移除闭包定义的作用域
      ScopeTest::withoutGlobalScopes()->get();                                          //移除所有作用域
      ScopeTest::withoutGlobalScopes([oneScope::class, twoScope::class])->get();   //移除某些作用域   

Eloquent模型方法前加上一个 scope前缀来使用作用域

   <?php
   
   namespace App\Models;
   use Illuminate\Database\Eloquent\Model;
   
   class ScopeTest extends Model
   {
       public function scopeStatus($query){
           return $query->where('status','>', 1);
       }
       public function scopeType($query){
           return $query->where('type','>', 0);
       }
   }
  • 调用时不需要加scope前缀,类似于修改器/访问器,并且可以一次性调用多个方法。

      $users = ScopeTest::status()->type()->get();
      ScopeTest::status()->orWhere(function (Builder $query) {
          $query->type();
      })->get();

关注友儿不迷路

Last modification:December 8th, 2020 at 05:29 pm
如果觉得我的文章对你有用,请随意赞赏