Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

michaelrtm's avatar

Using hasManyThrough through a pivot table

I am trying to create a relationship to access a table called comments through a model called grade, loaded through the students in the grade

From my understanding, it is not possible to access a hasManyThrough relationship that requires a pivot table (comments do not have a Grade identifier, only a student identifier)

Ultimately I want to run

App\User::find(x)->grade->comments

The current relationships are: Grade and Student models belongToMany of the other

class Grade extends Model{
    public function comments(){
        return $this->hasManyThrough("App\Comment","App\Student");
    }
}

And User:

//user belongs to one school
public function school()
{
    return $this->belongsTo("App\School");
}

// user has one teacher profile
public function teacher()
{
    return $this->hasOne("App\Teacher");
}

public function grade(){
    return $this->hasOne("App\Grade");
}

public function comments()
{
    return $this->hasMany("App\Comment");
}

I have these functions I found for Laravel 4 @ http://stackoverflow.com/questions/23788844/hasmanythrough-with-one-to-many-relationship/23789210#23789210 but it gives me the error Class 'App\Illuminate\Database\Eloquent\Relations\HasMany' not found

I don't have a good understanding on Namespaces, and can't work out what I should be doing in it's place for Laravel 5.

public function getCommentsAttribute()
{
    if ( ! array_key_exists('comments', $this->relations)) $this->loadComments();

    return $this->getRelation('comments');
}

protected function loadComments()
{
    $comments = Comment::join('grade_student', 'comments.student_id', '=', 'grade_student.student_id')
        ->where('grade_student.grade_id', $this->getKey())
        ->distinct()
        ->get(['comments.*','grade_id']);

    $hasMany = new Illuminate\Database\Eloquent\Relations\HasMany(Translation::query(), $this, 'grade_id', 'id');

    $hasMany->matchMany(array($this), $comments, 'comments');

    return $this;
}

More Info

Comment Table

    Schema::create('comments', function (Blueprint $table) {
        $table->increments('id');
        $table->timestamps();
        $table->integer('student_id')->unsigned();
        $table->integer('domain_id')->unsigned();
        $table->integer('teacher_id')->unsigned();
        $table->text('comment');

        $table->foreign('student_id')->references('id')->on('students') ->onDelete('cascade');
        $table->foreign('domain_id') ->references('id')->on('domains')->onDelete('cascade');
        $table->foreign('teacher_id')->references('id')->on('teachers')->onDelete('cascade');
    });

My Students Table

Schema::create('students', function (Blueprint $table) {
    $table->increments('id');
    $table->timestamps();
    $table->string('unique_identifier');
    $table->string('first_name');
    $table->string('last_name');
    $table->enum('gender',array('m','f'));
});

My Grades Table

Schema::create('grades', function (Blueprint $table) {
    $table->increments('id');
    $table->timestamps();
    $table->string('name',20);
    $table->integer('school_id')->unsigned();
    $table->integer('level_id')->unsigned();
    $table->foreign('school_id')->references('id')->on('schools')->onDelete('cascade');
    $table->foreign('level_id')->references('id')->on('classes_levels')->onDelete('cascade');
});

My Pivot Table

Schema::create('grade_student', function (Blueprint $table) {
    $table->engine = 'InnoDB';
    $table->increments('id');
    $table->timestamps();
    $table->integer('grade_id')->unsigned();
    $table->integer('student_id')->unsigned();
    $table->integer('school_id')->unsigned();
    $table->integer('year');

    $table->foreign('grade_id')->references('id')->on('grades')->onDelete('cascade');
    $table->foreign('student_id') ->references('id')->on('students')->onDelete('cascade');
    $table->foreign('school_id')->references('id')->on('schools') ->onDelete('cascade');
});
0 likes
5 replies
michaelrtm's avatar

I ended up going with this from one of the responses from the first link (lionelpc's response)

public function getCommentsAttribute(){
    return DB::table('comments')
        ->join('grade_student', 'comments.student_id', '=', 'grade_student.student_id')
        ->select('comments.*', 'grade_student.grade_id')
        ->where('grade_student.grade_id', '=', $this->id)->get();
}
michaelrtm's avatar

I still couldn't load related models through the query build way, and so I kept trying to work it out.

I ended up creating a new pivot table that had student_id and group_id as the primary keys, with no incremental id.

My Group model now has

public function comments()
{
    return $this->hasManyThrough("App\Comment", "App\Student", 'id', 'student_id');
}

and

App\Group::with('comments')->get()

returns a beautiful, related collection

1 like
misak's avatar

I guess this is a little old, but if anybody stumbles upon this, there's a package I developed that makes implementing these relationships a breeze! Check it out here!

Please or to participate in this conversation.