Laravel,与多个模型的多对多关系
Laravel, many-to-many relationship to multiple models
在 Laravel 5 中寻找执行以下操作的简单方法。
想象一下这些模型和界面
- 比赛
- 用户
- 团队
- 参与者(用户和团队实现的接口)
比赛与参赛者之间存在多对多关系,参赛者可以是用户,也可以是团队。所以我需要 competition_participant 枢轴 table 以下列来定义模型
- competition_id
- participant_id
- participant_type
但是我如何在竞争模型上编写关系,以便它知道应该从数据库中获取哪个模型,同时 return 混合模型或接口类型的集合?
这只是 Laravel documentation about many to many polymorphic relationships 的复制粘贴。
为了帮助您更好地理解,这是您的模型与 Laravel 文档中的模型之间的映射:
users == posts
teams == videos
competitions == tags
competitionables == tags
这是您应该如何实现多态关系,请记住,每当您感到困惑时,只需查看文档以及您的模型与文档模型之间的映射:
表格:
users
id - integer
name - string
teams
id - integer
name - string
competitions
id - integer
name - string
competitionables
competition_id - integer
competitionable_id - integer
competitionable_type - string
模型结构
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get all of the Competition for the user.
*/
public function competitions()
{
return $this->morphToMany('App\Competition', 'competitionable');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Team extends Model
{
/**
* Get all of the Competition for the Team.
*/
public function competitions()
{
return $this->morphToMany('App\Competition', 'competitionable');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Competition extends Model
{
/**
* Get all of the users that are assigned to this Competition.
*/
public function users()
{
return $this->morphedByMany('App\User', 'competitionable');
}
/**
* Get all of the Teams that are assigned to this Competition.
*/
public function teams()
{
return $this->morphedByMany('App\Video', 'competitionable');
}
}
检索关系
$user = App\User::find(1);
foreach ($user->competitions as $competition) {
//
}
或者反过来
$competition = App\Competition::find(1);
foreach ($competition->users as $user) {
// do something with your users
}
foreach ($competition->teams as $team) {
// do something with your teams
}
您对哪些 table 应该得到哪些列有些困惑。
您的参与者 table 需要成为 table 才能管理 users
和 teams
的多态关系。它至少收到 particpatable_id
和 particpatable_type
以及 id
和 timestamps()
。
然后你需要一个额外的 table 叫做 competition_participant
它将管理 competitions
和你的多态 table participants
.
这将使您能够将 participants
与 competitions
联系起来。这样,您可以通过比赛获取所有参与者,调用它的 $participant->participatable
属性,这将 return 是 App\User
或 App\Team
取决于参与者的类型.
这都是经过测试的。
迁移
public function up()
{
Schema::create('competitions', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('teams', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('participants', function(Blueprint $table) {
$table->increments('id');
$table->integer('participatable_id');
$table->string('participatable_type');
$table->timestamps();
});
Schema::create('competition_participant', function(Blueprint $table) {
$table->integer('competition_id');
$table->integer('participant_id');
});
}
型号
class Competition extends Model
{
public function participants()
{
return $this->belongsToMany(Participant::class);
}
}
class Participant extends Model
{
public function participatable()
{
return $this->morphTo();
}
public function competitions()
{
return $this->belongsToMany(Competition::class);
}
}
class Team extends Model
{
public function participants()
{
return $this->morphMany(Participant::class, 'participatable');
}
}
class User extends Authenticatable
{
public function participants()
{
return $this->morphMany(Participant::class, 'participatable');
}
}
种子
public function run()
{
$faker = Faker\Factory::create();
// Seed Users Table
DB::table('users')->delete();
$users = [];
for($i = 0; $i < 100; $i++) {
$users[] = [
'name' => $faker->name,
'email' => $faker->email,
'password' => Hash::make($faker->password),
'created_at' => new DateTime,
'updated_at' => new DateTime
];
}
DB::table('users')->insert($users);
// Seed Teams Table
DB::table('teams')->delete();
$teams = [];
for($i = 0; $i < 20; $i++) {
$teams[] = [
'name' => 'Team ' . ucwords($faker->domainWord),
'created_at' => new DateTime,
'updated_at' => new DateTime
];
}
DB::table('teams')->insert($teams);
// Seed Participants Table
DB::table('participants')->delete();
// Insert some of our users as participants
$users = App\User::limit(20)->orderByRaw('rand()')->get();
foreach($users as $user) {
$user->participants()->create([]);
}
// Insert some of the teams as participants
$teams = App\Team::limit(10)->orderByRaw('rand()')->get();
foreach($teams as $team) {
$team->participants()->create([]);
}
// Seed Competitions Table
DB::table('competitions')->delete();
$competitions = [];
for($i = 0; $i < 10; $i++) {
$competitions[] = [
'name' => $faker->company,
'created_at' => new DateTime,
'updated_at' => new DateTime,
];
}
DB::table('competitions')->insert($competitions);
// Seed Competitions Participants Relationships
DB::table('competition_participant')->delete();
// Sign up each participant to 3 random competitions
$participants = App\Participant::all();
$competitions = App\Competition::all();
foreach($participants as $participant) {
$participant->competitions()->sync($competitions->shuffle()->take(3));
}
}
用法
$competition = App\Competition::with('participants')->has('participants')->first();
foreach($competition->participants as $participant) {
echo get_class($participant->participatable); // Will output either App\User or App\Team
echo "<br />";
}
在 Laravel 5 中寻找执行以下操作的简单方法。
想象一下这些模型和界面
- 比赛
- 用户
- 团队
- 参与者(用户和团队实现的接口)
比赛与参赛者之间存在多对多关系,参赛者可以是用户,也可以是团队。所以我需要 competition_participant 枢轴 table 以下列来定义模型
- competition_id
- participant_id
- participant_type
但是我如何在竞争模型上编写关系,以便它知道应该从数据库中获取哪个模型,同时 return 混合模型或接口类型的集合?
这只是 Laravel documentation about many to many polymorphic relationships 的复制粘贴。
为了帮助您更好地理解,这是您的模型与 Laravel 文档中的模型之间的映射:
users == posts
teams == videos
competitions == tags
competitionables == tags
这是您应该如何实现多态关系,请记住,每当您感到困惑时,只需查看文档以及您的模型与文档模型之间的映射:
表格:
users
id - integer
name - string
teams
id - integer
name - string
competitions
id - integer
name - string
competitionables
competition_id - integer
competitionable_id - integer
competitionable_type - string
模型结构
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get all of the Competition for the user.
*/
public function competitions()
{
return $this->morphToMany('App\Competition', 'competitionable');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Team extends Model
{
/**
* Get all of the Competition for the Team.
*/
public function competitions()
{
return $this->morphToMany('App\Competition', 'competitionable');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Competition extends Model
{
/**
* Get all of the users that are assigned to this Competition.
*/
public function users()
{
return $this->morphedByMany('App\User', 'competitionable');
}
/**
* Get all of the Teams that are assigned to this Competition.
*/
public function teams()
{
return $this->morphedByMany('App\Video', 'competitionable');
}
}
检索关系
$user = App\User::find(1);
foreach ($user->competitions as $competition) {
//
}
或者反过来
$competition = App\Competition::find(1);
foreach ($competition->users as $user) {
// do something with your users
}
foreach ($competition->teams as $team) {
// do something with your teams
}
您对哪些 table 应该得到哪些列有些困惑。
您的参与者 table 需要成为 table 才能管理 users
和 teams
的多态关系。它至少收到 particpatable_id
和 particpatable_type
以及 id
和 timestamps()
。
然后你需要一个额外的 table 叫做 competition_participant
它将管理 competitions
和你的多态 table participants
.
这将使您能够将 participants
与 competitions
联系起来。这样,您可以通过比赛获取所有参与者,调用它的 $participant->participatable
属性,这将 return 是 App\User
或 App\Team
取决于参与者的类型.
这都是经过测试的。
迁移
public function up()
{
Schema::create('competitions', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('teams', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('participants', function(Blueprint $table) {
$table->increments('id');
$table->integer('participatable_id');
$table->string('participatable_type');
$table->timestamps();
});
Schema::create('competition_participant', function(Blueprint $table) {
$table->integer('competition_id');
$table->integer('participant_id');
});
}
型号
class Competition extends Model
{
public function participants()
{
return $this->belongsToMany(Participant::class);
}
}
class Participant extends Model
{
public function participatable()
{
return $this->morphTo();
}
public function competitions()
{
return $this->belongsToMany(Competition::class);
}
}
class Team extends Model
{
public function participants()
{
return $this->morphMany(Participant::class, 'participatable');
}
}
class User extends Authenticatable
{
public function participants()
{
return $this->morphMany(Participant::class, 'participatable');
}
}
种子
public function run()
{
$faker = Faker\Factory::create();
// Seed Users Table
DB::table('users')->delete();
$users = [];
for($i = 0; $i < 100; $i++) {
$users[] = [
'name' => $faker->name,
'email' => $faker->email,
'password' => Hash::make($faker->password),
'created_at' => new DateTime,
'updated_at' => new DateTime
];
}
DB::table('users')->insert($users);
// Seed Teams Table
DB::table('teams')->delete();
$teams = [];
for($i = 0; $i < 20; $i++) {
$teams[] = [
'name' => 'Team ' . ucwords($faker->domainWord),
'created_at' => new DateTime,
'updated_at' => new DateTime
];
}
DB::table('teams')->insert($teams);
// Seed Participants Table
DB::table('participants')->delete();
// Insert some of our users as participants
$users = App\User::limit(20)->orderByRaw('rand()')->get();
foreach($users as $user) {
$user->participants()->create([]);
}
// Insert some of the teams as participants
$teams = App\Team::limit(10)->orderByRaw('rand()')->get();
foreach($teams as $team) {
$team->participants()->create([]);
}
// Seed Competitions Table
DB::table('competitions')->delete();
$competitions = [];
for($i = 0; $i < 10; $i++) {
$competitions[] = [
'name' => $faker->company,
'created_at' => new DateTime,
'updated_at' => new DateTime,
];
}
DB::table('competitions')->insert($competitions);
// Seed Competitions Participants Relationships
DB::table('competition_participant')->delete();
// Sign up each participant to 3 random competitions
$participants = App\Participant::all();
$competitions = App\Competition::all();
foreach($participants as $participant) {
$participant->competitions()->sync($competitions->shuffle()->take(3));
}
}
用法
$competition = App\Competition::with('participants')->has('participants')->first();
foreach($competition->participants as $participant) {
echo get_class($participant->participatable); // Will output either App\User or App\Team
echo "<br />";
}