Laravel学习笔记基础系列--(二十七)Laravel 模型间的远程关联关系
作者:温新
时间:2021-07-02
hi,我是温新,一名PHPer
要弄懂远程远程关联关系,那么就少不了对基础关联关系的理解。拿多对多关联来说,其借助中间表来实现,而远程关系关系同样是借助中间表来实现。之所以叫远程关系,就是因为不能够直接获取到想要的数据,需要借助中间某个东西,而这个东西就可以理解为中间表。
举个例子,有个全球化的博客系统,针对不同国家的人只展示对应国家的文章,如中国用户只展示中国用户的文章,小日本用户只展示小日本的文章。现在我们有users
表,posts
表,还缺少一个countries
表。用户与文章是一对多的关系,国家与用户之间是一对多关系;通过中间表可以建立起国家与文章之间的一对多关系(这个关系就要通过远程关联来实现)。
准备工作
远程一对一准备工作
一个用户只一个合法的爱人,那么这个用户的爱人就可以通过该用户知道所就读的学校。
第一步:创建学校模型及迁移文件
php artisan make:model School -m
第二步:编写迁移文件
Schema::create('schools', function (Blueprint $table) {
$table->increments('id');
$table->string('shcool_name')->unique()->comment('学校名称');
$table->unsignedInteger('user_id')->comment('用户ID');
$table->timestamps();
});
第三步:创建用户爱人模型及迁移文件
php artisan make:model Lover -m
第四步:编写迁移文件
Schema::create('lovers', function (Blueprint $table) {
$table->increments('id');
$table->string('lover_name')->comment('爱人名字');
$table->timestamps();
});
第五步:用户表新增爱人关联id
php artisan make:migration alter_users_add_lover_id_to_user --table=users
第六步:编写迁移文件
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->unsignedInteger('lover_id')->comment('关联爱人ID');
});
}
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('lover_id');
});
}
第七步:执行迁移
php artisan migrate --path=database/migrations/2021_07_01_174008_create_schools_table.php
php artisan migrate --path=database/migrations/2021_07_01_174102_create_lovers_table.php
php artisan migrate --path=database/migrations/2021_07_01_174226_alter_users_add_lover_id_to_user.php
第八步:自行填充数据
远程一对多准备工作
创建国家表与其对应的模型
第一步:创建国家模型及迁移文件
php artisan make:model Country -m
第二步:编写迁移文件
Schema::create('countries', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 100)->unique();
$table->string('slug', 100)->unique();
$table->timestamps();
});
第三步:users
表中增加关联国家字段
php artisan make:migration alter_users_add_country_id --table=users
第四步:编写迁移文件
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->integer('country_id')->unsigned()->default(0);
$table->index('country_id');
});
}
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('country_id');
});
}
第五步:运行迁移文件
php artisan migrate --path=database/migrations/2021_07_01_164520_create_countries_table.php
php artisan migrate --path=database/migrations/2021_07_01_164719_alter_users_add_country_id.php
第六步:自行添加填充数据
远程一对一
方法:hasOneThrough($related, $through, $firstKey = null, $secondKey = null, $localKey = null, $secondLocalKey = null)
// 参数解释
参数一:最终希望获取数据的模型类名。这里是School模型;
参数二:中间模型类名。这里是User模型;
参数三:中间模型关联外键ID。这里是User模型的lover_id;
参数四:最终希望获取数据的模型关联外键ID。这里是School模型的user_id;
参数五:当前模型主键ID。这里是Lover模型的id;
参数六:中间模型的主键ID。这里是User模型的id;
前面已经完成了远程一对一的相关准备工作,那么,现在来解释一下所要完成的相关查询(不考虑非正常情况)。三张表分别是users
用户表,schools
用户所有学校表,lover
用户爱人表。一个用户与一个学校形成一对一的关系,一个用户一生只有一个合法的爱人,其爱人就可以通过用户获取用户所读学校的相关信息,这过程就是远程一对一关系。
查询时需要理清关系,是爱人要获取用户学校信息。
下面通过代码来实现。
第一步:定义模型关联方法
文件:app/Models/Lover.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Lover extends Model
{
use HasFactory;
public function userSchool()
{
// 注意这个名字千万不能写反,否则会报错
return $this->hasOneThrough(
School::class,
User::class,
'lover_id',// users表中关联爱人模型的外键
'user_id',// shcools表中的关联用户的外键
'id', //当前模型lovers表中的住键
'id'//users表的主键
);
}
}
添加参数时请一定要注意,有时候填错了,也能够正确的显示数据。
第二步:控制器调用
文件:DemoController.php
中的demo
方法
use App\Models\Lover;
// 远程一对一。用于 爱人需要获取用户所在学校的信息
$loverUserSchool = Lover::find(1)->userSchool;
dd($loverUserSchool);
远程一对多
方法:hasManyThrough($related, $through, $firstKey = null, $secondKey = null, $localKey = null, $secondLocalKey = null)
参数一:最终希望获取数据的模型类名。这里是文章模型Post;
参数二:中间模型类名。这里是User模型;
参数三:中间模型外键关联ID。这是User模型中country_id,用户关联countries表;
参数四:最终要获取数据的模型关联的外键ID。这里countries表的user_id;
参数五:当前模型的主键ID;这里是Contry模型的id;
参数六:中间模型的主键ID;这里是User模型的id;
第一步:定义模型方法
文件:app/Models/Country.php
return $this->hasManyThrough(
Post::class,//要获取数据的模型
User::class,//中间模型
'country_id',//中间模型User中的关键Country模型外键id
'user_id',//获取数据的模型Post所关联用户模型的user_id
'id',//当前模型主键ID
'id'//中间模型主键ID
);
第二步:控制器调用
文件:DemoController.php
中的demo
方法
use App\Models\Country;
// 远程一对多。该案例用于获取某个国家的所有文章
$countryPosts = Country::find(1)->posts;
关于远程关联关系的记录就到这里结束了。关于远程关联关系还是有点不太好理解的,在动手操作之前需要仔细把模型之前的关系缕清。只有把关系缕清了,动手时不会显得似懂非懂。
关于所有模型关联关系的操作,一定要把参数写全。虽然Laravel模型是约定优于配置,但是我仍旧要建议,一定要把参数写全!一定要把参数写全!一定要把参数写全!参数写全不仅利于理解,更利于维护。
我是温新
每天进步一点点,就一点点