Laravel关系:一个与几个localKey关系的外键

时间:2019-01-12 18:30:49

标签: laravel model foreign-keys relationship has-many

我必须使用Laravel开发一个api,但我遇到了这个问题: 我需要获取所有匹配项,并且每次匹配都需要获取属于该匹配项的用户(每个匹配项有2个用户)

我已经找到了这个问题的答案,但我发现了这个https://github.com/topclaudy/compoships,但对我没有用。

到目前为止,我有这个:

class Match extends Model
{
    protected $table = 'matchs';

    public $primaryKey = 'id';

    public function playerOne() {
    return $this->hasMany('App\User', 'id', 'playerOne_id');
    }

    public function playerTwo() {
        return $this->hasMany('App\User', 'id', 'playerTwo_id');
    }
}

控制器方法:

public function index()
{
    $matchs = Match::with('playerOne', 'playerTwo')->orderBy('created_at', 'asc')->get();

    return $matchs; 
    //return new MatchsCollection($matchs);
}

和我的数据库如下所示: (匹配表)

id    | playerOne_id   | playertwo_id | winner_id | status 
------------------------------------------------------------
1     | 1              | 3            | 0         | PENDING
2     | 2              | 1            | 0         | PENDING
3     | 3              | 2            | 0         | PENDING

和用户表:

id    | name      | email           
-----------------------------------
1     | John      | John@email.com 
2     | Mark      | Mark@email.com
3     | Harry     | Harry@email.com

当我调用我的api时,我得到以下结果:

[
  {
    id: 1,
    playerOne_id: 1,
    playerTwo_id: 3,
    winner_id: 0,
    status: "PENDING",
    created_at: "2019-01-10 00:00:00",
    updated_at: null,
    users: [
      {
        id: 1,
        name: "John",
        email: "John@email.com",
        email_verified_at: null,
        created_at: "2019-01-11 10:38:26",
        updated_at: "2019-01-11 10:38:26"
      }
    ]
  },
  {
    id: 2,
    playerOne_id: 2,
    playerTwo_id: 1,
    winner_id: 0,
    status: "PENDING",
    created_at: "2019-01-11 08:26:28",
    updated_at: "2019-01-11 08:26:28",
    users: [
      {
        id: 2,
        name: "Mark",
        email: "Mark@email.com",
        email_verified_at: null,
        created_at: "2019-01-11 10:40:13",
        updated_at: "2019-01-11 10:40:13"
      }
    ]
  },
  {
    id: 3,
    playerOne_id: 3,
    playerTwo_id: 2,
    winner_id: 0,
    status: "PENDING",
    created_at: "2019-01-11 08:45:22",
    updated_at: "2019-01-11 08:45:22",
    users: [
      {
        id: 3,
        name: "harry",
        email: "harry@email.com",
        email_verified_at: null,
        created_at: "2019-01-11 10:40:13",
        updated_at: "2019-01-11 10:40:13"
      }
    ]
  }
]

我不想得到的是这个结果(我只是告诉你第一场比赛)

[
  {
    id: 1,
    playerOne_id: 1,
    playerTwo_id: 3,
    winner_id: 0,
    status: "PENDING",
    created_at: "2019-01-10 00:00:00",
    updated_at: null,
    users: [
      {
        id: 1,
        name: "John",
        email: "John@email.com",
        email_verified_at: null,
        created_at: "2019-01-11 10:38:26",
        updated_at: "2019-01-11 10:38:26"
      },
      {
        id: 3,
        name: "Harry",
        email: "Harry@email.com",
        email_verified_at: null,
        created_at: "2019-01-11 10:38:26",
        updated_at: "2019-01-11 10:38:26"
      }
    ]
  }
]

在Laravel中这可能吗?谢谢:)

1 个答案:

答案 0 :(得分:0)

为了能够将所有玩家作为user数组的一部分返回,您可以将MatchUser之间的关系更改为belongsToMany (many-to-many)或简单地进行操作从控制器返回匹配数据之前。

将其更改为BelongsToMany是我的建议,因为从语义上讲它更有意义,但是,我知道(取决于您到目前为止已完成的工作量)它可能不切实际。

您需要:

  1. matchs表重命名为matches(这也意味着您可以删除
    protected $table = 'matchs';模型类中的Match
  2. 创建一个名为match_user的表。如果您的项目正在使用迁移,则可以运行:
    php artisan make:migration create_match_user_table --create=match_user
    在该迁移中,您需要将up()方法的内容更改为:

    public function up()
    {
        Schema::create('match_user', function (Blueprint $table) {
            $table->integer('match_id')->unsigned();
            $table->integer('user_id')->unsigned();
            $table->timestamps();
    
            $table->primary(['match_id', 'user_id']);
        });
    }
    
  3. 运行php artisan migrate

  4. 在您的Match模型中,将users()关系更改为:

    public function users()
    {
        return $this->belongsToMany(User::class)->withTimestamps();
    }
    
  5. 如果表中的数据是虚拟数据,则可以跳过此步骤。否则,您需要将playerOne_idplayertwo_id信息移到新的数据透视表中。您可以执行以下操作:

    Match::all()->each(function ($match) {
        $match->users()->attach([$match->playerOne_id, $match->playertwo_id]);
    });
    

    在何处运行它并不重要,因为它只需运行一次,因此在运行它之后可以将其删除。我通常会在路线或修补程序中运行它。

  6. 然后进行清理。同样,如果您拥有的数据只是虚拟数据,那么我只需要删除原始迁移的playerOne_idplayertwo_id,否则创建一个删除那些字段Dropping columns docs


完成上述操作后,您只需在控制器中执行以下操作即可获得结果:

$matches = Match::with('users')->latest()->get();