设一个名为User
的模型具有两个作用域ScopeF1()
和ScopeF2()
。我们可以写
User::f1()->f2()->get();
并且它执行作用域并返回结果。据我所知,作用域返回Builder
的一个实例,因为我们在其中调用query->where(...,...)
User::f1()->f2()->get();
它调用f1()
,返回Builder
的一个实例,根据链接规则,它必须从Builder
调用f2()
,但在Laravel中,它调用类User
的f2()
,而不是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继续工作,但现在您可以使用以下运算符进行查询<,>,>=
等等。。。
希望这能帮助