一对多、多对多关联,相对于来说还是比较容易的,可能后期由于业务升级,对于多表联查会有更多的需求时,可能就会用到多对多多态关联,中文手册里看到表述并不太清楚,也不容易让人理解,所以这里我以开发中实际遇到的案例做为讲解。
多对多多态关联的数据数结果最少应该是与4张表产生了关联,这种情况其实并不罕见,以我的美食网为例:
网站里的文章与菜谱可以共同使用同一个Tag标签,比如,我打开“丝瓜"这个标签时,如查询出与之相关的文章和菜谱:
其实表结构如下:
articles
id - integer
title - string
文章表ID为主键。
recipes
id - integer
name - string
菜谱表ID为主键。
tags
id - integer
name - string
标签表ID为主键。
tags_maps
tag_id - integer
taggable_id - integer
taggable_type - string
关联表是其几张表链接的桥梁,通过关联表,我可以无限链接其它更多的表,如:博客内容使用标签、视频使用标签、图片使用标签等。
tag_id 标签的ID。
taggable_id 与之产生关系的ID,如文章ID、菜谱ID、视频ID等。
taggable_type 与之产生关系的类名,这个需要与上面的taggable_id配合使用。
现在分别插入一条菜谱与文章的关联信息到关联表里:
INSERT INTO `meishi_tags_maps` (`tag_id`, `taggable_id`, `taggable_type`) VALUES(1, 121, 'article');
INSERT INTO `meishi_tags_maps` (`tag_id`, `taggable_id`, `taggable_type`) VALUES(1, 356, 'recipe');
现在Tag的第一个标签就与文章ID121和菜谱ID356产生了关联。我们现在需要通过Laravel的多对多多态关联的方法将其查询出来。
php artisan make:model Article
php artisan make:model Tag
php artisan make:model Recipe
php artisan make:model TagsMap
文章与菜谱模型里其主要内容为:
//获取文章TAGs(多对多关联)
public function tags()
{
//与Tag标签表关联
return $this->morphToMany(Tag::class, 'taggable', 'tags_maps') //关系名(类别字段名将以_type格式)中间表tags_maps,关联ID,关系键tag_id
->select('id', 'name'); //只需要标签ID,标签名
}
以上方法会生成下面的SQL查询语句:
select `id`, `name`
from `meishi_tags` inner join `meishi_tags_maps`
on `meishi_tags`.`id` = `meishi_tags_maps`.`tag_id`
where `meishi_tags_maps`.`taggable_id` = 1000001 and `meishi_tags_maps`.`taggable_type` = article
注意查询语句最后的结尾是article,这个并不会自动变成此值(不做这步时,此值为AppModelsArticle),我们还需要映射模型,打开app/Providers/AppServiceProvider.php 修改内容如下:
//启动APP服务
public function boot()
{
$this->bootEloquentMorphs();
}
//映射模型
private function bootEloquentMorphs()
{
Relation::enforceMorphMap([
'article' => 'AppModelsArticle', //文章模型
'recipe' => 'AppModelsRecipe', //菜谱模型
]);
}
然后控制器里使用下面的方法即可查询出来当前文章的所有标签:
use AppModelsArticle;
$article = Article::find(1);
foreach ($article->tags as $tag) {
//
}
我们通过返回菜谱与文章时,Tag模型如下:
//获取分配给此标签的所有文章。
public function articles()
{
return $this->morphedByMany(Article::class, 'taggable', 'tags_maps');
}
//获取分配给此标签的所有菜谱。
public function recipes()
{
return $this->morphedByMany(Recipe::class, 'taggable', 'tags_maps');
}
查询与Tag相关的文章:
Tag::find(1)->articles;
查询与Tag相关的菜谱:
Tag::find(1)->recipes;
最后,注意一个小坑就好了,模型生成的关联类型是以morphedByMany的每个名参数name_type方式,比如上面我的第二个参数为taggable,那么数据表里的字段名就应该是taggable_type与taggable_id。
除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:https://www.55mx.com/post/215
《【Laravel实战】理解多对多(morphedByMany)多态关联和实际中的应用结合》的网友评论(0)