问题
I have implemented the relationship without Eloquent but I was wondering is there was a way to define this relationship in Eloquent so that my application can have more consistency.
table User
-id
-other user attributes
table friend_requests:
-id
-sender_id
-reciever_id
table friends
-id
-first
-second
The friendRequest relation has been easily implemented in the Eloquent but the problem lies in Friends.
If I do this in the User model class:
public function friends(){
return $this->belongsToMany(User::class,'friends','first','second');
}
This wouldn't work as you would have noticed. Let me explain with example:
Table: friends
id | first | second
1 | 1 | 2
2 | 3 | 1
you see that user_1
is friends with user_2
as well as user_3
as the relationship is bi-directional. But Eloquent will naturally return that user_1
is friends with user_2
only. After thinking for a while I tweaked the statement but made little progress'
public function friends(){
return $this->belongsToMany(User::class,'friends','first','second')
->orWhere('second',$this->id);
}
That is because now it selects both rows but the User
s it returns are those whose id
= second
which means that in the second case it will return the user itself.
I implemented the relations with my own methods in User
model class which use DB::table('friends')->
to addFriend(User $user)
, removeFriend(user $user)
and returns list of friends()
, but I'm disappointed that this isn't as eloquent as Eloquent
relationships.
Perhaps some more experienced developers here would have come across this kind of problem and would have dealt better than I did. How do you propose I deal with this problem. Should I stick with my approach or is there a better way to deal with it?
回答1:
A more manageable way to implement bidirectional relations would be to create two entries for each confirmed friendship.
So a user would make a friend request to another user. When the second user confirms the friend request, two friendships are created.
Example Controller
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\User;
use App\FriendRequest;
use App\Friendship;
class FriendshipController extends Controller
{
public function friendRequest(Request $request)
{
$receiver_id = $request->input('receiver_id');
$request->user()->friend_offers()->create([
'receiver_id' => $receiver_id
]);
}
public function friendshipConfirmation(Request $request)
{
$friend_request_id = $request->input('friend_request_id');
$friend_request = FriendRequest::find($friend_request_id);
$friend_request->receiver->friendships()->create([
'user_2_id' => $friend_request->sender->id
]);
$friend_request->sender->friendships()->create([
'user_2_id' => $friend_request->receiver->id
]);
}
}
Database Tables
(Note the proper spelling of receiver
and plural users
table)
table users
- id
- other user attributes
table friend_requests:
- id
- sender_id
- receiver_id
table friendships
- id
- user_1_id
- user_2_id
User Model
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Authenticatable
{
use SoftDeletes;
public $timestamps = true;
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
/**
* The attributes that aren't mass assignable.
*
* @var array
*/
protected $guarded = ['id'];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
//
];
/**
* Return friend requests from other users
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function friend_requests()
{
return $this->hasMany(FriendRequest::class, 'receiver_id');
}
/**
* Return friend requests sent to other users
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function friend_offers()
{
return $this->hasMany(FriendRequest::class, 'sender_id');
}
/**
* Return friendships with other users
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function friendships()
{
return $this->hasMany(Friendship::class, 'user_1_id');
}
}
FriendRequest Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class FriendRequest extends Model
{
use SoftDeletes;
public $timestamps = true;
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
/**
* The attributes that aren't mass assignable.
*
* @var array
*/
protected $guarded = ['id'];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'sender_id',
'receiver_id'
];
/**
* Return the requesting user
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function sender()
{
return $this->belongsTo(User::class, 'sender_id');
}
/**
* Return the receiving user
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function receiver()
{
return $this->belongsTo(User::class, 'receiver_id');
}
}
Friendship Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Friendship extends Model
{
use SoftDeletes;
public $timestamps = true;
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
/**
* The attributes that aren't mass assignable.
*
* @var array
*/
protected $guarded = ['id'];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'user_1_id',
'user_2_id'
];
/**
* Return user_1
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function first()
{
return $this->belongsTo(User::class, 'user_1_id');
}
/**
* Return user_2
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function second()
{
return $this->belongsTo(User::class, 'user_2_id');
}
}
来源:https://stackoverflow.com/questions/39186350/defining-many-to-many-bidirectional-relations-more-eloquently