darkylmnx
darkylmnx

Reputation: 2071

multiple "has many through" with eloquent of laravel

I came accros a problem with laravel's ORM, eloquent and found no solution yet.

I have some tables as follows

Team

 - id
 - name

User

 - id
 - name
 - role
 - team_id

Student_Info

 - id
 - user_id
 - data1
 - data2
 - etc ...

Project

 - id
 - student_id
 - name

Now, I want to query all projects a certain team, where team = 'some team'

Now the thing here is, without an ORM, it's simple, I would have done multiple joins in raw SQL.

However, because all these tables have a common column "name" I will have to alias all this stuff, which is really boring

With eloquent I can't find a way to do this query using "has many through" because it only allows on intermediate and I can't do a raw SQL as the alis thing is really a pain in the ass and as it would be very difficult to map the result to laravel's Models

Upvotes: 4

Views: 5295

Answers (2)

Jonas Staudenmeir
Jonas Staudenmeir

Reputation: 25906

There is no native relationship for this case.

I created a HasManyThrough relationship with unlimited levels: Repository on GitHub

After the installation, you can use it like this:

class Team extends Model {
    use \Staudenmeir\EloquentHasManyDeep\HasRelationships;

    public function projects() {
        return $this->hasManyDeep(Project::class, [User::class, StudentInfo::class],
            [null, null, 'student_id']);
    }
}

$projects = Team::where('name', 'some team')->first()->projects;

Upvotes: 10

EddyTheDove
EddyTheDove

Reputation: 13259

Try with relationship existence. This assumes you have all relationships properly defined

$projects = Project::whereHas('students.user.team', function ($query) {
    $query->where('name', '=', 'some team');
})->get();

That's 3 levels of nesting. Never tested. However, if you already define a Project-User relationship via hasManyThrough() you can shorten it to 2 levels only.

$projects = Project::whereHas('user.team', function ($query) {
    $query->where('name', '=', 'some team');
})->get();

Those will give you the data for projects only. If you also want the the intermediate data, use eager loading instead with with(). Just replace whereHas() by with().

$projects = Project::with('user.team', function ($query) {
    $query->where('name', '=', 'some team');
})->get();

Upvotes: 1

Related Questions