首先,您需要修复该解决方案,因为它不会返回正确的结果(检查下方)。
其次,它不适用于预加载,所以我不会使用它。
话虽如此,您可以创建扩展 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;
}