1.什么叫多態(tài)關(guān)系度液?
英文叫polymorphic, 本意是一個物體可以有很多的狀態(tài)冤灾。在laravel里面徒恋,就是指各各模型直接有很多相互的關(guān)系,laravel有3種多態(tài)關(guān)系眨攘。我們舉個例子主慰,一個圖片的模型可以歸屬于一個用戶,也可以歸屬于一個文章鲫售,一篇文章可以有多個圖共螺,一個用戶也可以有多個圖。如何在模型文件里反應(yīng)這些關(guān)系呢情竹?我們可以用一個圖片模型來反應(yīng)這個關(guān)系藐不。下面我們通過一個例子來說明這個關(guān)系。
2.創(chuàng)建文章模型秦效,圖片模型雏蛮,然后我們來寫一個遷移文件和工廠文件來填充假數(shù)據(jù)到文章數(shù)據(jù)庫。
php artisan make:model Post -mf
在文章里棉安,我們填兩個字段:
$table->string('title');
$table->text('body');
然后我們創(chuàng)建一個圖片模型文件:
php artisan make:model Image -m
我們暫時不需要創(chuàng)建工廠文件了底扳。
在填遷移文件的時候我們需要填兩個字段:
在通常情況下,我們會填一個post_id來表明這個圖片是屬于這個POST的贡耽。
但是在多態(tài)情況下衷模,這種做法是無法反應(yīng)用戶ID和這個圖片的關(guān)系。
所以在這種情況下我們就加一個特殊的字段蒲赂,叫做"imageable_id".
還有一個字段是填入我們的模型阱冶,一般的做法是加一個"imageable_type"這個字段。
讓我們來看下Image這個模型的遷移文件里加了什么:
$table->string('image_url');
$table->unsignedBigInteger('imageable_id');
$table->string('imageable_type');
第一個字段我們填的是上傳后的圖片連接滥嘴。
第二個字段里我們填的是模型的ID木蹬,例如如果是post的話就是post_id, 如果是user的話是user_id.
第三個字段我們填的是模型類型:如App\Post或者App\User等。
然后我們來遷移若皱。我們來填充一個假數(shù)據(jù)到post這個表格镊叁。
3.一對一的模型文件里多態(tài)關(guān)系的寫法:
在文章模型文件里,我們可以寫:
app/Post.php里面
public function image()
{
return $this->morphOne(Image::class, 'imageable');
}
app/Image.php里面:
在這里我們必須要用imageable這個方法名走触,因為我們在上面已經(jīng)定義了晦譬。
public function imageable()
{
return $this->morphTo();
}
就好比我們belongTo()一樣认然,這里要用morphTo().
下面我們來填充一個數(shù)據(jù)到圖片這個模型里锈拨。
Post::first()->image()->create(['image_url' => 'some/image.jpg']);
我們可以用關(guān)系來填充,如果我們看下數(shù)據(jù)庫里面的話图毕,我們會看到:
imageable_id是1,imageable_type是App\Post.
接下來我們要寫User.php里面的來填充一個假數(shù)據(jù)并且加一個圖片到對應(yīng)關(guān)系里面的表格像樊。
在User.php里面的關(guān)系的語句跟post里面的是一模一樣的尤莺。我們還是用同樣的方法來填充數(shù)據(jù):
User::first()->image()->create(['image_url' => 'some/image.jpg']);
數(shù)據(jù)庫里表現(xiàn)的是:imageable_id是1,imageable_type是App\User.
4. 一對多的多態(tài)關(guān)系:
一篇文章可以有多個評論生棍,一個用戶可以有多個評論颤霎。
創(chuàng)建模型文件:
php artisan make:model Comment
遷移文件里面:
$table->text('body');
$table->unsignedBigInteger('commentable_id');
$table->string('commentable_type');
在Post里面:
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
在Comment里面,加關(guān)系方法:
public function commentable()
{
return $this->morphTo();
}
我們利用這個關(guān)系來添加一個評論:
Post::first()->comments()->create(['body' => 'my message']);
我們會看到數(shù)據(jù)庫里多一個記錄足绅。
imageable_id是1捷绑,imageable_type是App\Post.
當(dāng)然因為它是1對多的關(guān)系,我們可以繼續(xù)加一條記錄氢妈。
用同樣的方法粹污,我們可以加一個評論,用User的模型首量。
5.多對多的多態(tài)關(guān)系
多對多的多態(tài)關(guān)系壮吩,跟上面的不同點比較多,我們來用tags(標(biāo)簽)來做下例子加缘。任何模型都可以有很多tag鸭叙。標(biāo)簽也屬于很多的模型。例如一個帖子post有很多標(biāo)簽拣宏,php, java, python等等沈贝,反過來也一樣。
我們首先需要創(chuàng)建一個模型勋乾,然后需要再創(chuàng)建一個“膠水”宋下,用這個“膠水”把標(biāo)簽?zāi)P秃推渌哪P吐?lián)系到一起。
php artisan make:model tag -m
我們再做一個“膠水”的遷移文件:
php artisan make:migration creates_taggables_table --create taggables
我們把這個遷移文件打開進行修改辑莫。
$table->increments('id');
我們將這句改一下学歧,因為我們要把tag模型和taggables直接做個關(guān)聯(lián)。
$table->unsignedBigInteger('tag_id');
然后再加2個字段:
$table->unsignedBigInteger('taggable_id');
$table->string('taggable_type');
在tag這個表格上我們只需要加一個字段
$table->string('name');
這樣我們所要做的工作就結(jié)束了各吨,我們在Post這個模型上加一個方法:
Post.php
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
在tags.php里面枝笨,我們可以加
public function posts()
{
return $this->morphedByMany(Post::class, 'taggable');
}
比較好的記憶方法是,在要被關(guān)聯(lián)的模型里加一個以表格名稱起名的方法揭蜒,然后跟模型和關(guān)鍵詞('taggable')進行關(guān)聯(lián)横浑,然后在另一個模型里放morphedByMany這個關(guān)鍵詞,放對應(yīng)的模型和關(guān)鍵詞就行可以了屉更。
如果我們試著放一個數(shù)據(jù)到這里的時候伪嫁,我們會發(fā)現(xiàn):
Post::first()->tag()->create(['name' => 'php']);
在taggables表格里多出了一個記錄,而且在tags表格里多出了一個記錄偶垮。