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
相关产品推荐
相关产品推荐

