Laravel 关系:一个foreignKey 对应多个localKey 关系
Laravel relationship : one foreignKey for several localKey relationship
我必须用 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);
}
我的数据库如下所示:
(匹配 table)
id | playerOne_id | playertwo_id | winner_id | status
------------------------------------------------------------
1 | 1 | 3 | 0 | PENDING
2 | 2 | 1 | 0 | PENDING
3 | 3 | 2 | 0 | PENDING
和用户 table :
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 中可能吗?谢谢:)
为了能够 return 所有玩家作为 user
数组的一部分,您可以将 Match
和 User
之间的关系更改为 belongsToMany (many-to-many) 或在 return 从控制器获取匹配数据之前简单地操作匹配数据。
将其更改为 BelongsToMany
是我的建议,因为它在语义上更有意义,但是,我知道(取决于您到目前为止所做的工作量)它可能不切实际。
您需要:
- 将您的
matchs
table 重命名为 matches
(这也意味着您可以删除
protected $table = 'matchs';
来自您的 Match
型号 class ).
创建一个名为 match_user
的 table。如果您的项目正在使用迁移,那么您可以 运行:
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']);
});
}
运行 php artisan migrate
在您的 Match
模型中,将 users()
关系更改为:
public function users()
{
return $this->belongsToMany(User::class)->withTimestamps();
}
如果您在 table 中的数据是虚拟数据,您可以跳过此步骤。否则,您需要将 playerOne_id
和 playertwo_id
信息移动到新的枢轴 table。您可以执行以下操作:
Match::all()->each(function ($match) {
$match->users()->attach([$match->playerOne_id, $match->playertwo_id]);
});
你在哪里 运行 这并不重要,因为它只需要 运行 一次,所以在你 运行 它之后你可以删除它。我通常会 运行 在路线或修补程序中这样做。
然后是清理。同样,如果您拥有的数据只是虚拟数据,那么我只会删除 playerOne_id
和 playertwo_id
原始迁移,否则创建一个新的迁移来删除这些字段 Dropping columns docs
完成上述操作后,您只需在控制器中执行以下操作即可获得结果:
$matches = Match::with('users')->latest()->get();
我必须用 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);
}
我的数据库如下所示: (匹配 table)
id | playerOne_id | playertwo_id | winner_id | status
------------------------------------------------------------
1 | 1 | 3 | 0 | PENDING
2 | 2 | 1 | 0 | PENDING
3 | 3 | 2 | 0 | PENDING
和用户 table :
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 中可能吗?谢谢:)
为了能够 return 所有玩家作为 user
数组的一部分,您可以将 Match
和 User
之间的关系更改为 belongsToMany (many-to-many) 或在 return 从控制器获取匹配数据之前简单地操作匹配数据。
将其更改为 BelongsToMany
是我的建议,因为它在语义上更有意义,但是,我知道(取决于您到目前为止所做的工作量)它可能不切实际。
您需要:
- 将您的
matchs
table 重命名为matches
(这也意味着您可以删除
protected $table = 'matchs';
来自您的Match
型号 class ). 创建一个名为
match_user
的 table。如果您的项目正在使用迁移,那么您可以 运行:
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']); }); }
运行
php artisan migrate
在您的
Match
模型中,将users()
关系更改为:public function users() { return $this->belongsToMany(User::class)->withTimestamps(); }
如果您在 table 中的数据是虚拟数据,您可以跳过此步骤。否则,您需要将
playerOne_id
和playertwo_id
信息移动到新的枢轴 table。您可以执行以下操作:Match::all()->each(function ($match) { $match->users()->attach([$match->playerOne_id, $match->playertwo_id]); });
你在哪里 运行 这并不重要,因为它只需要 运行 一次,所以在你 运行 它之后你可以删除它。我通常会 运行 在路线或修补程序中这样做。
然后是清理。同样,如果您拥有的数据只是虚拟数据,那么我只会删除
playerOne_id
和playertwo_id
原始迁移,否则创建一个新的迁移来删除这些字段 Dropping columns docs
完成上述操作后,您只需在控制器中执行以下操作即可获得结果:
$matches = Match::with('users')->latest()->get();