将 hasManyThrough 应用于更深层次的关系

Posted

技术标签:

【中文标题】将 hasManyThrough 应用于更深层次的关系【英文标题】:Applying hasManyThrough to deeper relationships 【发布时间】:2017-05-10 03:21:08 【问题描述】:

Laravel 文档似乎表明 hasManyThrough 声明只能用于两层“深”的关系。更复杂的关系呢?例如,一个User 有很多Subjects,每个Decks 有很多Decks,每个Cards 很多。使用hasManyThrough 声明让所有Decks 属于User 很简单,但是属于User 的所有Cards 呢?

【问题讨论】:

I asked this same question 几年前。 HasManyThrough 只是一个捷径。就目前而言,没有用于访问远距离关系的内置机制。 【参考方案1】:

如 cmets 中所述,hasManyThrough 不支持此级别的特异性。您可以做的一件事是返回一个相反方向的查询构建器实例:

//App\User;

public function cards()

    Card::whereHas('decks', function($q)
         return $q->whereHas('subjects', function($q)
            return $q->where('user_id', $this->id);
        );
    );

我们将从Cards -> Decks -> Subjects 出发。 subjects 应该有一个 user_id 列,然后我们可以锁定它。

当从用户模型调用时,它会如此轻松地完成:

$user->cards()->get();

【讨论】:

【参考方案2】:

我创建了一个无限级别的HasManyThrough 关系:Repository on GitHub

安装后,可以这样使用:

class User extends Model 
    use \Staudenmeir\EloquentHasManyDeep\HasRelationships;

    public function cards() 
        return $this->hasManyDeep(Card::class, [Subject::class, Deck::class]);
    

【讨论】:

【参考方案3】:

好吧,实际上最好的解决方案是将额外的列放入 Card 表 - user_id,如果您经常需要为用户获取所有卡片。

Laravel 为 2-depth 关系提供 Has-Many-Through 关系,因为这是非常广泛使用的关系。 对于 Laravel 不支持的关系,你需要自己找出最佳的表关系。

出于您的目的,您可以使用以下代码快照以任何方式使用您当前的关系模型为用户获取所有卡片。

假设

用户与 Deck 有hasManyThough 关系,

所以项目模型将有以下代码:

 public function decks()
    
        return $this->hasManyThrough('Deck', 'Subject');
    
Deck 与 Card 有 hasMany 关系

代码

$deck_with_cards = $user->decks()->with("cards")->get();
$cards = [];
foreach($deck_with_cards AS $deck) 
  foreach ($deck->cards as $c) 
    $cards[] = $c->toArray();
  

现在$cards 拥有$user 的所有卡片。

【讨论】:

以上是关于将 hasManyThrough 应用于更深层次的关系的主要内容,如果未能解决你的问题,请参考以下文章

php facetwp索引只有孙子或更深层次的术语

使用 RTTI 时,我们如何获取和设置更深层次的子属性?

更深层次的深度测试(由混合所引出)

将过滤应用于层次结构

大企鹅PK老干妈后的危机公关,可以看到更深层次的问题

NLP“理解层次”工具的应用