多態(tài)關(guān)聯(lián)
版本 | 功能調(diào)整 |
---|---|
5.0.8 | 支持多態(tài)一對一關(guān)聯(lián) |
5.0.4 | 支持多態(tài)一對多關(guān)聯(lián) |
多態(tài)一對多關(guān)聯(lián)(V5.0.4+
)
多態(tài)關(guān)聯(lián)允許一個模型在單個關(guān)聯(lián)定義方法中從屬一個以上其它模型,例如用戶可以評論書和文章,但評論表通常都是同一個數(shù)據(jù)表的設(shè)計。多態(tài)一對多關(guān)聯(lián)關(guān)系,就是為了滿足類似的使用場景而設(shè)計。
下面是關(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
有兩個需要注意的字段是 comment
表中的 commentable_id
和 commentable_type
我們稱之為多態(tài)字段。其中, commentable_id
用于存放書或者文章的 id(主鍵) ,而 commentable_type
用于存放所屬模型的類型。通常的設(shè)計是多態(tài)字段有一個公共的前綴(例如這里用的commentable
),當然,也支持設(shè)置完全不同的字段名(例如使用data_id
和type
)。
多態(tài)關(guān)聯(lián)定義
接著,讓我們來查看創(chuàng)建這種關(guān)聯(lián)所需的模型定義:
文章模型:
<?php
namespace app\index\model;
use think\Model;
class Article extends Model
{
/**
* 獲取所有針對文章的評論。
*/
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字段名'],默認為當前的關(guān)聯(lián)方法名作為字段前綴。
多態(tài)類型(可選):當前模型對應(yīng)的多態(tài)類型,默認為當前模型名,可以使用模型名(如Article
)或者完整的命名空間模型名(如app\index\model\Article
)。
書籍模型:
<?php
namespace app\index\model;
use think\Model;
class Book extends Model
{
/**
* 獲取所有針對書籍的評論。
*/
public function comments()
{
return $this->morphMany('Comment', 'commentable');
}
}
書籍模型的設(shè)置方法同文章模型一致,區(qū)別在于多態(tài)類型不同,但由于多態(tài)類型默認會取當前模型名,因此不需要單獨設(shè)置。
下面是評論模型的關(guān)聯(lián)定義:
<?php
namespace app\index\model;
use think\Model;
class Comment extends Model
{
/**
* 獲取評論對應(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字段名'],默認為當前的關(guān)聯(lián)方法名作為字段前綴
多態(tài)類型別名(可選):數(shù)組方式定義
獲取多態(tài)關(guān)聯(lián)
一旦你的數(shù)據(jù)表及模型被定義,則可以通過模型來訪問關(guān)聯(lián)。例如,若要訪問某篇文章的所有評論,則可以簡單的使用 comments
動態(tài)屬性:
$article = Article::get(1);
foreach ($article->comments as $comment) {
dump($comment);
}
你也可以從多態(tài)模型的多態(tài)關(guān)聯(lián)中,通過訪問調(diào)用 morphTo
的方法名稱來獲取擁有者,也就是此例子中 Comment
模型的 commentable
方法。所以,我們可以使用動態(tài)屬性來訪問這個方法:
$comment = Comment::get(1);
$commentable = $comment->commentable;
Comment
模型的 commentable
關(guān)聯(lián)會返回 Article
或 Book
模型的對象實例,這取決于評論所屬模型的類型。
自定義多態(tài)關(guān)聯(lián)的類型字段
默認情況下,ThinkPHP 會使用模型名作為多態(tài)表的類型區(qū)分,例如,Comment
屬于 Article
或者 Book
, commentable_type
的默認值可以分別是 Article
或者 Book
。我們可以通過定義多態(tài)的時候傳入?yún)?shù)來對數(shù)據(jù)庫進行解耦。
public function commentable()
{
return $this->morphTo('commentable',[
'book' => 'app\index\model\Book',
'post' => 'app\admin\model\Article',
]);
}
多態(tài)一對一關(guān)聯(lián)(V5.0.8+
)
多態(tài)一對一相比多態(tài)一對多關(guān)聯(lián)的區(qū)別是動態(tài)的一對一關(guān)聯(lián),舉個例子說有一個個人和團隊表,而無論個人還是團隊都有一個頭像需要保存但都會對應(yīng)同一個頭像表
member
id - integer
name - string
team
id - integer
name - string
avatar
id - integer
avatar - string
imageable_id - integer
imageable_type - string
會員模型:
<?php
namespace app\index\model;
use think\Model;
class Member extends Model
{
/**
* 獲取用戶的頭像
*/
public function avatar()
{
return $this->morphOne('Avatar', 'imageable');
}
}
團隊模型:
<?php
namespace app\index\model;
use think\Model;
class Team extends Model
{
/**
* 獲取團隊的頭像
*/
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字段名'],默認為當前的關(guān)聯(lián)方法名作為字段前綴。
多態(tài)類型(可選):當前模型對應(yīng)的多態(tài)類型,默認為當前模型名,可以使用模型名(如Member
)或者完整的命名空間模型名(如app\index\model\Member
)。
下面是頭像模型的關(guān)聯(lián)定義:
<?php
namespace app\index\model;
use think\Model;
class Avatar extends Model
{
/**
* 獲取頭像對應(yīng)的多態(tài)模型。
*/
public function imageable()
{
return $this->morphTo();
}
}