如何为Laravel morphMany关联字段设置非数据库层默认值
方案1:使用makeUsing关联钩子(推荐,兼容Laravel 5.8+)
该方案无需修改调用逻辑,完全符合你需要的$post->images()->create()调用方式,仅修改Post模型的关联定义即可:
class Post{ public function videos(){ return $this->morphMany(File::class, 'filable') ->where('type', File::VIDEO_TYPE) // 新增以下代码,创建实例时自动注入type属性 ->makeUsing(fn ($attributes) => new File(array_merge($attributes, ['type' => File::VIDEO_TYPE]))); } public function images(){ return $this->morphMany(File::class, 'filable') ->where('type', File::IMAGE_TYPE) // 新增以下代码,创建实例时自动注入type属性 ->makeUsing(fn ($attributes) => new File(array_merge($attributes, ['type' => File::IMAGE_TYPE]))); } }
makeUsing是Laravel关联提供的原生方法,会在调用关联的make()、create()、createMany()生成File实例前触发,自动把对应type合并到属性中,不会影响原有查询功能。
方案2:封装创建辅助方法(兼容所有Laravel版本)
如果你使用的Laravel版本不支持makeUsing,可以直接在Post模型中新增专用创建方法,调用逻辑更简洁:
class Post{ // 保留原有关联定义 public function videos(){ return $this->morphMany(File::class, 'filable') ->where('type', File::VIDEO_TYPE); } public function images(){ return $this->morphMany(File::class, 'filable') ->where('type', File::IMAGE_TYPE); } // 新增创建辅助方法 public function createImage(array $attributes) { return $this->images()->create(array_merge($attributes, [ 'type' => File::IMAGE_TYPE ])); } public function createVideo(array $attributes) { return $this->videos()->create(array_merge($attributes, [ 'type' => File::VIDEO_TYPE ])); } }
调用方式:
$post->createImage(['path' => 'my-image.jpg']); $post->createVideo(['path' => 'my-video.mp4']);
方案3:抽离通用Trait(多模型复用时推荐)
如果系统内还有其他模型(比如文章、用户等)也需要关联File模型,可以把逻辑抽成通用Trait,避免重复编码:
- 首先定义通用Trait
trait HasFiles { public function fileRelation(string $type) { return $this->morphMany(File::class, 'filable') ->where('type', $type) ->makeUsing(fn ($attributes) => new File(array_merge($attributes, ['type' => $type]))); } public function images() { return $this->fileRelation(File::IMAGE_TYPE); } public function videos() { return $this->fileRelation(File::VIDEO_TYPE); } public function audios() { return $this->fileRelation(File::AUDIO_TYPE); } public function applications() { return $this->fileRelation(File::APPLICATION_TYPE); } }
- 在Post模型中引入Trait即可
class Post { use HasFiles; // 不需要再手动编写各类文件关联方法 }
内容的提问来源于stack exchange,提问作者unnoq
相关产品推荐
相关产品推荐

