我有一个'连接'表,其中包含以下架构:
id
requestor_id (user_id)
requested_id (user_id)
让我们说John Doe(请求者)连接到Jane Doe(请求),Jonnie Doe(请求者)连接到John Doe(请求)。列出所有John Doe的联系我必须
inner join "connections"
on "users"."id" = "connections"."requested_id"
or "users"."id" = "connections"."requestor_id"
但目前Laravel目前还不行,因为afaik没有BelongsToMany->or()
方法,所以你会怎么做呢?
答案 0 :(得分:1)
我设法破解了关系,并提出了一个临时解决方案:
public function connections()
{
$relation = $this
->belongsToMany(static::class, 'connections', 'requestor_id', 'requested_id')
->withTimestamps();
/// delete the already built inner join
$relation
->getQuery() // Eloquent\Builder
->getQuery() // Query\Builder
->joins = [];
/// create a new inner join with the needed or condition
$relation->getQuery()->getQuery()->join('connections', function($join)
{
$join->on('users.id','=','connections.requestor_id');
$join->orOn('users.id','=','connections.requested_id');
});
return $relation;
}
答案 1 :(得分:0)
首先,您需要修复该解决方案,因为它不会返回正确的结果(检查以下)。 其次,它不适用于急切加载,因此我不会使用它。
话虽如此,您可以创建扩展BelongsToMany
的自定义关系并调整模型上的关系方法,或者使用已存在的关系方法。
所以,让我首先提出一些建议,我发现一种更好的方式(我会使用朋友而不是连接,以便更容易理解):
// friendship that I started
function friendsOfMine()
{
return $this->belongsToMany(static::class, 'friends', 'user_id', 'friend_id');
}
// friendship that I was invited to
function friendOf()
{
return $this->belongsToMany(static::class, 'friends', 'friend_id', 'user_id');
}
public function getFriendsAttribute()
{
if ( ! array_key_exists('friends', $this->relations)) $this->loadFriends();
return $this->getRelation('friends');
}
protected function loadFriends()
{
if ( ! array_key_exists('friends', $this->relations))
{
$friends = $this->mergeFriends();
$this->setRelation('friends', $friends);
}
}
protected function mergeFriends()
{
return $this->friendsOfMine->merge($this->friendOf);
}
现在它非常易于使用,非常灵活,并且可以轻松加载:
$user = User::first();
$user->friends; // merged collection thanks to the accessor
$user->friendOf; // collection of my fans ;)
$user->friendsOfMine; // my idols
$users = User::with('friendOf', 'friendsOfMine')->get();
问题是,仍会有where
子句,这会破坏您的查询。因此,您需要将其移至joinClause
并再添加一个:
public function friends()
{
$relation = $this
->belongsToMany(static::class, 'friends', 'user_id', 'friend_id')
->withTimestamps();
// get underlying Query\Builder
$query = $relation->getQuery()->getQuery();
// get rid of wrong where and its bindings
$query->setBindings([])
$query->wheres = [];
// fetch and alter joinClause
$join = reset($query->joins);
$join->where('friends.user_id', '=', $this->getKey())
->orOn('users.id','=','friends.user_id')
->where('friends.friend_id', '=', $this->getKey());
// Now the join looks like this:
//
// $key = $this->getKey();
//
// $query->join('friends', function($join) use ($key)
// {
// $join->on('users.id', '=', 'friends.friend_id')
// ->where('friends.user_id', '=', $key)
// ->orOn('users.id', '=','friends.user_id')
// ->where('friends.friend_id', '=', $key);
// });
return $relation;
}