带动态参数的Laravel 5全局作用域


Laravel 5 Global Scope with Dynamic Parameter

我们在使用带有动态查询参数的全局作用域时遇到了问题。全局作用域是基于管理器ID的,但是$model是空的,而且$this指的是管理器作用域而不是模型,所以$this-> ID是一个未定义的属性。有没有办法这样做:

public function apply(Builder $builder, Model $model)
{
    return $builder->where('manager', $model->id); // $this->id
}

我假设$model应该是经理模型,但由于它是空的,我找不到任何关于它的文档,我不完全确定(如果有人能在评论中告诉我,我会很感激)。这是我们在Manager模型中的全局作用域方法:

protected static function boot()
{
    parent::boot();
    static::addGlobalScope(new ManagerScope);
}

由于全局作用域不需要显式方法,我想也许可以添加一些东西到引导可能允许一个额外的参数,如:

protected static function boot()
{
    parent::boot();
    static::addGlobalScope(new ManagerScope($this->id);
}

但是这在静态方法中是不允许的,这在我看到错误后是有意义的。

全局作用域自然是自动应用的,没有办法直接向它们传递参数。

因此,您可以坚持使用动态局部作用域,这在我看来更有意义,

public function scopeForManager($query, $manager)
{
    return $query->where('manager', $manager->id);
}
Document::forManager($manager)->all();

或者如果管理器信息在某种全局状态(即会话)中可用,则可以创建某种ManagerResolver类

class ManagerScope
{
    protected $resolver;
    public function __construct(ManagerResolver $resolver)
    {
        $this->resolver = $resolver
    }
    public function apply(Builder $builder, Model $model)
    {
        return $builder->where('manager', $this->resolver->getManagerId());
    }    
}

并将其实例传递到

作用域
protected static function boot()
{
    parent::boot();
    static::addGlobalScope(new ManagerScope(new ManagerResolver());
}

更新Laravel 8.x

您可以在模型中创建一个静态函数,然后在创建的作用域中使用它。例如,假设您想要为所有表创建一个全局搜索,而不是为每个模型创建一个搜索函数。

在作用域类中执行以下操作:

<?php
namespace App'Scopes;
 
use Illuminate'Database'Eloquent'Builder;
use Illuminate'Database'Eloquent'Model;
use Illuminate'Database'Eloquent'Scope;
 
class SearchScope implements Scope
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  'Illuminate'Database'Eloquent'Builder  $builder
     * @param  'Illuminate'Database'Eloquent'Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        if(!empty($keyword = 'request()->query('q')))
            $builder->where($model::searchField(), 'LIKE', '%' . $keyword . '%');
    }
}

然后在每个模型中创建searchField()函数,像这样:

    <?php
    namespace Modules'Api'Models;
    
    use Illuminate'Database'Eloquent'Model;
    use App'Scopes'SearchScope;
    
    class Product extends Model
    {
        protected static function searchField(){
            return "products.name"; // Name of field to be used in WHERE clause while searching using LIKE operator
        } 
    
        protected static function booted()
        {
            static::addGlobalScope(new SearchScope);
        }
}

万岁!现在你可以在Laravel作用域中使用动态变量了!!