Laravel Eloquent:模型关联远程一对多的反向,远程一对一写法记录

因工作中需要且在论坛没有找到相关的答案,自行找到了解决办法,记录一下。

远程一对多文档链接
拿文档的表结构举例

projects
    id - integer
    name - string

environments
    id - integer
    project_id - integer
    name - string

deployments
    id - integer
    environment_id - integer
    commit_hash - string

官方给予的远程一对多配置

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Project extends Model
{
    /**
     * 获取项目的所有部署。
     */
    public function deployments()
    {
        return $this->hasManyThrough(Deployment::class, Environment::class);
    }
}

上面的可以通过project直接获取所有部署不多赘述。
但是有的时候可能需要从部署的机器来获取项目信息,以上表结构也可以两个反向一对一来解决问题,但是有点不够优雅。
比如一下这两个模型关联

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Environment extends Model
{
    /**
     * 获取环境所属项目。
     */
    public function Project()
    {
        return $this->belongsTo(Project::class);
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Deployment extends Model
{
    /**
     * 获取部署所属环境。
     */
    public function Environment()
    {
        return $this->belongsTo(Environment::class);
    }

    // 这样从部署对象获取项目
    public function getProject()
    {
        $deployment = self::query()
            ->with(['Environment' => function (BelongsTo $query) {
                $query->with(['Project']);
            }])
            ->first();
        $project = $deployment->Environment->Project;
    }
}

以上的办法有点冗余,每次要使用都要with套with,而且如果要筛选projects的name字段是某个值的部署列表,使用whereHas也很麻烦(真实场景可能是部署列表里筛选project的status字段是正常的等等),还需要用到having,但是如果能在Deployment中直接定义一个远程一对一关联到Project,那就可以直接一个with取到Project信息,而且可以正常使用whereHas,定义方式如下:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Deployment extends Model
{
    /**
     * 获取部署所属环境。
     */
    public function Project()
    {
        return $this->hasOneThrough(
            Project::class,  // 最终获取表
            Environment::class, // 中间表
            'id',   // Environment 被Deployment表(当前表) 关联主键
            'id',   // Project 被Environment表(中间表) 关联主键
            'environment_id',  // Deployment表(当前表)关联中间表关联字段
            'project_id'  // Environment(中间表) 关联最终表关联字段
        );
    }

    // 这样从部署对象获取项目
    public function getProject()
    {
        $deployment = self::query()
            ->with(['Project'])
            ->first();
        // 获取项目信息
        $project = $deployment->Project;
        // whereHas筛选 名字是我的项目的部署列表
        $deployment = self::query()
            ->whereHas('Project',function ($query) {
                $query->where(['projects.name' => '我的项目']);
            })
            ->get()->toArray();
    }
}

以上,希望可以帮助到各位

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!