Eloquent 關係圖例(譯)

ibucoin發表於2017-11-24

在學習Eloquent Model關係的時候,看官網的文件感覺自己理解得不夠透徹,基本上1對1,1對多,多對多有個模糊概念,當然,中文的翻譯文件給的例子也很不錯。找到了這麼一篇文章,我覺得很好的解決了我的疑問,文章為:Eloquent Relationships Cheat Sheet

Laravel 5.5的 Eloquent ORM 關係圖

一對一

Demo描述

在這個Demo中,我們有2個模型(Owner和Car)和2張表(owners, cars)

關係描述

車主(Owner)可以擁有1臺車(Car)
1臺車(Car)對應著1個車主(Owner)

關係圖表

關係圖描述

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

儲存資料

// 更新car和owner之間的關係
$owner->car()->save($car);
$car->owner()->associate($owner)->save();

注:兩個的效果其實是一樣的,都是更新Car列表中的owner_id。這樣一來,我們就無需使用以下這樣的更新方式。
Car::where('id',$car->id)->update(['owner_id' => $owner->id]);

獲取資料

//獲取當前Owner擁有的car
$owner->car;
//獲取當前car的Owner
$car->owner;

一對多關係

Demo 描述

注:原文用的是Thief,但是我認為我們可以將上文的Owner拿來用,即1個Owner可以擁有多輛Car,所以下面都進行了更改

在這邊,我們有2個模型(Owner和Car)和2張表(owners, cars)

關係描述

車主(Owner)可以擁有多臺車(Car)
1臺車(Car)只能對應著1個車主(Owner)

關係圖表

注:將Thief 當作是Owner

關係圖描述

Cars表中需要儲存 Owner ID外來鍵,用於查詢對應的車主

Eloquent 模型

class Owner
{
    public function cars()
    {
       return $this->hasMany(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');
});

儲存資料

// 更新car和owner之間的關係
這邊和上面就有些不太一樣了
$owner->cars()->saveMany([
   $car1, 
   $car2,
]);
一次性更新多臺車的owner_id
$owner->cars()->save($car);
獲取和上文一樣,更新單個model

$car->owner()->associate($owner)->save();

獲取資料

//獲取當前Owner擁有的car
$owner->cars;
//獲取當前car的Owner
$car->owner;

多型一對多關係

注:簡單解釋多型的概念,即一個模型在單個關聯上屬於多個其他模型,也就是1臺車屬於一個車主,但是車主可以是男或女兩個模型。

Demo 描述

在這個demo中,我們有3個模型(Man, Woman, Car),3張表(men, women, cars)

關係描述

Man(男買家) 可以賣多輛車(Cars)
Man(女買家) 可以賣多輛車(Cars)
一輛車只能屬於一個買家(Man or Woman)

關係圖表

關係圖描述

Car 表會儲存BuyerID和 BuyerType,其中的BuyerType可以是Man或者Woman這兩個model name,但不侷限於這兩個。

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();
    }
}
從這邊來說,我們將hasMany變成了morphMany,同時增加了一個buyer關係。而Car中的belongTo也變成了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->morphs(‘buyer’);
    //以下兩句可以被上面這句所替代
    //$table->integer('buyer_id')->unsigned()->index()->nullable();
    //$table->string('buyer_type')->nullable();   
});

儲存資料

//修改Car表中的資料
/*
$man:   id=1
$car1: id =1, buyer_id=null, buyer_type= null
經過操作後
$car1: id = 1, buyer_id=1, buyer_type= man
*/
$man->cars()->saveMany([
   $car1, 
   $car2,
]);
$woman->cars()->saveMany([
   $car1, 
   $car2,
]);

// 以下為單Model操作
$man->cars()->save($car);
$woman->cars()->save($car);

// 同上,變動的是buyer_id和buyer_type
$car1->buyer()->associate($man)->save();
$car2->buyer()->associate($woman)->save();

獲取資料

//獲取所屬的cars
$men->cars
$women->cars
// 獲取Car的buyer資料,Man或者Woman
$car->buyer

注:從上面幾個例子可知,不管是一對一,一對多,多型一對多,我們始終修改的都是Cars這張表對應的model外來鍵欄位。

多對多關係

Demo 描述

在這個demo中,我們有2個模型(Driver,Car), 3張表(drivers, cars,中間關聯表car_driver)

關係描述

一個司機(Driver)可以開不同型別的車(Cars)
一輛車(car)可以由不同人(Drivers)來駕駛

關係圖表

關係描述

中間關聯表 car_driver 儲存了兩張表的關聯id driver_idcar_id

Eloquent 模型

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

儲存資料

// 多資料儲存,更新關聯表的car_id
$driver->cars()->attach([
   $car1->id,
   $car2->id,
]);

// 反向操作,更新關聯表的driver_id
$car->drivers()->attach([
   $driver1->id,
   $driver2->id,
]);

獲取資料

// 獲取相關聯的cars
$driver->cars
// 獲取相關聯的drivers
$car->drivers

多型多對多關係

Demo描述

在這個Demo中,我們有3個模型(Valet, Owner,Car),4張表(valets, owners, cars, drivers)
注:在這邊的話,我認為valet和owner相對於drivers並不是特別妥當,但是你可以忽略它,當這兩個是drivers的兩個不同的普通型別,如Dad或者Mom

關係描述

Valet和Owner都屬於Drivers
1個Driver可以開多輛車(Cars)
1輛車也可以有不同的司機(Drivers,只是屬於不同的型別(Valet或Owner))

關係圖表

關係圖描述

由多對多可知,我們通過car_driver儲存了driver_id和car_id,對應driver和car表。但是多型多對多的情況下,我們需要的是model的對應關係是(Car和Valet, Owner直接的對應),所以中間關聯表drivers需要包含3個欄位:driver_id, driver_type, car_id。前兩個是多型對應Valet,Owner,後一個對應Car

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

由上面可知,belongToMany更換成了morphToMany,傳入了driver欄位。而Car model則更換成了morphedByMany,分別對應著不同的model

儲存資料

// 多資料處理
$valet->cars()->saveMany([$car1, $car2]);
$owner->cars()->saveMany([$car1, $car2]);

//單資料處理
$valet->cars()->save($car1);
$owner->cars()->save($car1);

//以下的處理方式不同
//多資料處理
$car->valets()->attach([
    $valet1->id,
    $valet2->id,
]);
$car->owners()->attach([
    $owner1->id,
    $owner2->id,
]);

獲取資料

// 獲取driver的相關cars
$valet->cars
$owner->cars
// 獲取car的相關drivers
$car->owners
$car->valets

總結關係圖


來自原文章

個人總結

如果對於關係概念不熟的,可以先看看Laravel5.5 中文文件。這篇文章主要是整合了例子和程式碼,我們可以按照程式碼手動的操作一遍,加深自己的理解。

對於翻譯這篇文章,感覺自己的底子薄弱,看英文理解不會太吃力,但是要想把它翻譯成可理解閱讀的中文實在是很困難,佩服那些翻譯文件的人員。

一入php深似海,從此c++是路人

相關文章