Laravel作用域链接如何从基类而不是Builer调用作用域



设一个名为User的模型具有两个作用域ScopeF1()ScopeF2()。我们可以写

User::f1()->f2()->get();

并且它执行作用域并返回结果。据我所知,作用域返回Builder的一个实例,因为我们在其中调用query->where(...,...)

User::f1()->f2()->get();

它调用f1(),返回Builder的一个实例,根据链接规则,它必须从Builder调用f2(),但在Laravel中,它调用类Userf2(),而不是Builder,我不知道它背后的逻辑。如果有人能解释它是如何工作的,我将不胜感激。

更新

我想做的是为项目中模型的每个字段实现一个默认范围。例如,如果模型User包含mobile字段,那么我可以使用以下范围,而无需实际编写其函数

User::mobileScope($value)->...

为此,每个模型都扩展了一个抽象类EntityAbstract,该抽象类又扩展了Model类。我的项目中的每个模型都包含一个静态函数mappedFields(),它返回一个按大小写的实际字段名的键值数组。例如

return [
'firstName' => 'first_name',
'lastName' => 'last_name',
'mobile' => 'mobile' 
];

函数fn($value)也存在,它返回给定骆驼大小写值的字段名。作为示例,CCD_ 18返回CCD_。

EntityAbstract中,我有以下功能

public function __call($name, $arguments)
{
if (str_ends_with($name, "Scope")) {
$scopeField = substr($name, 0, -5);
$mappedFields = static::mappedFields();
if (array_key_exists($scopeField, $mappedFields)) {
return $this->where(static::fn($scopeField), $arguments[0]);
} else
return parent::__call($name, $arguments);
} else
return parent::__call($name, $arguments);
}
public static function __callStatic($name, $arguments)
{
if (str_ends_with($name, "Scope")) {
$scopeField = substr($name, 0, -5);
$mappedFields = static::mappedFields();
if (array_key_exists($scopeField, $mappedFields)) {
$model = new static();
return $model->where(static::fn($scopeField), $arguments[0]);
}
else
return parent::__callStatic($name, $arguments);
} else
return parent::__callStatic($name, $arguments);
}

我调用了parent::__callStatic($name, $arguments),以确保当我的范围条件不满足时,Laravel的工作流程不会中断。

现在的问题是当我写

User::mobileScope('123456')->first()

它运行得很好,但当我写时

User::mobileScope('123456')->nameScope('xyz')->first()

它抛出错误

调用未定义的方法Illuminate\Database\Eloquent\Builder::nameScope()

如您所见,mobileScope返回为Builder的实例,而不是User类,并且nameScope()Builder中未定义。

提前谢谢。

我认为这些调用和静态函数会使事情变得复杂,因为实际上几乎是在覆盖模型的作用域行为。

按照Laravel文档中的声明来声明动态作用域不会更好。

/**
* Scope a query to only include users with a given field value.
*
* @param Builder $query
* @param $field
* @param $value
* @return Builder
*/
public function scopeWithField(Builder $query, $field, $value): Builder
{
return $query->where($field, $value);
}

用作

$user = User::withField('name','Manuel Glez')->withField('email','manuel@mydomain.com')->get();

或者您甚至可以改进它,并传递另一个指定要使用的运算符的参数,使其默认为'='

public function scopeWithField(Builder $query, $field, $value,$operator='='): Builder
{
return $query->where($field,$operator ,$value);
}

因此,使用as继续工作,但现在您可以使用以下运算符进行查询<,>,>=

等等。。。

希望这能帮助

最新更新