Laravel 多對多之多型-範例


建立時間: 2025年5月18日 01:46
更新時間: 2025年5月18日 01:59

說明

本篇分享我在使用多對多之多型時一些小技巧,有些細節值得注意。

前言

本篇以文章和標籤為例,標籤可以用在多張表上,也就是多個模型,但本篇只會示範文章。

遷移

文章

database/migrations/2025_01_01_000000_create_articles_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->comment('文章');
            $table->id();
            $table->string('title')->comment('標題');
            $table->longText('content')->nullable()->comment('內容');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('articles');
    }
};

標籤

database/migrations/2025_01_01_000000_create_tags_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('tags', function (Blueprint $table) {
            $table->comment('標籤');
            $table->id();
            $table->string('name')->unique()->comment('標籤名稱');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('tags');
    }
};

標籤中介表

database/migrations/2025_01_01_000000_create_taggables_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('taggables', function (Blueprint $table) {
            $table->comment('標籤關聯');
            $table->id();
            $table->foreignId('tag_id')
                ->constrained()
                ->cascadeOnDelete()
                ->cascadeOnUpdate();
            $table->morphs('taggable');
            $table->timestamps();

            $table->index(['tag_id', 'taggable_id', 'taggable_type']);
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('taggables');
    }
};

經過我再三的思考,最終還是保留 id,主要是未來查資料或刪除資料會比較方便。

模型

文章

app/Models/Article.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\Collection;

/**
 * 文章
 *
 * @property Collection<Tag> $tags 標籤
 */
class Article extends Model
{
    public function tags(): MorphToMany
    {
        return $this->morphToMany(Tag::class, 'taggable')->withTimestamps();
    }
}

withTimestamps() 可以讓中介表記錄建立時間和更新時間。

標籤

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphToMany;

/**
 * 標籤
 */
class Tag extends Model
{
    public function articles(): MorphToMany
    {
        return $this->morphedByMany(Article::class, 'taggable');
    }
}

文章取得標籤

app/Http/Controllers/Main/ArticleController.php

<?php

declare(strict_types=1);

namespace App\Http\Controllers\Main;

use App\Http\Controllers\Controller;
use App\Models\Article;
use Inertia\Response;

/**
 * 文章控制器
 */
class ArticleController extends Controller
{
    /**
     * 顯示文章
     */
    public function show(Article $article): Response
    {
        $article->load([
            'tags',
        ]);
    }
}

觀看次數: 77
articlelaravelmanymorphrelationshiptagto關係多型
按讚追蹤 Enjoy 軟體 Facebook 粉絲專頁
每週分享資訊技術

一杯咖啡的力量,勝過千言萬語的感謝。

支持我一杯咖啡,讓我繼續創作優質內容,與您分享更多知識與樂趣!