多態(tài)關(guān)聯(lián)

版本 功能調(diào)整
5.0.8 支持多態(tài)一對(duì)一關(guān)聯(lián)
5.0.4 支持多態(tài)一對(duì)多關(guān)聯(lián)

多態(tài)一對(duì)多關(guān)聯(lián)(V5.0.4+

多態(tài)關(guān)聯(lián)允許一個(gè)模型在單個(gè)關(guān)聯(lián)定義方法中從屬一個(gè)以上其它模型,例如用戶可以評(píng)論書和文章,但評(píng)論表通常都是同一個(gè)數(shù)據(jù)表的設(shè)計(jì)。多態(tài)一對(duì)多關(guān)聯(lián)關(guān)系,就是為了滿足類似的使用場(chǎng)景而設(shè)計(jì)。

下面是關(guān)聯(lián)表的數(shù)據(jù)表結(jié)構(gòu):

article
    id - integer
    title - string
    content - text

book
    id - integer
    title - string

comment
    id - integer
    content - text
    commentable_id - integer
    commentable_type - string

有兩個(gè)需要注意的字段是 comment 表中的 commentable_id 和 commentable_type我們稱之為多態(tài)字段。其中, commentable_id 用于存放書或者文章的 id(主鍵) ,而 commentable_type 用于存放所屬模型的類型。通常的設(shè)計(jì)是多態(tài)字段有一個(gè)公共的前綴(例如這里用的commentable),當(dāng)然,也支持設(shè)置完全不同的字段名(例如使用data_idtype)。

多態(tài)關(guān)聯(lián)定義

接著,讓我們來(lái)查看創(chuàng)建這種關(guān)聯(lián)所需的模型定義:

文章模型:

<?php
namespace app\index\model;

use think\Model;

class Article extends Model
{
    /**
     * 獲取所有針對(duì)文章的評(píng)論。
     */
    public function comments()
    {
        return $this->morphMany('Comment', 'commentable');
    }
}

morphMany方法的參數(shù)如下:

morphMany('關(guān)聯(lián)模型名','多態(tài)字段信息','多態(tài)類型');

關(guān)聯(lián)模型名(必須):關(guān)聯(lián)的模型名稱,可以使用模型名(如Comment)或者完整的命名空間模型名(如app\index\model\Comment)。

多態(tài)字段信息(可選):支持兩種方式定義 如果是字符串表示多態(tài)字段的前綴,多態(tài)字段使用 多態(tài)前綴_type多態(tài)前綴_id,如果是數(shù)組,表示使用['多態(tài)類型字段名','多態(tài)ID字段名'],默認(rèn)為當(dāng)前的關(guān)聯(lián)方法名作為字段前綴。

多態(tài)類型(可選):當(dāng)前模型對(duì)應(yīng)的多態(tài)類型,默認(rèn)為當(dāng)前模型名,可以使用模型名(如Article)或者完整的命名空間模型名(如app\index\model\Article)。

書籍模型:

<?php
namespace app\index\model;

use think\Model;

class Book extends Model
{
    /**
     * 獲取所有針對(duì)書籍的評(píng)論。
     */
    public function comments()
    {
        return $this->morphMany('Comment', 'commentable');
    }
}

書籍模型的設(shè)置方法同文章模型一致,區(qū)別在于多態(tài)類型不同,但由于多態(tài)類型默認(rèn)會(huì)取當(dāng)前模型名,因此不需要單獨(dú)設(shè)置。

下面是評(píng)論模型的關(guān)聯(lián)定義:

<?php
namespace app\index\model;

use think\Model;

class Comment extends Model
{
    /**
     * 獲取評(píng)論對(duì)應(yīng)的多態(tài)模型。
     */
    public function commentable()
    {
        return $this->morphTo();
    }
}

morphTo方法的參數(shù)如下:

morphTo('多態(tài)字段信息',['多態(tài)類型別名']);

多態(tài)字段信息(可選):支持兩種方式定義 如果是字符串表示多態(tài)字段的前綴,多態(tài)字段使用 多態(tài)前綴_type多態(tài)前綴_id,如果是數(shù)組,表示使用['多態(tài)類型字段名','多態(tài)ID字段名'],默認(rèn)為當(dāng)前的關(guān)聯(lián)方法名作為字段前綴
多態(tài)類型別名(可選):數(shù)組方式定義

獲取多態(tài)關(guān)聯(lián)

一旦你的數(shù)據(jù)表及模型被定義,則可以通過(guò)模型來(lái)訪問(wèn)關(guān)聯(lián)。例如,若要訪問(wèn)某篇文章的所有評(píng)論,則可以簡(jiǎn)單的使用 comments 動(dòng)態(tài)屬性:

$article = Article::get(1);

foreach ($article->comments as $comment) {
    dump($comment);
}

你也可以從多態(tài)模型的多態(tài)關(guān)聯(lián)中,通過(guò)訪問(wèn)調(diào)用 morphTo 的方法名稱來(lái)獲取擁有者,也就是此例子中 Comment 模型的 commentable 方法。所以,我們可以使用動(dòng)態(tài)屬性來(lái)訪問(wèn)這個(gè)方法:

$comment = Comment::get(1);
$commentable = $comment->commentable;

Comment 模型的 commentable 關(guān)聯(lián)會(huì)返回 Article 或 Book 模型的對(duì)象實(shí)例,這取決于評(píng)論所屬模型的類型。

自定義多態(tài)關(guān)聯(lián)的類型字段

默認(rèn)情況下,ThinkPHP 會(huì)使用模型名作為多態(tài)表的類型區(qū)分,例如,Comment屬于 Article 或者 Book , commentable_type 的默認(rèn)值可以分別是 Article 或者 Book 。我們可以通過(guò)定義多態(tài)的時(shí)候傳入?yún)?shù)來(lái)對(duì)數(shù)據(jù)庫(kù)進(jìn)行解耦。

    public function commentable()
    {
        return $this->morphTo('commentable',[
        	'book'	=>	'app\index\model\Book',
            'post'	=>	'app\admin\model\Article',
        ]);
    }

多態(tài)一對(duì)一關(guān)聯(lián)(V5.0.8+

多態(tài)一對(duì)一相比多態(tài)一對(duì)多關(guān)聯(lián)的區(qū)別是動(dòng)態(tài)的一對(duì)一關(guān)聯(lián),舉個(gè)例子說(shuō)有一個(gè)個(gè)人和團(tuán)隊(duì)表,而無(wú)論個(gè)人還是團(tuán)隊(duì)都有一個(gè)頭像需要保存但都會(huì)對(duì)應(yīng)同一個(gè)頭像表

member
	id - integer
    name - string
    
team
	id - integer
    name - string
    
avatar
	id - integer
    avatar - string
    imageable_id - integer
    imageable_type - string    

會(huì)員模型:

<?php
namespace app\index\model;

use think\Model;

class Member extends Model
{
    /**
     * 獲取用戶的頭像
     */
    public function avatar()
    {
        return $this->morphOne('Avatar', 'imageable');
    }
}

團(tuán)隊(duì)模型:

<?php
namespace app\index\model;

use think\Model;

class Team extends Model
{
    /**
     * 獲取團(tuán)隊(duì)的頭像
     */
    public function avatar()
    {
        return $this->morphOne('Avatar', 'imageable');
    }
}

morphOne方法的參數(shù)如下:

morphOne('關(guān)聯(lián)模型名','多態(tài)字段信息','多態(tài)類型');

關(guān)聯(lián)模型名(必須):關(guān)聯(lián)的模型名稱,可以使用模型名(如Member)或者完整的命名空間模型名(如app\index\model\Member)。

多態(tài)字段信息(可選):支持兩種方式定義 如果是字符串表示多態(tài)字段的前綴,多態(tài)字段使用 多態(tài)前綴_type多態(tài)前綴_id,如果是數(shù)組,表示使用['多態(tài)類型字段名','多態(tài)ID字段名'],默認(rèn)為當(dāng)前的關(guān)聯(lián)方法名作為字段前綴。

多態(tài)類型(可選):當(dāng)前模型對(duì)應(yīng)的多態(tài)類型,默認(rèn)為當(dāng)前模型名,可以使用模型名(如Member)或者完整的命名空間模型名(如app\index\model\Member)。

下面是頭像模型的關(guān)聯(lián)定義:

<?php
namespace app\index\model;

use think\Model;

class Avatar extends Model
{
    /**
     * 獲取頭像對(duì)應(yīng)的多態(tài)模型。
     */
    public function imageable()
    {
        return $this->morphTo();
    }
}
文檔最后更新時(shí)間:2018-06-09 15:41:35

文檔
目錄

深色
模式

切換
寬度