今天我們來處理前面說到的文章標籤
多對多關係,顧名思義,就是甲乙兩個物件:
可能有讀者會疑惑:「這有什麼難的,不就原本是一對多,現在變成多對多而已嗎?」。
問題在於,之前甲乙兩個物件,有某個只會有單一對應關係時,我們可以讓該物件去紀錄對應物件的 id
。但是,當甲乙兩個物件,都可能對應多個物件的時候,我們就比較難用之前紀錄 id
的方式來處理。
比較良好的設計,是使用一個「多對多關係表」,專門紀錄物件的對應關係。比方說以我們的「文章-標籤」對應關係來說,就可以用:
資料表欄位名稱 | 資料欄位內容 |
---|---|
post_id | 文章 id |
tag_id | 標籤 id |
來進行處理。
Laravel 這個框架同樣的套路,相信讀者們又猜到了。
繼前面的資料表命名由 Laravel 綁定,接著一對多關係的 id
名稱由 Laravel 綁定,可以想像的到,其實多對多關係表的結構 Laravel 還是幫我們設計好了。
以 Post
和 Tag
物件的多對多關係,對應表的名稱是 post_tag
,注意物件名稱前後,要依據字母順序前後,不能是 tag_post
。
再來就是裡面的欄位名稱,如說明一樣,會是 post_id
和 tag_id
。
我們來建立 Tag
物件的資料表,和這張關係對應表
$ php artisan make:migration create_tags_table
Created Migration: 2019_09_15_111649_create_tags_table
$ php artisan make:migration create_post_tag_table
Created Migration: 2019_09_15_111657_create_post_tag_table
然後跟之前一樣,改寫 migration 裡面內容
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTagsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('tags', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('content', 255);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('tags');
}
}
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePostTagTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('post_tag', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('post_id');
$table->bigInteger('tag_id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('post_tag');
}
}
改完之後,我們再跑一下 migrate,資料表關係就建立完成囉!
再來就是實際在物件裡面建立多對多關係囉!
我們先建立 Tag
物件
$ php artisan make:model Tag
Model created successfully.
然後,我們在 Tag
物件裡面,加上 belongsToMany()
函式,來宣告其多對多關係
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name'
];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function posts()
{
return $this->belongsToMany(Post::class);
}
}
對應的,我們也在 Post
物件裡面加上一樣的函式
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'content'
];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function subject()
{
return $this->belongsTo(Subject::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function tags()
{
return $this->belongsToMany(Tag::class);
}
}
成功囉!我們一樣用測試路徑來看看效果。
首先我們在 tags
裡面加入幾筆資料:
id | content | created_at | updated_at |
---|---|---|---|
1 | 111 | NULL | NULL |
2 | 222 | NULL | NULL |
3 | 333 | NULL | NULL |
然後修改一下 post_tag
裡面的資料
|id|post_id|tag_id|created_at|updated_at|
|----|----|----|
|1|1|1|NULL|NULL|
|2|2|1|NULL|NULL|
|3|2|2|NULL|NULL|
|4|3|2|NULL|NULL|
首先,我們來取出 tag 標記為一的文章(也就是 id
為 1 和 2 的文章)
Route::get('/test', function(){
$tag = App\Tag::find(1);
$posts = $tag->posts;
return $posts;
});
來取出資料看看,連線 http://127.0.0.1/test :
[
{
id: 1,
content: "Laravel demo 6.0 day 11 test",
created_at: null,
updated_at: "2019-09-13 09:20:51",
subject_id: 1,
pivot: {
tag_id: 1,
post_id: 1
}
},
{
id: 2,
content: "Laravel demo 6.0 day 11 test",
created_at: null,
updated_at: null,
subject_id: 1,
pivot: {
tag_id: 1,
post_id: 2
}
}
]
成功囉!我們取出了對應的 post 資料了!
如果我們將 /test
改成
Route::get('/test', function(){
$tag = App\Tag::find(2);
$posts = $tag->posts;
return $posts;
});
那就會變成
[
{
id: 2,
content: "Laravel demo 6.0 day 11 test",
created_at: null,
updated_at: null,
subject_id: 1,
pivot: {
tag_id: 2,
post_id: 2
}
},
{
id: 3,
content: "Laravel demo 6.0 day 11 test",
created_at: null,
updated_at: null,
subject_id: 2,
pivot: {
tag_id: 2,
post_id: 3
}
}
]
是不是很容易呀!
要反過來透過 Post
物件找到對應的 Tag
也是很容易的
我們將路徑改成
Route::get('/test', function(){
$post = App\Post::find(2);
$tags = $post->tags;
return $tags;
});
就可以看到
[
{
id: 1,
content: "111",
created_at: null,
updated_at: null,
pivot: {
post_id: 2,
tag_id: 1
}
},
{
id: 2,
content: "222",
created_at: null,
updated_at: null,
pivot: {
post_id: 2,
tag_id: 2
}
}
]
可以找到每個 Post
所對應的 Tag
物件囉!
我們這裡小總結一下
今天我們延續上次所談到的一對多關係,討論多對多關係所需要的架構,並且實作了文章與標籤之間的多對多關係。
希望今天的文章能讓大家滿意!我們明天見!