laravel 关联模型 多态关系

laravel 关联模型 多态关系

一对一(多态)

note

1个关联上从属于多个模型,如:博客post和用户user共享1个关联图片image

1篇博客拥有1张主图
1个用户拥有1个头像

imageable_id=post.id
imageable_type=App\Model\Post

imageable_id=user.id
imageable_type=App\Model\User

图片

博客

用户

table

copypost ( id, title, content)
user ( id, name )
image ( id, imageable_id, imageable_type, url)
#`imageable_id`关联表ID,`imageable_type`关联模型类名

model

copyclass Image extends Model
{
    const TABLE = 'image';
    protected $table = self::TABLE;
    
    protected $fillable = [ 'id','imageable_id','imageable_type','url','created_at','updated_at' ];

    public function imageable()
    {
        return $this->morphTo();
    }
}
copyclass Post extends Model
{
    const TABLE = 'post';
    protected $table = self::TABLE;
    
    protected $fillable = [ 'id','title','content','created_at','updated_at' ];

    public function image()
    {
        return $this->morphOne(Image::class, 'imageable');
    }
}
copyclass User extends Model
{
    const TABLE = 'user';
    protected $table = self::TABLE;
    
    protected $fillable = [ 'id','name','created_at','updated_at' ];

    public function image()
    {
        return $this->morphOne(Image::class, 'imageable');
    }
}

code

查询关联

image表

ID imageable_id imageable_type url

1 1 App\Model\Post xxx
2 1 App\Model\User xxxx

copyPost::with('image')->find(1)->toArray();
User::with('image')->find(1)->toArray();

#反向查询
Image::with('imageable')->find(1)->toArray();

添加关联

copy#非关联添加,直接新增关联表
Image::create(['imageable_id' => 2,'imageable_type' => Post::class,'url' => 'xxx']);

#关联添加,不用给关联字段赋值,推荐使用
$post = Post::find(1);
$post->image()->create(['url'=>'x']);

更新关联

copy#非关联更新,直接更新关联表对应记录
Image::where(['imageable_id'=>2,'imageable_type'=>Post::class)->update(['url'=>'new url']);
              
#关联更新,推荐使用
$post = Post::find(1);
$post->image()->update(['url'=>'new url']);
#update针对‘一对一’,‘一对多’应该删除对应的所有关联再新增

删除关联

copy#非关联删除,直接删除关联表对应记录
Image::where(['imageable_id'=>2,'imageable_type'=>Post::class)->delete();

#关联删除,推荐使用
$post = Post::find(1);
$post->image()->delete();

一对多(多态)

note

1个关联上从属于多个模型,如:文章article和视频video共享1个关联评论comment

1篇文章拥有多个评论
1个视频拥有多个评论

commentable_id=article.id
commentable_type=App\Model\Article

commentable_id=video.id
commentable_type=App\Model\Video

评论

文章

视频

table

copyarticle ( id, name )
video ( id, title, url )
comment ( id, commentable_id, commentable_type, content)
#`commentable_id`关联表ID,`commentable_type`关联模型类名

model

copyclass Comment extends Model
{
    const TABLE = 'comment';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','commentable_id','commentable_type','content','created_at','updated_at' ];

    public function commentable()
    {
        return $this->morphTo();
    }
}
copyclass Article extends Model
{
    const TABLE = 'article';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','name','created_at','updated_at' ];

    public function comments()
    {
        return $this->morphMany(Comment::class,'commentable');
    }
}
copyclass Video extends Model
{
    const TABLE = 'video';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','title','url','created_at','updated_at' ];

    public function comments()
    {
        return $this->morphMany(Comment::class,'commentable');
    }
}

code

查询关联

copyArticle::with('comments')->find(1)->toArray();
Video::with('comments')->find(1)->toArray();

#反向查询
Comment::with('commentable')->find(1)->toArray();

高级1点的查询

copyArticle::has('comments')->get()->toArray();	#查询至少1条评论的文章
Article::has('comments','>=',5)->get()->toArray();	#查询至少5条评论的文章

#查询评论包含‘xx’的文章
Article::whereHas('comments', function (Builder $query) {
            $query->where('content', 'like', '%xx%');
        })->get()->toArray();

#查询评论 包含‘xx’ & 至少5条评论 的文章
Article::whereHas('comments', function (Builder $query) {
            $query->where('content', 'like', '%xx%');
        }, '>=', 5)->get()->toArray();

添加关联

copy$article = Article::find(3);

$article->comments()->save(new Comment(['content'=>'new new']))
$article->comments()->create(['content' => 'good good study']);

$article->comments()->createMany([
            ['content' => 'good good study'],
            ['content' => 'day day up']
        ]);

删除关联

copy$article = Article::find(3);
$article->comments()->where('id',7)->delete();	#删除关联表comment id=7记录
$article->comments()->delete();	#删除所有关联

更新关联

copy#更新指定评论
$article = Article::find(3);
$article->comments()->where('id',6)->update(['content'=>'new contetn']);

#先删除所有关联,再添加关联。

多对多(多态)

note

使用多对多多态关联允许使用一个唯一标签在博客文章和视频间共享。

1篇文章对应多个标签,1个标签对应多篇文章
1个视频对应多个标签,1个标签对应多个视频
1个标签既可以是文章的标签,也是视频的标签,即文章和视频共享同1个标签

tag_id

tagable_id=article.id
tagable_type=App\Model\Article

tagable_id=video.id
tagable_type=App\Model\Video

标签

关联

文章

视频

table

copyarticle ( id, name )
video ( id, title, url )
tag ( id, name )
tagable ( tag_id, tagable_id, tagable_type )
#`tagable_id`关联表ID,`tagable_type`关联模型类名

model

copyclass Tag extends Model
{
    const TABLE = 'tag';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','name','created_at','updated_at' ];


    public function articles()
    {
        return $this->morphedByMany(Article::class, 'tagable', Tagable::TABLE);
    }

    public function videos()
    {
        return $this->morphedByMany(Video::class, 'tagable', Tagable::TABLE);
    }
}

copyclass Tagable extends Model
{
    const TABLE = 'tagable';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','tag_id','tagable_id','tagable_type','created_at','updated_at' ];
}
copyclass Article extends Model
{
    const TABLE = 'article';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','name','created_at','updated_at' ];

    public function tags()
    {
        return $this->morphToMany(Tag::class, 'tagable', Tagable::TABLE);
    }
}
copyclass Video extends Model
{
    const TABLE = 'video';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','title','url','created_at','updated_at' ];

    public function tags()
    {
        return $this->morphToMany(Tag::class, 'tagable', Tagable::TABLE);
    }
}

注意

morphToMany($related, $name, $table = null)
morphedByMany($related, $name, $table = null)
//$table=null,默认为$name + s

code

查询关联

copyArticle::with('tags')->find(1)->toArray();
Video::with('tags')->find(1)->toArray();

//反向查询
Tag::with('articles')->find(1)->toArray();

添加关联

copy$article->tags()->create(['name' => '神话']);
#新增记录,标签表tag & 关联表tagable,同时新增

$article->tags()->attach(4);
#新增记录,仅新增关联表tagable

$article->tags()->attach([
    7 => ['created_at' => '2020-07-08 11:01:27'],
    8 => ['created_at' => '2020-07-08 11:01:27'],
]);

同步关联

copy$article = Article::find(1);
$article->tags()->sync([1,3]);
//sync(),等同于,新增或保留1,3,删除其他

删除关联

copy$article = Article::find(1);
$article->tags()->detach([1,3]);
//detach($tagIds); $tagIds: 数组,要删除的id
//  为null即不传参数时,删除对应的所有关联
posted @   pine007  阅读(1164)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示

目录导航