staudenmeir / eloquent-has-many-deep

Laravel Eloquent HasManyThrough relationships with unlimited levels
MIT License
2.67k stars 157 forks source link

Trying to get withCount of a hasManyDeep relationship #120

Closed JeffreyDavidson closed 2 years ago

JeffreyDavidson commented 3 years ago

I'm retrieving all courses that were taken during a semester. As you can see there is not a has many relationship between semester and course. Instead, I'm using the many-to-many relationship between a semester and a course section, and with the course sections get the one-to-many relationship between the course section and course.

Currently I'm getting the collection of courses for a semester. What I also need to do is get the count of students that have participated in the sections for these courses for the specific semester.

Right now when I loop over the courses and in my view and dd() the first $course in the loop I don't see a accessor/property for the withCount of students anywhere. Inside the courseSectionSemester relation of the course I do see the students as inside the withCounts but no accessor in the attributes to access. What am I doing wrong here?

Any ideas?

Semester
- id
- name
...

Course
- id
- name
...

CourseSection
- id
- course_id
...

CourseSectionSemester
- id
- course_section_id
- semester_Id
...

CourseSectionSemesterStudent
- id
- course_section_semester_id
- student_id

Semester.php

public function courses()
{
    return $this->hasManyDeep(
        Course::class,
        [CourseSectionSemester::class, CourseSection::class],
        ['semester_id', 'course_id', 'id']
    );
);

CourseSectionSemester.php

protected $withCount = ['students'];

public function students()
{
    return $this->belongsToMany(
        User::class, 
        'course_section_semester_student', 
       'section_semester_id', 'student_id'
    )->withTimestamps();
}

Query Ran From Livewire Component

$query = $this->semester->courses()->newQuery()...
staudenmeir commented 3 years ago

Right now when I loop over the courses and in my view and dd() the first $course in the loop I don't see a accessor/property for the withCount of students anywhere

Isn't the withCount on the CourseSectionSemester model while you are checking a Course?

Inside the courseSectionSemester relation of the course I do see the students as inside the withCounts but no accessor in the attributes to access.

How are you accessing the courseSectionSemester? Are you eager loading the relationship?

$query = $this->semester->courses()->newQuery()...

Where is ->newQuery() coming from?

JeffreyDavidson commented 3 years ago

@staudenmeir

Isn't the withCount on the CourseSectionSemester model while you are checking a Course?

Yes it is.

How are you accessing the courseSectionSemester? Are you eager loading the relationship?

How should I be eager loading this data?

Where is ->newQuery() coming from?

I have now removed this section of the query.

I'm just not sure what I'm doing wrong here.

staudenmeir commented 3 years ago

Isn't the withCount on the CourseSectionSemester model while you are checking a Course?

Yes it is.

Do you mean that a withCount attribute of CourseSectionSemester should appear on a Course?

JeffreyDavidson commented 3 years ago

It shouldn't be accessed directly by course but I'm not sure what I need to do to access the relationship count.

JeffreyDavidson commented 3 years ago

@staudenmeir I included all included models as a way to help give you clarity on relationships.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Staudenmeir\EloquentHasManyDeep\HasRelationships;

class Semester extends Model
{
    use HasFactory, HasRelationships;

    /**
     * Get course sections for the semester.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function courseSections()
    {
        return $this->belongsToMany(CourseSection::class)->using(CourseSectionSemester::class)->withTimestamps();
    }

    /**
     * Get the courses for the semester.
     *
     * @return \Staudenmeir\EloquentHasManyDeep
     */
    public function courses()
    {
        return $this->hasManyDeep(
            Course::class,
            [CourseSectionSemester::class, CourseSection::class],
            ['semester_id', 'course_id', 'id']
        )->withIntermediate(CourseSectionSemester::class);
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\Pivot;

class CourseSectionSemester extends Pivot
{
    use HasFactory;

    /**
     * The relationship counts that should be eager loaded on every query.
     *
     * @var array
     */
    protected $withCount = ['students'];

    /**
     * Get the semester for the course sememester.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function semester()
    {
        return $this->belongsTo(Semester::class);
    }

    /**
     * Get the course section for the course semester.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function courseSection()
    {
        return $this->belongsTo(CourseSection::class);
    }

    /**
     * Get the students of the course section.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function students()
    {
        return $this->belongsToMany(User::class, 'course_section_semester_student', 'section_semester_id', 'student_id')->withTimestamps();
    }
}
<?php

namespace App\Models;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class CourseSection extends Model
{
    use HasFactory;

    /**
     * Get the course of the course section.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function course()
    {
        return $this->belongsTo(Course::class);
    }

    /**
     * Get the semesters of the course section.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function semesters()
    {
        return $this->belongsToMany(Semester::class)->using(CourseSectionSemester::class)->withTimestamps();
    }

    /**
     * Get the teacher of the course section.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function teacher()
    {
        return $this->belongsTo(User::class);
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Course extends Model
{
    use HasFactory;

    /**
     * Retrieve sections for the course.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function sections()
    {
        return $this->hasMany(CourseSection::class);
    }
}
JeffreyDavidson commented 3 years ago

@staudenmeir As one more followup the relationship that I have to get from semesters to courses even though having the HasManyDeep does return correctly for me is the fact that it might be a false positive. Is this package not supporting of this type of level of relationships?

Semester has Many-> CourseSectionSemester Belongs to -> CourseSection belongs To Course
staudenmeir commented 3 years ago

Sorry, I didn't have any time. Is your question still standing?