You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel如何为Page模型建立可关联Image和Video的attachments关联

Laravel Page模型多类型附件关联实现方案

你需要用多对多多态关联+自定义封装实现需求,步骤如下:


1. 创建中间表迁移

生成迁移文件:

php artisan make:migration create_attachables_table

编写迁移逻辑:

<?php

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

return new class extends Migration
{
    public function up()
    {
        Schema::create('attachables', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('page_id');
            $table->unsignedBigInteger('attachable_id');
            $table->string('attachable_type');
            $table->timestamps();

            // 外键约束+避免重复关联
            $table->foreign('page_id')->references('id')->on('pages')->onDelete('cascade');
            $table->unique(['page_id', 'attachable_id', 'attachable_type']);
            
            // 可选:增加排序字段支持附件自定义排序
            // $table->unsignedInteger('sort')->default(0);
        });
    }

    public function down()
    {
        Schema::dropIfExists('attachables');
    }
};

执行迁移:

php artisan migrate

2. 配置模型关联

Image/Video 模型配置

两个模型添加反向关联(按需使用即可):

// App/Models/Image.php
public function pages()
{
    return $this->morphToMany(Page::class, 'attachable');
    // 带排序的话追加:->orderBy('sort')
}

// App/Models/Video.php
public function pages()
{
    return $this->morphToMany(Page::class, 'attachable');
    // 带排序的话追加:->orderBy('sort')
}

Page 模型配置

在Page模型中实现统一的attachments关联和访问器:

// App/Models/Page.php
use Illuminate\Database\Eloquent\Model;

class Page extends Model
{
    // 基础关联:关联所有图片附件
    public function images()
    {
        return $this->morphToMany(Image::class, 'attachable');
    }

    // 基础关联:关联所有视频附件
    public function videos()
    {
        return $this->morphToMany(Video::class, 'attachable');
    }

    // 访问器:直接获取所有附件实例(Image/Video)
    public function getAttachmentsAttribute()
    {
        return $this->images->merge($this->videos);
        // 带全局排序的话追加:->sortBy('sort')
    }

    // 自定义关联方法:支持批量保存混合类型附件
    public function attachments()
    {
        return new class($this) {
            protected $page;

            public function __construct(Page $page)
            {
                $this->page = $page;
            }

            public function saveMany(array $attachments)
            {
                foreach ($attachments as $attachment) {
                    match (true) {
                        $attachment instanceof Image => $this->page->images()->save($attachment),
                        $attachment instanceof Video => $this->page->videos()->save($attachment),
                        default => throw new \InvalidArgumentException('不支持的附件类型')
                    };
                }
                return $this->page->attachments;
            }
        };
    }
}

效果验证

完全支持你要求的调用方式:

遍历附件

foreach($page->attachments as $attachment)
{
    // $attachment 为 Image 或 Video 实例
}

批量保存附件

$attachments = [$image, $video];
$page->attachments()->saveMany($attachments);

内容的提问来源于stack exchange,提问作者Kekior

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 11:45:10