laravel - Laravel 5:有条件的雄辩关系方法
问题描述
正常的关系方法通常没有条件,并且往往看起来像这样:
class StripeCustomer extends Model
{
public function user()
{
return $this->belongsTo(User::class, 'stripe_customer_id');
}
}
在我的模型中,我在关系方法中有一个条件,如下所示:
class StripeCustomer extends Model
{
public function user()
{
if ($this->type === 'normal') {
return $this->hasOne(User::class, 'stripe_customer_id');
} else {
return $this->hasOne(User::class, 'stripe_customer_charity_id');
}
}
}
Laravel 是否像上面那样支持 Eloquent 中的条件关系。许多常用的方法仍然像这样工作:
StripeCustomer::get()->first()->user;
StripeCustomer::get()->first()->user()->get();
但是以下工作是否可以预见:
Foo::with('user')->get();
这里的问题是我不确定“with”运算符在 Eloquent 内部是如何工作的。
我认为它也不起作用的一个原因是user()
需要为每个模型执行该方法。但是,当我dump(...)
在方法的开头添加a时,我发现它只运行了一次,表明它with()
不起作用。
解决方案
不,它不适用于with()
. 当您尝试执行以下代码时,您认为会发生什么:
Foo::with('user')->get();
答案是 Laravel 将创建新的实例Foo
并尝试调用user()
以获取关系对象。这个新实例没有任何type
( (new Foo)->type
will be null
),因此您的方法user()
将始终返回$this->hasOne(Bar::class, 'b_id')
,并且此关系对象将用于构造查询。
正如您所看到的,这显然不是您想要的,因为只有 B 类用户会急切地加载所有Foo
行。在这种情况下,您需要做的是为用户创建两个关系(每种类型一个)和访问器(get/set):
class Foo extends Model
{
public function userA()
{
return $this->hasOne(Bar::class, 'a_id');
}
public function userB()
{
return $this->hasOne(Bar::class, 'b_id');
}
public function getUserAttribute()
{
if ($this->type === 'a') {
return $this->userA;
} else {
return $this->userB;
}
}
public function setUserAttribute($user)
{
if ($this->type === 'a') {
$this->userA()->associate($user);
} else {
$this->userB()->associate($user);
}
}
}
然后,您可以使用with()
这两种关系来利用急切加载:
$fooRows = Foo::with('userA', 'userB')->get();
...
foreach ($fooRows as $row) {
$row->user;
}
编辑: 由于您在问题中编辑了代码,因此我的答案中的示例代码不再代表您的情况,但我希望您了解总体思路。
推荐阅读
- sql - 我应该在哪里修改?
- sybase - 如何创建本机 Sybase BCP 文件?
- swift - 快速帮助缺少完整说明
- php - 如何使用 PHP 添加 active 包括 OR
- flutter - 如何在windows10的c分区中构建flutter apk
- java - Java:编译器如何使用声明类型作为其超类的表达式找不到特定方法?
- python - 如何从 Python 多处理进程中打印?
- php - opencart错误致命错误:未捕获异常:错误:未知列
- javascript - Json 对象到对象
- kotlin - 由于 jsNpm 配置,KMP 库 gradle allTests 失败