Mihkel Allorg
Mihkel Allorg

Reputation: 989

Laravel 5.1 relationship of relationship

Let's say I have three models:

  • Worker
  • Department
  • Company

A Company has many Departments and a Department has many Workers. Now how can I get all the Workers from the company?

I can get all the departments with

Company::find(1)->departments()

I can get all the Workers with

Department::find(1)->workers()

I tried creating a method to the model Company like that:

public function workers()
{
    return $this->departments->map(function($item, $key){
        return $item->workers;
    });
}

The issue rose, when I wanted to call a the method 'where()' on the collection with three arguments and it gave me an empty collection.

Company::find(1)->workers()->where('salary', '>=', '100');

And that returns an empty collection whatever I do. I tried whereLoose, passed '100' as an integer. The following works fine:

Company::find(1)->workers()->where('salary', '100');

Gives me all the workers, who have a salary of 100.

Is there a way to kind of use the Relationships so I can get the Relationship from Company->hasMany('Worker')?

Upvotes: 2

Views: 1321

Answers (2)

num8er
num8er

Reputation: 19372

Read about hasManyThrough (http://laravel.com/docs/5.1/eloquent-relationships#has-many-through). Add function to Your Company model:

public function workers()
{
    // hasMany Workers through Department
    return $this->hasManyThrough('App\Models\Worker', 'App\Models\Department'); 
}

so now You're able to do:

$Company = Company::with('workers')->find(1);
$Workers = $Company->workers;



a little bonus. to get data through 2 models, something like hasManyThrough+hasMany (not tested):

create class (file in models directory):

app/Models/ExtendedModel.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class ExtendedModel extends Model {
    public function hasManyThrough2Models($model1, $model2, $model3, $model1Key, $model2KeyWith1, $model2Key, $model3KeyWith2)
    {
        $model1 = new $model1;
        $model1Table = $model1->getTable();
        $model2 = new $model2;
        $model2Table = $model2->getTable();
        $model3 = new $model3;
        $model3Table = $model3->getTable();

        return $model1
            ->join($model2Table, $model2Table . '.' . $model2KeyWith1, '=', $model1Table . '.' . $model1Key)
            ->join($model3Table, $model3Table . '.' . $model3KeyWith2, '=', $model2Table . '.' . $model2Key)
            ->select($model1Table . '.*');
    }
}

and then get data through 2 models:

<?php namespace App\Models;

class Company extends ExtendedModel {

    public function worksheets() {
        return $this->hasManyThrough2Models('App\Models\Worksheet', 'App\Models\Worker', 'App\Models\Department', 'worker_id', 'id', 'department_id', 'id');
    }

now use:

$Company = Company::with('worksheets')->find(1);
$Worksheets = $Company->worksheets;

Upvotes: 1

The Alpha
The Alpha

Reputation: 146191

You may try:

$company = Company::with('departments.workers')->find(1);

So, it'll return all the workers who belongs to that company under each department individually. In this case, you may loop like this:

@foreach($company->departments as $department)

    {{ $department->name }}

    @foreach($department->workers as $worker)

        {{ $worker->name }}

    @endforeach;

@endforeach;

Upvotes: 0

Related Questions