Laravel学习笔记基础系列--(二十八)Laravel 模型间的多样化关联关系
作者:温新
时间:2021-07-02
hi,我是温新,一名PHPer
关于多样化关联关系,我不知道如何来介绍,通过案例需求来说看吧。
多样化一对一关联关系
什么是多样化一对关联关系?
有这样一个需求,文章封面缩略图与用户头像共用一张缩略图,关于这个需求如何实现?现在就来看看多样化一对一是如何实现这个需求的。
- 1)一个用户只能设置一个头像,因此用户与头像之间是一对一的关系;
- 2)一篇文章只能有一个封面缩略图,因此文章与缩略图之间也是一对一的关系;
- 3)可以看到,用户与图片之间存在关系,因此把图像独立出来,使用一个字段用户标识图像是谁的,这样就可以建立一个多样化的一对一关系出来。
已知现在有users
表与posts
表,现在还需要一个用户存放图片的images
表。images
表需要两个字段才能建立起多样化一对一关联关系。第一个字段是存放模型完整路径名称;第二个字段是用于存放用户ID或文章ID。
正向多样化一对一关联关系
准备工作
第一步:创建图像模型及迁移文件
php artisan make:model Image -m
第二步:编写迁移文件
Schema::create('images', function (Blueprint $table) {
$table->increments('id');
$table->string('url')->comment('图片URL');
$table->morphs('imageable');
$table->timestamps();
});
注意:$table->morphs('imageable');
用于创建imageable_id
与imageable_type
字段。
imageable_type
字段用于存放模型,如app\Models\Post
;
imageable_id
字段用于存放对应的模型实例ID。对于本案例来讲,就是文章主键ID与用户主键ID。
第三步:执行迁移文件
php artisan migrate --path=/database/migrations/2021_07_02_145619_create_images_table.php
第四步:自行填充数据
如:我这里使用的数据是
id | url | imageable_type | imageable_id |
---|---|---|---|
1 | https://www.ziruchu.com/uploads/article/20210523/2021052343644.jpg | App\Models\User | 1 |
2 | https://www.ziruchu.com/uploads/article/20210612/2021061299961.jpg | App\Models\Post | 1 |
正向一对一关联关系的使用
方法:morphTo($name = null, $type = null, $id = null, $ownerKey = null)
参数一:关联关系方法名。本例关联关系方法名是 imageable
参数二、三需要配合 参数一 用于构建关联字段;本例中参数二是imageable_type,参数三是imageable_id
参数四:当前模型主键ID
案例:通过图片查询用户或文章信息
第一步:定义模型方法
文件:app/Models/Image.php
public function imageable()
{
return $this->morphTo(__FUNCTION__, 'imageable_type', 'imageable_id','id');
}
第二步:控制器调用
文件:DemoController.php
// 通过Image实例获取其归属模型实例
$image = Image::find(2)->imageable;
此时返回的就是App\Models\Post
实例,若find(1)
返回的则是App\Models\User
实例。
相对多样化一对一关联关系
方法:morphOne($related, $name, $type = null, $id = null, $localKey = null)
参数一:相关联的模型类。这里是Image模型;
参数二:关联关系方法名。这里是image;
参数三、四需要配置 参数二 用于构建关联字段。本例中参数三为imageable_type,参数四为 imageable_id;
参数五:当前模型主键ID
在实际开发,最为常见的是获取用户头像或谋篇文章的缩略图。
第一步:定义模型方法
文件:app/Models/User.php
// 相对多样化一对一
public function image()
{
return $this->morphOne(Image::class, 'imageable','imageable_type','imageable_id','id');
}
文件:app\Models/Post.php
// 相对多样化一对一
public function image()
{
return $this->morphOne(Image::class, 'imageable', 'imageable_type','imageable_id','id');
}
第二步:控制器调用
文件:DemoController.php
中的demo
方法
$imagePost = Post::find(1)->image;
$imageUser = User::find(1)->image;
多样化一对多关联关系
什么是多样化一对多关联关系
多样化一对多关联与普通的一对多关系是类似的,不同的是,目标模型可以在一个关联中从属于多个模型。
以博客系统为例,文章一般有两种,一是普通文章页面,二是一个单页页面。这两个页面都可以有评论。实际开发中不会建2张数据结构完全一样表来存储不同页面的评论内容。做法是,一张评论表中加上用于区分不同页面的评论作为标识,这样就可以区分是文章页面还是单独的独立页面。
准备工作
第一步:创建评论表模型及迁移文件
php artisan make:model Comment -m
第二步:编写迁移文件
public function up()
{
Schema::create('comments', function (Blueprint $table) {
$table->increments('id');
$table->text('content')->comment('评论内容');
$table->integer('user_id')->unsigned()->default(0);
$table->morphs('commentable');
$table->index('user_id');
$table->softDeletes();
$table->timestamps();
});
}
第三步:创建独立页面模型及迁移文件
php artisan make:model Page -m
第四步:编写迁移文件
public function up()
{
Schema::create('pages', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('slug')->unique();
$table->text('content');
$table->integer('user_id')->unsigned()->default(0);
$table->index('user_id');
$table->timestamps();
});
}
第五步:执行迁移文件
php artisan migrate --path=/database/migrations/2021_07_02_165923_create_comments_table.php
php artisan migrate --path=/database/migrations/2021_07_02_170056_create_pages_table.php
评论表的迁移文件中使用了morphs
,这不是多样化一对一使用的方法吗?现在来分析下,一个评论只会对应一个页面(文章页/独立页面),我们需要使用morphs
生成两个用于标识不同页面评论的字段。因此仍旧使用morphTo
方法定义文页与独立页面的关联关系。
第六步:自行填充数据
以下我用的测试数据
comments
表
id | comment | user_id | commentable_id |
---|---|---|---|
1 | 好文章 | 1 | 1 |
2 | 很不错的文章 | 1 | 1 |
3 | 这个独立页面真好 | 2 | 1 |
4 | 不错不独立页面 | 2 | 1 |
pages
表
id | title | content | user_id |
---|---|---|---|
1 | 我是独立页面 | 独立页面内容独立页面内容 | 2 |
多样化一对多关系
第一步:定义模型方法
文件:app/Models/Comment.php
public function commentable()
{
return $this->morphTo(__FUNCTION__, 'commentable_type','commentable_id','id');
}
在评论模型中使用morphTo
方法定义与Post
模型和Page
模型之间的多样化一对多关联。
第二步:控制器调用
// 获取某个单页的所有评论
$pages = Page::find(1)->comments;
相对多样化一对多关联关系
方法:morphMany($related, $name, $type = null, $id = null, $localKey = null)
参数含义与
morphOne
完全一致。
一般的情况下,都是使用文章来获取评论。假如现在是想通过评论来获取文章信息呢?此时需要在Post
模型和Page
模型中使用morphMany
方法实现。
第一步:模型中定义方法
文件:Post模型
public function comments()
{
return $this->morphMany(Comment::class,'commentable','commentable_type','commentable_id','id');
}
文件:Post模型
public function comments()
{
return $this->morphMany(Comment::class,'commentable','commentable_type','commentable_id','id');
}
第二步:控制器调用
$postsComment = Post::with('comments')->find(1);
多样化多对多关联关系
什么是多样化多对多关联关系
与普通的多对多类似,不同的是多样化多对多关系的中间表存的不再是post_id
与tag_id
,而是换成的模型名,用于标识标签是谁的。普通的对多对是ID进行关联,而多样化多对多则是与模型名进行关联。仍旧用到了一对一时用到的方法morphs
。
仍旧用文章与标签模型举例,当需要添加视频、音频等页面时,他们也是有标签的,他们表结构是一样的,因此完全可以共用一张标签表。面对多样化的内容,使用ID来存储是不够的。那么多样化多对多就来了,用于解决这样的问题。
准备工作
之前所建议的post_tag
中间表,这里就用不上,这里就需要新建一个中间表来完成多样化多对多关系。
第一步:创建中间表
php artisan make:migration create_taggables_table --create=taggables
第二步:编辑迁移文件
Schema::create('taggables', function (Blueprint $table) {
$table->increments('id');
$table->integer('tag_id');
$table->morphs('taggable');
$table->index('tag_id');
$table->unique(['tag_id', 'taggable_id', 'taggable_type']);
$table->timestamps();
});
morphs方法用于生成标识标签归属模型
第三步:运行迁移文件
php artisan migrate --path=database/migrations/2021_07_03_062420_create_taggables_table.php
第四步:自行填充数据
如下数据是我使用的案例
id | tag_id | taggable_type | taggable_id |
---|---|---|---|
1 | 1 | App\Models\Post | 1 |
2 | 2 | App\Models\Page | 1 |
3 | 1 | App\Models\Post | 1 |
多样化多对多关联
方法:morphedByMany($related, $name, $table = null, $foreignPivotKey = null,$relatedPivotKey = null,$parentKey = null, $relatedKey = null)
参数一:需要关联的模型类。如Post、Page模型;
参数二:关联的名称。需要和迁移文件时morphs方法指定的值一致,如taggable;
参数三:中间表名称。这里是 taggables 表;
参数四:当前模型类在中间表中的外键。这是 taggables表中的 tag_id;
参数五:中间表中的关联字段。这里是 taggables表中 taggable_id;
参数六:当前模型类的主键ID。如当前模型Tag中的id;
参数七:关联模型的主键ID。这里就是参数一模型中的主键。
第一步:Tag模型中定义多样化多对对方法
文件:app\Models\Tag.php
// 文章多样化多对多
public function manyPostTag()
{
return $this->morphedByMany(Post::class,'taggable','taggables','tag_id','taggable_id','id','id');
}
// 单页多样化多对多
public function manyPageTag()
{
return $this->morphedByMany(Page::class, 'taggable','taggables','tag_id','taggable_id','id','id');
}
第二步:控制器调用
// 通过标签来获取文章
$tags = Tag::with('manyPostTag','manyPageTag')->find(1);
$tags->manyPostTag;
$tags->manyPageTag;
相对多样化多对多关联
方法:morphToMany($related, $name, $table = null, $foreignPivotKey = null,$relatedPivotKey = null, $parentKey = null,$relatedKey = null, $inverse = false)
morphToMany
方法的参数与morphedByMany
的参数含义完全是一样的。不同的是参数一(需要关联的模型)与参数七(需要关联的模型的主键)不同。如这个案例是通过文件来获取标签,因此我们使用的Post
模型需要与Tag
模型进行关联,那么参数一就要换成Tag模型,若Tag模型的主键ID不是id
,那么就需要修改参数七。
第一步:定义模型方法
文件:app\Models\Post.php
public function mangTags()
{
return $this->morphToMany(Tag::class,'taggable','taggables','tag_id','taggable_id','id','id');
}
第二步:控制器调用
$postTag = Post::with('mangTags')->find(1);
到这里,多样化关联关系就记录完了。
更新完成时间:7月3日
关于多样化关联关系,我在实际开发中并没有用到。很多参数的含义已经忘记,得查看文档,算是当做一个复习了。如果参数不写全,时间久了,会是一脸懵逼。因此还是那句话,参数一定要写全。
顺便再说一句,我们习惯了使用id
作为自增主键,而在实际开发中,不使用自增ID作为主键的情况非常多。因此,参数一定要写全。
我是温新
每天进步一点点,就一点点