如何从与Has-One和Have-Many关系相关的3个模型中获取数据?

时间:2015-01-03 12:47:56

标签: php mysql laravel orm eloquent

我的项目中有一个友情请求模块。正在使用以下3个表: -

  1. 用户
  2. User_profile
  3. 友谊
  4.   

    用户: - ID,slug,名称,电子邮件,密码

         

    UserProfile: - ID,user_slug,Profile_pic,DOB..etc。

         

    友谊: - ID,User_slug,Friend_slug,状态

    关系: -

    用户模型: -

    public function Profile(){
        return $this->hasOne('UserProfile','user_slug','slug')->first();
    }
    
    public function sentFriendshipRequests(){
        return $this->hasMany('Friendship','user_slug','slug');
    }
    
    public function receivedFriendshipRequests(){
        return $this->hasMany('Friendship','friend_slug','slug');
    }   
    

    UserProfile模型: -

    public function User(){
        return $this->belongsTo('User','user_slug','slug');
    }
    

    友谊模式: -

    public function receiver(){
        return $this->belongsTo('User','friend_slug','slug');
    }
    
    
    public function sender(){
        return $this->belongsTo('User','user_slug','slug');
    }
    

    目标: - 我想显示用户收到的待处理友情请求列表。

    所需数据: - 所有友谊请求具有当前登录用户的待处理状态&姓名,Slug,友情请求发送者的Profile_pic。

    我的方法: -

    $friendship_requests= Auth::user()->receivedFriendshipRequests();
    
    foreach($friendship_requests as $frnd_req)
    {
        $sender_user=User::where('slug',$frnd_req->user_slug());
    }
    

    是否有其他正确的方法可以使用Eloquent Relationship方法获取此数据,而无需使用join。我的意思是如何在一个查询中使用HasOne和HasMany关系获取数据。

    非常感谢任何帮助或建议。

    由于

1 个答案:

答案 0 :(得分:1)

这是一种自引用多对多关系,因此您根本不需要这些hasMany / belongsTo关系。 您只需将一个belongsToMany用于自己的请求,另一个用于收到请求。

首先阅读:https://stackoverflow.com/a/25057320/784588

然后添加这些关系:

// pending requests of mine
function pendingFriendsOfMine()
{
  return $this->belongsToMany('User', 'friendship', 'user_slug', 'friend_slug')
     ->wherePivot('accepted', '=', 0)
     ->withPivot('accepted');
}

// pending received requests
function pendingFriendOf()
{
  return $this->belongsToMany('User', 'friendship', 'friend_slug', 'user_slug')
     ->wherePivot('accepted', '=', 0)
     ->withPivot('accepted');
}

// accessor allowing you call $user->friends
public function getPendingFriendsAttribute()
{
    if ( ! array_key_exists('pendingFriends', $this->relations)) $this->loadPendingFriends();

    return $this->getRelation('pendingFriends');
}

protected function loadPendingFriends()
{
    if ( ! array_key_exists('pendingFriends', $this->relations))
    {
        $pending = $this->mergePendingFriends();

        $this->setRelation('pendingFriends', $pending);
    }
}

protected function mergePendingFriends()
{
    return $this->pendingFriendsOfMine->merge($this->pendingFriendOf);
}

然后你只需使用嵌套关系加载它:

$user = Auth::user();
$user->load('pendingFriendsOfMine.profile', 'pendingFriendOf.profile');
// the above will execute 4 queries - 2 for requests, 2 for related profiles

$pendingFriends = $user->pendingFriends; // for all pending requests
// or
// $user->load('pendingFriendOf.profile'); // 2 queries in this case
// $pendingRequests = $user()->pendingFriendOf; // for received requests only

foreach ($pendingFriends as $user) {
  $user->profile; // eager loaded profie model
}

此外,您的代码中存在一些错误:

// there can't be first() in the relation definition
// and it is not needed anyway
public function Profile(){
    return $this->hasOne('UserProfile','user_slug','slug')->first();
}



// You never want to run this User::where() ...
// in a foreach loop, for it will result in n+1 queries issue
// You need eager loading instead.
foreach($friendship_requests as $frnd_req)
{
    $sender_user=User::where('slug',$frnd_req->user_slug());
}