Issue
I have the following models in my application:
User.php
<?php namespace App\Models;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Kodeine\Acl\Traits\HasRole;
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
use Authenticatable, CanResetPassword, HasRole;
/**
* The database table used by the model.
*
* @var stringSS
*/
protected $table = 'users';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name', 'email', 'password', 'is_active'];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = ['password', 'remember_token'];
public function customer_details()
{
return $this->hasOne('App\Models\CustomerDetails', 'user_id');
}
}
CustomerDetails.php
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class CustomerDetails extends Model {
protected $table = 'customer_details';
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
protected $appends = ['full_name'];
public function getFullNameAttribute()
{
return $this->attributes['first_name'] .' '. $this->attributes['last_name'];
}
public function user()
{
return $this->belongsTo('App\Models\User', 'user_id');
}
public function invoices() {
return $this->hasMany('App\Models\Invoices', 'customer_id');
}
}
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. This function will be used on one page alone meaning there are other pages that may require all details but not this one so I want to create a separate Eloquent relation to do this.
Solution
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
Answered By - Josh
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.