Laravel学习笔记基础系列--(二十七)Laravel 模型间的远程关联关系

作者: 温新

分类: 【Laravel】

阅读: 1639

时间: 2021-07-28 14:58:14

作者:温新

时间: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模型是约定优于配置,但是我仍旧要建议,一定要把参数写全!一定要把参数写全!一定要把参数写全!参数写全不仅利于理解,更利于维护。

我是温新

每天进步一点点,就一点点

请登录后再评论