更雄辩地定义多对多双向关系

问题描述 投票:0回答:2

我已经在没有 Eloquent 的情况下实现了这种关系,但我想知道是否有一种方法可以在 Eloquent 中定义这种关系,以便我的应用程序可以具有更高的一致性。

table User
    -id
    -other user attributes

table friend_requests:
    -id
    -sender_id
    -reciever_id

table friends
    -id
    -first
    -second

friendRequest 关系在 Eloquent 中很容易实现,但问题在于 Friends。

如果我在用户模型类中执行此操作:

public function friends(){
    return $this->belongsToMany(User::class,'friends','first','second');
}

这不会像您所注意到的那样起作用。让我用例子来解释一下:

Table: friends 
 id    |   first    | second  
 1     |   1        | 2  
 2     |   3        | 1  

您会看到

user_1
user_2
以及
user_3
都是朋友,因为这种关系是双向的。但 Eloquent 自然会返回
user_1
只与
user_2
是朋友。经过思考一段时间,我调整了声明,但进展甚微'

public function friends(){
    return $this->belongsToMany(User::class,'friends','first','second')
                ->orWhere('second',$this->id);
}

那是因为现在它选择了两行,但它返回的

User
是那些
id
=
second
的行,这意味着在第二种情况下它将返回用户本身。

我在

User
模型类中实现了我自己的方法的关系,该模型类使用
DB::table('friends')->
addFriend(User $user)
removeFriend(user $user)
并返回
friends()
列表,但我很失望,这不像
那么雄辩Eloquent
关系。

也许这里一些更有经验的开发人员会遇到这种问题,并且会比我处理得更好。你建议我如何处理这个问题。我应该坚持我的方法还是有更好的方法来处理它?

laravel eloquent
2个回答
2
投票

实现双向关系的更易于管理的方法是为每个已确认的友谊创建两个条目。

因此,一个用户会向另一个用户发出好友请求。当第二个用户确认好友请求时,就会创建两个好友。

示例控制器

<?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
        ]);
    }
}

数据库表

(注意

receiver
和复数
users
表的正确拼写)

table users
    - id
    - other user attributes

table friend_requests:
    - id
    - sender_id
    - receiver_id

table friendships
    - id
    - user_1_id
    - user_2_id

用户模型

<?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 模型

<?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');
    }
}

友谊模型

<?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');
    }
}

0
投票

我通过 union

morphToMany()
morphedByMany()
获得了双向关系,并使用了一些解决方法,如下所述:https://github.com/laravel/framework/discussions/50302

© www.soinside.com 2019 - 2024. All rights reserved.