多態關聯
| 版本 | 功能調整 |
|---|---|
| 5.0.8 | 支持多態一對一關聯 |
| 5.0.4 | 支持多態一對多關聯 |
多態一對多關聯(V5.0.4+)
多態關(guan)聯允許一(yi)個(ge)模型在單個(ge)關(guan)聯定義方法中從屬一(yi)個(ge)以上其它(ta)模型,例如(ru)用戶(hu)可以評論(lun)書(shu)和(he)文章,但(dan)評論(lun)表通常都是同(tong)一(yi)個(ge)數據表的設計。多態一(yi)對多關(guan)聯關(guan)系,就(jiu)是為了滿足類似的使用場景而設計。
下面是關聯表的(de)數據(ju)表結構(gou):
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我們稱之為多態字段。其中, commentable_id 用于存放書或者文章的 id(主鍵) ,而 commentable_type 用于存放所屬模型的類型。通常的設計是多態字段有一個公共的前綴(例如這里用的commentable),當然,也支持設置完全不同的字段名(例如使用data_id和type)。
多態關聯定義
接(jie)著,讓我們來(lai)查看創建這種關聯(lian)所需的模型定(ding)義:
文章模型:
<?php
namespace app\index\model;
use think\Model;
class Article extends Model
{
/**
* 獲取(qu)所有針(zhen)對文章的評論。
*/
public function comments()
{
return $this->morphMany('Comment', 'commentable');
}
}
morphMany方法的參數如下:
morphMany('關聯模型名','多態字段信息','多態類型');
關聯(lian)模(mo)型名(必須):關聯的模型名稱,可以使用模型名(如Comment)或者完整的命名空間模型名(如app\index\model\Comment)。
多態字段信息(可選):支持兩種方式定義 如果是字符串表示多態字段的前綴,多態字段使用 多態前綴_type和多態前綴_id,如果是數組(zu),表示(shi)使用['多態(tai)類型字(zi)(zi)段(duan)名(ming)','多態(tai)ID字(zi)(zi)段(duan)名(ming)'],默認為當前(qian)的關聯方法名(ming)作(zuo)為字(zi)(zi)段(duan)前(qian)綴。
多態類型(可選):當前模型對應的多態類型,默認為當前模型名,可以使用模型名(如Article)或者完整的命名空間模型名(如app\index\model\Article)。
書籍模型:
<?php
namespace app\index\model;
use think\Model;
class Book extends Model
{
/**
* 獲取所(suo)有針對書籍的評論。
*/
public function comments()
{
return $this->morphMany('Comment', 'commentable');
}
}
書籍(ji)模型(xing)的(de)設置(zhi)方法同(tong)文章模型(xing)一(yi)致,區別在于多(duo)態(tai)類型(xing)不同(tong),但由于多(duo)態(tai)類型(xing)默(mo)認會取當(dang)前模型(xing)名,因此不需要單獨設置(zhi)。
下面(mian)是評(ping)論模型的關聯定(ding)義(yi):
<?php
namespace app\index\model;
use think\Model;
class Comment extends Model
{
/**
* 獲(huo)取(qu)評論對(dui)應的(de)多態模型(xing)。
*/
public function commentable()
{
return $this->morphTo();
}
}
morphTo方法的參數如下:
morphTo('多態字段信息',['多態類型別名']);
多態字段信息(可選):支持兩種方式定義 如果是字符串表示多態字段的前綴,多態字段使用 多態前綴_type和多態前綴_id,如果是數組,表示使用['多態類型字段名','多態ID字段名'],默認為當前的關聯方法名作為字段前綴
多態(tai)類型別名(可選):數組方式定(ding)義
獲取多態關聯
一旦你的數據表及模型被定義,則可以通過模型來訪問關聯。例如,若要訪問某篇文章的所有評論,則可以簡單的使用 comments 動(dong)態屬(shu)性:
$article = Article::get(1);
foreach ($article->comments as $comment) {
dump($comment);
}
你也可以從多態模型的多態關聯中,通過訪問調用 morphTo 的方法名稱來獲取擁有者,也就是此例子中 Comment 模型的 commentable 方(fang)(fang)法(fa)。所以,我們可以使用動態屬性(xing)來訪問(wen)這個方(fang)(fang)法(fa):
$comment = Comment::get(1);
$commentable = $comment->commentable;
Comment 模型的 commentable 關聯會返回 Article 或 Book 模型(xing)(xing)的對象(xiang)實例(li),這取決于評論所(suo)屬模型(xing)(xing)的類(lei)型(xing)(xing)。
自定義多態關聯的類型字段
默認情況下,ThinkPHP 會使用模型名作為多態表的類型區分,例如,Comment屬于 Article 或者 Book , commentable_type 的默認值可以分別是 Article 或者 Book 。我(wo)們可以通(tong)過定義多態的時候傳(chuan)入參數來對數據庫進行解耦。
public function commentable()
{
return $this->morphTo('commentable',[
'book' => 'app\index\model\Book',
'post' => 'app\admin\model\Article',
]);
}
多態一對一關聯(V5.0.8+)
多(duo)(duo)(duo)態一(yi)對一(yi)相(xiang)比多(duo)(duo)(duo)態一(yi)對多(duo)(duo)(duo)關聯的區(qu)別是(shi)動態的一(yi)對一(yi)關聯,舉個(ge)例子說(shuo)有(you)一(yi)個(ge)個(ge)人和團隊表,而(er)無論個(ge)人還是(shi)團隊都有(you)一(yi)個(ge)頭像(xiang)需要保存(cun)但都會對應同(tong)一(yi)個(ge)頭像(xiang)表
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方法的參數如下:
morphOne('關聯模型名','多態字段信息','多態類型');
關聯模型名(必須):關聯的模型名稱,可以使用模型名(如Member)或者完整的命名空間模型名(如app\index\model\Member)。
多態字(zi)段信息(可選):支持兩種方式定義 如果是字符串表示多態字段的前綴,多態字段使用 多態前綴_type和多態前綴_id,如果是數組,表示(shi)使用['多態類型字段名','多態ID字段名'],默認為(wei)當前的關聯方法名作為(wei)字段前綴。
多態(tai)類型(可選):當前模型對應的多態類型,默認為當前模型名,可以使用模型名(如Member)或者完整的命名空間模型名(如app\index\model\Member)。
下面是頭像模型(xing)的關(guan)聯定義:
<?php
namespace app\index\model;
use think\Model;
class Avatar extends Model
{
/**
* 獲取(qu)頭像對應的(de)多態模型。
*/
public function imageable()
{
return $this->morphTo();
}
}
