I have the following models in my application:
User.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function customer_details()
{
return $this->hasOne(CustomerDetails::class);
}
}
CustomerDetails.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class CustomerDetails extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
Now I am trying to run the following query:
$user = User::select('email', 'phone')
->where('id', Auth::user()->id)
->with('customer_details')
->first();
Now what I want it to do is to select only the email and phone number from my users table and first_name, last_name from my customer_details table but whenever I try this it always returns customer_details as null
.
You need to include the id
in your select, otherwise the eager loading has nothing to match against. I just tested this against my own project and ran into the same issue, adding the id
to the select fixes it.
$user = User::select('id', 'email', 'phone')->where('id', Auth::user()->id)->with('customer_details')->first();
To further explain this, eager loading works by making your parent call first (in this case, the call to users
) and then doing a second call like SELECT * FROM customer_details WHERE customer_details.user_id IN (?)
where ?
is a list of user IDs. It then loops through the results from that second call and attaches them to the appropriate user objects. Without the id
on the user objects, there's nothing to match against in the second call or when attaching.
EDIT
To select specific columns from an eagerly loaded table, you can use the closure capabilities explained here. So you use the relationship name as the key and a closure that receives a Builder
object as the value, like so:
$user = User::select('id', 'email', 'phone')
->where('id', Auth::user()->id)
->with('customer_details' => function (Builder $query) {
$query->select('id', 'user_id', 'name', 'foo');
})
->first();
Note that you must select the relationship column for both, otherwise Laravel has no idea how to connect the two