【问题标题】:How to setup conditional relationship on Eloquent如何在 Eloquent 上设置条件关系
【发布时间】:2017-09-25 20:39:48
【问题描述】:

我有这个(简化的)表结构:

users
- id
- type (institutions or agents)

institutions_profile
- id
- user_id
- name

agents_profile
- id
- user_id
- name

我需要在Users 模型上创建profile 关系,但以下不起作用:

class User extends Model
{
    public function profile()
    {
        if ($this->$type === 'agents')
            return $this->hasOne('AgentProfile');
        else
            return $this->hasOne('InstitutionProfile');
    }    
}

我怎样才能实现这样的目标?

【问题讨论】:

    标签: laravel eloquent relationships


    【解决方案1】:

    让我们采用不同的方法来解决您的问题。首先让我们分别设置各种模型的关系。

    class User extends Model
    {
        public function agentProfile()
        {
            return $this->hasOne(AgentProfile::class);
        }    
    
        public function institutionProfile()
        {
            return $this->hasOne(InstitutionProfile::class);
        }
    
        public function schoolProfile()
        {
            return $this->hasOne(SchoolProfile::class);
        }
    
        public function academyProfile()
        {
            return $this->hasOne(AcademyProfile::class);
        }
    
        // create scope to select the profile that you want
        // you can even pass the type as a second argument to the 
        // scope if you want
        public function scopeProfile($query)
        {
            return $query
                  ->when($this->type === 'agents',function($q){
                      return $q->with('agentProfile');
                 })
                 ->when($this->type === 'school',function($q){
                      return $q->with('schoolProfile');
                 })
                 ->when($this->type === 'academy',function($q){
                      return $q->with('academyProfile');
                 },function($q){
                     return $q->with('institutionProfile');
                 });
        }
    }
    

    现在您可以像这样访问您的个人资料

    User::profile()->first();
    

    这应该会为您提供正确的个人资料。希望对您有所帮助。

    【讨论】:

    • 我不确定这是否适用。我需要能够急切地加载配置文件并访问 $user->profile->name。
    • 仔细检查范围。它急切地加载配置文件(基于类型)并使用 with 来急切加载,这样可以更有效地防止任何 N+1 查询问题。我已将您的 if 语句更改为更类似于 laravel 的雄辩语法
    • 是的,你是对的。但是如果我有更多的个人资料类型呢?
    • 已更新答案。如果您觉得这样更方便,可以使用 if 语句。
    • 这将不起作用,因为在范围运行时未加载“用户”对象。因此 "$this->type" 在加载用户时将始终为空。您必须先加载用户,然后才然后运行其余代码。
    【解决方案2】:

    您可以使用其他方法来做到这一点,请检查:

    一个博客帖子和视频模型可以共享一个多态关系到一个 标记模型。使用多对多多态关系允许您 拥有一个在博客文章之间共享的唯一标签列表 和视频。首先,我们来看看表结构:

    https://laravel.com/docs/5.4/eloquent-relationships#many-to-many-polymorphic-relations

    【讨论】:

    • 谢谢,但多态关系不适用于此处。
    • 我认为多态就在这里,但你需要稍微重组你的数据库。
    【解决方案3】:

    看起来应该是 $this->type 而不是 $this->$type - 因为 type 是一个属性,而不是一个变量。

    【讨论】:

    • 我简直不敢相信我没有看到!谢谢。但是现在我在尝试加载配置文件时遇到了这个错误:Fatal error: Call to a member function addEagerConstraints() on a non-object in /vendor/illuminate/database/Eloquent/Builder.php on line 667 有什么想法吗?
    • 不确定究竟是什么原因导致的 - 也许检查表/模型的名称?我注意到它们被称为不同的东西,因此它们可能在各自的模型中需要 $table 属性。
    • 刚刚看到关于 addEagerConstraints 的消息 - 这是当您的关系函数(例如 profile())没有返回任何内容时引起的 - 怀疑范围是更好的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-15
    • 2016-02-21
    • 1970-01-01
    • 2020-11-13
    • 2012-09-27
    • 2018-08-20
    • 2015-05-26
    相关资源
    最近更新 更多