Laravel Eloquent 模型关联速查表

file

一張 Laravel’s Eloquent ORM 5.5 的速查表

一對一關聯

展示細節:

在這個展示中,我們有 2 個模型(Owner 和 Car)及兩張表(owners 和 cars)。

商業邏輯:

一個使用者可以擁有一台車。
一台車可以有一個擁有者。

關聯圖:

file

關聯細節:

Cars 表必須儲存 Owner ID。

Eloquent 模型:

class Owner
{
    public function car()
    {
       return $this->hasOne(Car::class);
    }
}
class Car
{
    public function owner()
    {
        return $this->belongsTo(Owner::class);
    }
}

資料庫遷移:

Schema::create('owners', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
});
Schema::create('cars', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->integer('owner_id')->unsigned()->index()->nullable();
    $table->foreign('owner_id')->references('id')->on('owners');
});

儲存紀錄:

// 在 Owner 及 Car 之間建立關聯
$owner->car()->save($car);
// 在 Car 及 Owner 之間建立關聯
$car->owner()->associate($owner)->save();

取得紀錄:

// 取得 Owner Car
$owner->car;
// 取得 Car Owner
$car->owner;

一对多关联

示例细节:

在此示例中,我们有两个模型:Thief (小偷) 和 Car (车),和两张表:
thieves 和 cars 。

业务规则:

小偷可以偷走多辆车。
车只能被一个小偷偷走。

关系图:

file

关系细节:

车辆表应该存储小偷的 ID 。

Eloquent 模型:

class Thief
{
    public function cars()
    {
       return $this->hasMany(Car::class);
    }
}
class Car
{
    public function thief()
    {
        return $this->belongsTo(Thief::class);
    }
}

数据迁移:

Schema::create('thieves', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
});
Schema::create('cars', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->integer('thief_id')->unsigned()->index()->nullable();
    $table->foreign('thief_id')->references('id')->on('thieves');
});

记录存储:

// 创建介于小偷与车之间的关联。
$thief->cars()->saveMany([
   $car1, 
   $car2,
]);
// 或者在单一模型调用 save() 方法。
$thief->cars()->save($car);
// 创建介于 Car 和 Thief 的关联。
$car->thief()->associate($thief)->save();

拉取记录:

// 获取小偷所偷的车
$thief->cars;
// 获取偷盗某辆车的小偷
$car->thief;

多态一对多关系

演示细节:

在这个演示中,我们有三个模型(Man, Woman 和 Car),和三张表(man, women 和 cars)。

业务规则:

一个男人(买家)可以买很多汽车。
一个女人(买家)可以买很多汽车。
这个汽车可以被一个买家购买(男人或女人)。

关系图:

file

关系详情:

Car表应该储存买家 ID 和买家类型。
"buyer" 是一组模型名称 (男人 和 女人), 它不仅限于两者,buyer 类型是模型的真实名称 。

Eloquent 模型:

class Man
{
    public function cars()
    {
        return $this->morphMany(Car::class, 'buyer');
    }
}
class Woman
{
    public function cars()
    {
        return $this->morphMany(Car::class, 'buyer');
    }
}
class Car
{
    public function buyer()
    {
        return $this->morphTo();
    }
}

数据库迁移:

Schema::create('men', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
});
Schema::create('women', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
});
Schema::create('cars', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->integer('buyer_id')->unsigned()->index()->nullable();
    $table->string('buyer_type')->nullable();   
    // 或者使用 $table->morphs(‘buyer’); 代替 "buyer_id" 和 "buyer_type"
});

储存记录:

// 在买家 (男人 / 女人) 和汽车之间建立联系。
$man->cars()->saveMany([
   $car1, 
   $car2,
]);
$woman->cars()->saveMany([
   $car1, 
   $car2,
]);
// 或者为单个模型使用 save() 函数。
$man->cars()->save($car);
$woman->cars()->save($car);
//创建汽车与买家之间的关系 ( 男人/女人 )。
$car1->buyer()->associate($man)->save();
$car2->buyer()->associate($woman)->save();

检索记录:

// 获取买家 (男人 / 女人)的汽车
$men->cars
$women->cars
// 获取这辆车的买家 (男人 / 女人)
$car->buyer

多对多关联

示例展示:

在这个示例中,我们有两个模型(Driver 和 Car),和三张表
(drivers,名为 car_driver的中间关联表).

业务规则:

一个司机可以驾驶很多辆车。
一辆车可以被很多个司机开。

关系图:

文件

关联详情:

关联表"car_driver"应该保存驾驶员ID和汽车ID。

关联模型:

class Driver
{
    public function cars()
    {
       return $this->belongsToMany(Car::class);
    }
}
class Car
{
    public function drivers()
    {
        return $this->belongsToMany(Driver::class);
    }
}

数据库迁移:

Schema::create('drivers', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
});
Schema::create('cars', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
});
Schema::create('car_driver', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('car_id')->unsigned()->index();
    $table->foreign('car_id')->references('id')->on('cars')->onDelete('cascade');
    $table->integer('driver_id')->unsigned()->index();
    $table->foreign('driver_id')->references('id')->on('drivers')->onDelete('cascade');
});

保存记录:

//创建Driver和Car之间的关联。
$driver->cars()->attach([
   $car1->id,
   $car2->id,
]);
//或者使用sync()函数防止重复关联。
$driver->cars()->sync([
   $car1->id,
   $car2->id,
]);
//创建Car和Driver之间的关联。
$car->drivers()->attach([
   $driver1->id,
   $driver2->id,
]);
//或者使用sync()函数防止重复关联。
$car->drivers()->sync([
   $driver1->id,
   $driver2->id,
]);

查询记录:

// Get Driver Car
$driver->cars
// Get Car Drivers
$car->drivers

多對多多態關聯

展示細節:

在這個展示中我們有三個模型(Valet、Owner 及 Car)和 4 張表(valets、owners、cars 及 drivers)。

商業邏輯:

一個代駕(司機)可以駕駛很多輛車
一個車主(司機)可以駕駛很多輛車
一台車可以被很多個司機駕駛(代駕和 / 或車主)

關聯圖

file

關聯細節:

中間表「drivers」應該儲存駕駛人 ID、駕駛人類型及車輛 ID。
駕駛是一個模型集合的代稱(Valet 及 Owner),而且不限定兩個模型。駕駛人類型是模型的真正名稱。

Eloquent 模型:

class Valet
{
    public function cars()
    {
        return $this->morphToMany(Car::class, 'driver');
    }
}
class Owner
{
    public function cars()
    {
        return $this->morphToMany(Car::class, 'driver');
    }
}
class Car
{
    public function valets()
    {
        return $this->morphedByMany(Valet::class, 'driver');
    }

    public function owners()
    {
        return $this->morphedByMany(Owner::class, 'driver');
    }
}

資料庫遷移:

Schema::create('valets', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
});
Schema::create('owners', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
});
Schema::create('drivers', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('driver_id')->unsigned()->index();
    $table->string('driver_type');
    // 或使用 $table->morphs(‘driver’) 來取代「driver_id」和「driver_type」
    $table->integer('car_id')->unsigned()->index();
    $table->foreign('car_id')->references('id')->on('cars')->onDelete('cascade');
});

儲存紀錄:

// 在 driver(Valet / Owner)和 Car 間建立關聯
$valet->cars()->saveMany([$car1, $car2]);
$owner->cars()->saveMany([$car1, $car2]);
// 或使用 save() 方法來儲存單一模型
$valet->cars()->save($car1);
$owner->cars()->save($car1);
// 在 Car 和 driver(Valet / Owner)間建立關聯
$car->valets()->attach([
    $valet1->id,
    $valet2->id,
]);
$car->owners()->attach([
    $owner1->id,
    $owner2->id,
]);
// 或是用 sync() 方法來避免重複關聯
$car->valets()->sync([
    $valet1->id,
    $valet2->id,
]);
$car->owners()->sync([
    $owner1->id,
    $owner2->id,
]);

取得紀錄:

// 取得 driver(Valet / Owner)的 Cars
$valet->cars
$owner->cars

// 取得 Car 的 drivers(Valet 及 Owner)
$car->owners
$car->valets

file

更多现代化 PHP 知识,请前往 Laravel / PHP 知识社区

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容

  • http://big5.china.com/gate/big5/auto.china.com/life/more/...
    wokeman阅读 2,514评论 0 1
  • 中文名稱(Chinese name): 月球漫步者 英文名稱(English name): MOONWALKER ...
    JENTSON阅读 1,210评论 0 2
  • 说不定哪天。 我自己就懒死了
    radio阅读 205评论 0 1
  • 人生就像是一场旅行,你看到的是阳光,那就是阳光,你看到的是阴霾,那就是阴霾。 人生就像是一次选择,你想到是前方,那...
    前度小花静院阅读 180评论 1 1
  • 今天学习每股收益,反映的是每一份股票给股东带来的收益。 学习财报需要反复计算练习思考 不要短期希望过高,长期希望过...
    浩苒阅读 193评论 0 1