如何更快的找到自己所需的模型關聯型別?

finecho發表於2018-12-21

@這是小豪的第一篇文章
這遍文章主要的目的就是讓大家能夠更快捷的找到自己所需的模型關聯型別。

模型關聯有哪些關聯型別 ?

一對一關聯

已知我們有兩張表 usersid_cards
從生活常識中我們可以得到兩個資訊:

  • 使用者 -> 有且只有一個身份證(普通人、普通人。。。。)
  • 身份證 -> 有且只有一個使用者 ( 依賴使用者而存在 )

好現在看看,Laravel 是如何將上面這種文字轉換為程式碼的:

class User extends Model
{
    /**
     * 獲取與使用者關聯的身份證。
     */
    public function idCard()
    {
        return $this->hasOne('App\IdCard');
    }
}
class IdCard extends Model
{
    /**
     * 獲得擁有此身份證的使用者。
     */
    public function user()
    {
        return $this->belongsTo('App\User');
    }
}

從上面的程式碼中我們可以看到有且只有一個分別被轉化為了 hasOnebelongsTo , 單獨從這兩個單詞的字面意思上就可以很清楚的理解為什麼是這樣,擁有屬於。使用者有一個身份證、身份證屬於一個人。在整個模型關係中,凡是為身份證這種有且只有一個主體的時候,都是使用belongsTo

如何去使用呢 ?很簡單!

$idCard = User::find(1)->idCard;
$user = IdCard::find(1)->user;

其實反向關聯並不是強制要求的,看自己需求,像現在通過手機號去拿使用者也不是很常用。

:關聯外來鍵就不在這裡詳細說明了

一對多關聯

已知我們有兩張表 userssocks
繼續從生活常識中獲取資訊:

  • 使用者 -> 襪子有很多
  • 襪子 -> 有且只有一個使用者 ( 依賴使用者而存在 )

從上面的資訊中大家有沒有發現,襪子和上面一對一模型關聯中的身份證的型別是一致的,是的,你的襪子總是你一個人的吧,難不成和別人共襪? 哈哈,所以可以輕易得出襪子的反向關聯為:

class Sock extends Model
{
    /**
     * 獲得擁有此襪子的使用者。
     */
    public function user()
    {
        return $this->belongsTo('App\User');
    }
}

至於使用者嘛,有很多襪子:

class User extends Model
{
    /**
     * 獲取與使用者關聯的襪子。
     */
    public function socks()
    {
        return $this->hasMany('App\Sock');
    }
}

一目瞭然哈,有很多襪子,大家在寫關聯的時候,記得加s.......習慣要養好。
模型關係定義好了,接下來是如何使用:
這裡是好多雙襪子

$socks = User::find(1)->socks;
$user = Sock::find(1)->user;

瞭解完一對一模型關聯一對多模型關聯後,不知道大家是不是有種後悔早點進入 Laravel 世界的感覺,優雅吧,哈哈。

多對多關聯

現在我們接到了一個需求:實現使用者角色管理
從需求中我們知道了如下資訊:

  • 一個使用者有可以有多個角色
  • 一個角色有多個使用者

這兩條資訊告訴我們,使用者和角色的關聯型別是一一致的

那麼我們現在來確定關聯表的設計:
使用者表:users
角色表:roles
使用者角色中間表:role_user

我們可能首先想到的是 hasMany,但是畢竟他們兩者沒有絕對的主體客體之分,兩個 hasMany 豈不是兩邊一直在爭主體呀,不如兩者都退後一步 belongsToMany,退一步海闊天空嘛,哈哈。現在我們來看看具體的實現:

class User extends Model
{
    /**
     * 使用者的角色
     */
    public function roles()
    {
        return $this->belongsToMany('App\Role');
    }
}
class Role extends Model
{
    /**
     * 擁有此角色的使用者
     */
    public function users()
    {
        return $this->belongsToMany('App\User');
    }
}

有沒有很和諧的感覺。
關係建立好了,現在我們來看看如何去查詢使用。
獲取使用者角色:

$roles =  User::find(1)->roles;

獲取角色使用者:

$users = Role::find(1)->users;

如果需要獲取使用者繫結角色的時間呢,這個時候就會有點蒙了,改怎麼查呢,Laravel 已經跟我們處理好了,通過pivot來獲取中間表的資料:

$user = App\User::find(1);

foreach ($user->roles as $role) {
    echo $role->pivot->created_at;
}

一般來說中間表都是隻存兩個表的外來鍵,如果有需要更多的欄位呢可以使用 withPivot

return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');

至此,多對多的模型關聯就結束了,當然裡面還有很多細節的東西噢,後面的文章會更加詳細的講解,哈哈哈。

多型關聯

顧名思義,並不侷限於單獨的一種型別狀態,下面我們就來見識見識什麼叫多型關聯。

現在的需求是:文章、視訊都可評論。
當得到這個需求的時候,我們可能會思考評論表中是不是該有個欄位用來儲存是對哪種型別的評論。!對,當想到這裡的時候,多型就來了,型別可以跟著評論的主體而變化。

從需求中我們知道了如下資訊:

  • 一篇文章可以有多個評論
  • 一個視訊可以有多個評論
  • 一個評論可以有一個文章主體或一個視訊主體

好,到這裡我們開始設計表了:
視訊表:videos
文章表:posts
評論表:comments
評論表中有這兩個欄位:commentable_typecommentable_id 分別儲存評論主體資訊
第一時間我們想到的是 hasMany ,但是為了區分多型,Laravel 提供給我們的模型關聯方法為 morphMany ,其實有點不太好理解了哈,變形為很多是個什麼意思,我們來看一下 comments 的反向關聯就知道了。

class Comment extends Model
{
    /**
     * 獲得擁有此評論的模型。
     */
    public function commentable()
    {
        return $this->morphTo();
    }
}

morphTo,“變形為”。因為不確定評論的主體型別是什麼,所以我們給了一個模糊的 commentable,通過morphTo 變形為所需的評論模型,至此 morphMany 的由來也說得通了,哈哈。現在來看一下文章和視訊模型中對評論模型的關聯處理:

class Post extends Model
{
    /**
     * 獲得此文章的所有評論。
     */
    public function comments()
    {
        return $this->morphMany('App\Comment', 'commentable');
    }
}
class Video extends Model
{
    /**
     * 獲得此視訊的所有評論。
     */
    public function comments()
    {
        return $this->morphMany('App\Comment', 'commentable');
    }
}

可以看到 morphMany 裡面都有接收兩個引數,第一個是評論模型,第二個是用來儲存主體型別和Id的 name ,也就是說要是 comments 表中用來儲存主體型別和Id的名稱為 a_typea_id 這個時候第二個引數就為 a。具體的使用和上面的是一致的,這裡就不多說了。

總的來說呢,多型關聯就是主體不確定,客體需要儲存主體型別加以判斷。

多對多多型關聯

理解上面的多型關聯之後,就可以很快的理解現在要講的 多對多多型關聯 了, 多對多多型關聯 揉和了多對多關聯與多型關聯。這樣我們就可以得到兩個關鍵資訊:

  • 型別不確定
  • 中間表

下面我們就用一個例項來講解一下:
要求:文章、視訊都有標籤
你可能會想,這不是和上面的多型關聯是一樣的嗎,其實不一樣,一個評論只對應一個文章或視訊,但是一個標籤可能對應多篇文章、多個視訊,這樣就能理解中間表的作用了吧,現在我們來設計表:

視訊表:videos
文章表:posts
標籤表:tags
中間表:taggables
中間表中有這三個欄位:tag_idtaggable_idtaggable_type
具體的實現:

class Post extends Model
{
    /**
     * 獲取文章標籤
     */
    public function tags()
    {
        return $this->morphToMany('App\Tag', 'taggable');
    }
}
class Tag extends Model
{
    /**
     * 獲取擁有這個標籤的文章
     */
    public function posts()
    {
        return $this->morphedByMany('App\Post', 'taggable');
    }

    /**
     *獲取擁有這個標籤的視訊
     */
    public function videos()
    {
        return $this->morphedByMany('App\Video', 'taggable');
    }
}

具體的使用方法,和上面是一樣的。

如何選擇合適的模型關聯 ?

如何去選擇合適的模型關聯呢?下面給一些自己的想法給大家參考一下:

  1. 行為日誌

    • 主體不確定
    • 一個行為日誌對應一個主體
      ----- 通過這兩點可以得出模型關聯為:多型關聯
  2. 使用者文章

    • 主體確定
    • 一個文章一個使用者
      ----- 通過這兩點可以得出模型關聯為:1對多關聯
  3. 標籤

    • 主體不確定
    • 一個標籤多個主體
      ----- 通過這兩點可以得出模型關聯為:多對多多型關聯

    。。。。。。

以上只是冰山一角,還有更關聯模型組合,待我慢慢總結完善,哈哈。。。。

這是小豪的邁出的第一步,文章中不夠完善嚴謹的地方還請大家指正,共同進步,我後面也會慢慢去完善改進這篇文章。

finecho # Lhao

相關文章