Laravel 5:有条件的雄辩关系法

时间:2018-07-19 09:52:17

标签: laravel laravel-5 eloquent

普通关系方法通常没有条件,并且往往看起来像这样:

@implementation MySingleton (Shared)

+ (MySingleton*)shared {

  static MySingleton* mySingleton;
  static dispatch_once_t predicate;

  dispatch_once(&predicate, ^{
    SomeClass* someClass = [[SomeClass alloc] init];
    mySingleton = [[MySingleton alloc] initWithSomeClass:someClass];
  });

  return mySingleton;
}
@end

在我的模型中,像这样的关系方法中有一个条件:

class StripeCustomer extends Model
{
    public function user()
    {
         return $this->belongsTo(User::class, 'stripe_customer_id');
    }
}

Laravel是否像上面那样在Eloquent中支持条件关系。许多常用方法仍然可以像这样工作:

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');
        }
    }
}

但是可以预期以下工作:

StripeCustomer::get()->first()->user;
StripeCustomer::get()->first()->user()->get();

这里的问题是,我不确定“ with”运算符在Eloquent内部如何工作。

我认为它也不起作用的原因是,Foo::with('user')->get(); 方法需要为每个模型执行。但是,当我在方法开始时添加user()时,发现它只运行了一次,表明dump(...)不起作用。

2 个答案:

答案 0 :(得分:1)

不,它不适用于with()。当您尝试执行以下代码时,您会怎么想:

Foo::with('user')->get();

答案是Laravel将创建Foo的新实例,并尝试调用user()以获取关系对象。这个新实例没有任何type(new Foo)->type将是null),因此您的方法user()将始终返回$this->hasOne(Bar::class, 'b_id'),并且此关系对象将是用于构造查询。

如您所见,这显然不是您想要的,因为只有B类用户才会渴望加载所有Foo行。在这种情况下,您需要为用户创建两个关系(每种类型一个)和访问者(获取/设置):

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;
}

修改: 由于您已经在问题中编辑了代码,因此我回答中的示例代码不再代表您的情况,但我希望您有所了解。

答案 1 :(得分:-1)

是的,with()有效。它对您的user()方法返回的任何关系运行子查询。由于您的关系已经具有约束,因此可以按预期将约束应用于子查询。