Search code examples
laraveleloquentquery-buildereager-loading

How to return a collection of models with selected columns and relation eager loaded in Laravel 5.2


Problem details:

I have three models

  • a Directorate with id and name fields,
  • an Employee with id and name fields and
  • a Telephone with id, tel, employee_id, directorate_id, description and type fields. The employee_id may be nullable, that is there are telephones stored in database with employee_id = null

The models are related as follows:

  • an employee may have many telephones
  • a directorate, may have many telephones

    class Directorate extends Model
    {
        public function telephones()
        {
            return $this->hasMany(Telephone::class);
        }
    
        public function employees()
        {
            return $this->hasMany(Employee::class);
        }
    }
    
    
    class Employee extends Model
    {
        public function telephones()
        {
            return $this->hasMany(Telephone::class);
        }
    
        public function directorate()
        {
            return $this->belongTo(Directorate::class);
        }
    }
    
    
    class Telephone extends Model
    {
        public function employee()
        {
            return $this->belongsTo(Employee::class);
        }
    
        public function directorate()
        {
            return $this->belongsTo(Directorate::class);
        }
    }
    

Question:

I want to fetch a Collection of all the Telephone models that belong to a specific Directorate, that have employee_id = null and also having their directorate relation eager loaded. In addition, from that resulting collection of Telephone models, I need only some of the models' fields, that is id, tel and description

Tries

What I tried so far was the following:

I created a query scope in the Telephone model:

public function scopeHaveNoEmployeeId($query)
{
    return $query->where('telephones.employee_id', '=', null);
}

In my controller

$myTelephones = Telephone::with('directorate')

                ->haveNoEmployeeId()

                ->where('directorate_id', $directorateId)

                ->get(['id', 'tel', 'description']);

However what I am receiving are the requested fields of the filtered models without the relation eager loaded, for instance:

[
{
"id": 79,
"tel": "0648136867",
"directorate": null
},
{
"id": 380,
"tel": "0223796011",
"directorate": null
}
] 

I tried also to lazy eager load the relation afterwards but with no luck.

Finally I noticed that if I request all the Telephone models fields, the relation will eager load as I request. For example:

$myTelephones = Telephone::with('directorate')

                ->haveNoEmployeeId()

                ->where('directorate_id', $directorateId)

                ->get();

Then as a result:

[
{
"id": 79,
"tel": "0648136867",
"directorate": {
                "id": 23
                 "name": "Some name"
                }    
},
{
"id": 380,
"tel": "0223796011",
"directorate": {
                "id": 23
                 "name": "Some name"
                }       
}  
] 

Solution

  • Actually, after digging into Laravel's details for a while, I noticed that my initial question was out of context and somewhat silly. I was first eager loaded a relationship and then fatuously I filtered out the relationship by not including it in get() parameters. I had just to do the following:

    $myTelephones = Telephone::with('directorate')
    
                    ->haveNoEmployeeId()
    
                    ->where('directorate_id', $directorateId)
    
                    ->get(['id', 'tel', 'description', 'directorate']);