You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 5.4如何通过hasManyThrough获取用户订阅课程的作业?

嘿,刚好碰到过类似的问题,Laravel 5.4 的 hasManyThrough 确实存在这个局限——它没办法指定中间表(UserCourse)用来关联目标表(Homework)的字段,默认会用中间表的 id 去关联 Homework 的 course_id,这就导致了 SQL 错误。下面给你两个实用的解决方案:

方案一:手动构建查询(简单直接)

如果不需要 Eloquent 关联的高级特性(比如预加载、关联附加等),直接在 User 模型里写一个方法,用查询构造器手动关联表即可:

public function homeworks()
{
    return \App\Homework::join('user_course', 'user_course.course_id', '=', 'homework.course_id')
        ->where('user_course.user_id', $this->id)
        ->select('homework.*');
}

使用的时候直接调用:

$user = User::find(1);
$userHomeworks = $user->homeworks()->get();

这个方法简单粗暴,马上就能解决问题,唯一的缺点是它返回的是查询构造器实例,不是标准的 Eloquent 关联对象,所以没法用 with('homeworks') 这种预加载方式。

方案二:自定义关联类(支持 Eloquent 特性)

如果需要保留 Eloquent 关联的所有特性(比如预加载、关联计数等),可以自定义一个扩展版的 HasManyThrough 关联类,来弥补 5.4 的参数缺失:

步骤1:创建自定义关联类

在 app/Relations 目录下新建 CustomHasManyThrough.php(如果没有 Relations 目录就自己创建):

namespace App\Relations;

use Illuminate\Database\Eloquent\Relations\HasManyThrough;

class CustomHasManyThrough extends HasManyThrough
{
    protected $throughForeignKey;

    public function __construct($query, $farParent, $throughParent, $firstKey, $secondKey, $throughForeignKey)
    {
        parent::__construct($query, $farParent, $throughParent, $firstKey, $secondKey);
        $this->throughForeignKey = $throughForeignKey;
    }

    // 重写方法,指定中间表用来关联目标表的字段
    protected function getQualifiedForeignKeyName()
    {
        return $this->throughParent->getTable() . '.' . $this->throughForeignKey;
    }
}

步骤2:在 User 模型中使用自定义关联

修改 User 模型,引入自定义关联类并定义 homeworks 方法:

use App\Relations\CustomHasManyThrough;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    // ... 其他模型代码

    public function homeworks()
    {
        // 初始化中间表和目标表的实例
        $throughModel = $this->newRelatedInstance(\App\UserCourse::class);
        $targetQuery = $this->newRelatedInstance(\App\Homework::class)->newQuery();

        return new CustomHasManyThrough(
            $targetQuery,
            $this,
            $throughModel,
            'user_id',       // User表关联UserCourse的字段
            'course_id',     // Homework表中关联的字段
            'course_id'      // UserCourse表关联Homework的字段(这就是5.4缺失的参数)
        );
    }
}

现在你就可以像使用标准 Eloquent 关联一样操作了:

// 直接获取作业
$user = User::find(1);
$homeworks = $user->homeworks;

// 预加载作业
$users = User::with('homeworks')->get();

补充说明

Laravel 5.5 确实通过 PR #19114 给 hasManyThrough 添加了 $throughKey 参数,用来指定中间表关联目标表的字段,所以在 5.5+ 里你可以直接这么写:

$this->hasManyThrough('App\Homework', 'App\UserCourse', 'user_id', 'course_id', null, 'course_id');

但 5.4 不支持这个参数,所以只能用上面的两种方法来绕开这个限制。

内容的提问来源于stack exchange,提问作者Denis Rozimovschii

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:30:58