代码之家  ›  专栏  ›  技术社区  ›  Yahya Uddin

拉勒维尔5:有条件的雄辩关系法

  •  0
  • Yahya Uddin  · 技术社区  · 6 年前

    正常的人际关系方法通常没有条件,而且往往是这样的:

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

    拉勒维尔是否支持上述雄辩的条件关系。很多常用的方法仍然是这样:

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

    但是,下面的工作是否可以预见:

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

    这里的问题是,我不确定“with”操作符如何在内部雄辩地工作。

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

    2 回复  |  直到 6 年前
        1
  •  1
  •   d3jn    6 年前

    不,这不管用 with() . 当您尝试执行以下代码时,您认为会发生什么情况:

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

    答案是Laravel将创建 Foo 试着打电话 user() 以获取关系对象这个新实例没有任何 type ( (new Foo)->type null ),所以你的方法 用户() 总会回来的 $this->hasOne(Bar::class, 'b_id') 这个关系对象将用于构造查询。

    正如您所看到的,这显然不是您想要的,因为只有类型B的用户会渴望加载所有 排。在这种情况下,您需要为用户创建两个关系(每种类型一个)和访问器(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);
            }
        }
    }
    

    那你就可以用 使用() 对于这两种关系,都要使用紧急加载:

    $fooRows = Foo::with('userA', 'userB')->get();
    ...
    foreach ($fooRows as $row) {
        $row->user;
    }
    

    编辑: 既然您已经编辑了问题中的代码,那么我的答案中的示例代码就不再代表您的情况了,但是我希望您能了解总体情况。

        2
  •  -1
  •   JordyvD    6 年前

    是的, with() 作品。它对任何关系运行子查询 user() 方法返回。因为您的关系已经有一个约束,所以它会像您期望的那样将该约束应用于子查询。