Reputation: 1140
I'd appreciate some help understanding the discrepancy I'm seeing with the following in my laravel 6.8 project:
I have a "UserAlert" model
class UserAlert extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'user_id', 'from_id', 'subject', 'message'
];
//Relationships
public function user()
{
return $this->belongsTo(User::class);
}
//Only include the name of the sender in this relationship
public function from()
{
return $this->hasOne(User::class, 'id', 'from_id')->select('name');
}
}
The "user" relationship is the default 'user_id' to 'id' and is working as expected.
As you can see, the "from" relationship pulls the name from the User model associated with the 'from_id' of the UserAlert.
If I obtain a collection of UserAlerts and then iterate over it to get the 'from' relationship for each as follows:
$thisUserAlerts = \App\UserAlert::where('user_id', $thisUser->id)->get();
foreach ($thisUserAlerts as $userAlert) {
dump($userAlert->from);
}
Then I do see the name from the 'from' relationship as I desire:
...
#original: array:1 [
"name" => "Administrator"
]
...
However if I try to include the relationship directly in the UserAlert collection using 'with' then 'from' is always null.
$thisUserAlertsWith = \App\UserAlert::where('user_id', $thisUser->id)->with('from')->get();
dump($thisUserAlertsWith);
...
#relations: array:1 [
"from" => null
]
...
I can see from the query log that when I do the above there is no sql query to pull the name from the users table, but when I iterate over the collection and call '->from' directly then the query is made.
Have I misunderstood 'with'?
[edited to remove discrepancy in the examples for clarity]
Upvotes: 0
Views: 1543
Reputation: 1140
With thanks to Danial Petrovaliev for pointing me in the right direction I have found two answers to my problem.
For the relationship to be included then it turns out you must include the primary key (id) in the collection.
So the first answer is to modify the relationship from
return $this->hasOne(User::class, 'id', 'from_id')->select('name');
to
return $this->hasOne(User::class, 'id', 'from_id')->select(['id', 'name']);
My original example then works as I intended.
Researching this also led me to another option which was not to limit the fields in the relationship itself but instead to limit them in the "with" call.
So remove the select completely from the relationship:
return $this->hasOne(User::class, 'id', 'from_id')
and instead filter on the collection with the following:
$userAlerts = UserAlert::where('user_id', $id)->with('from:id,name')->get();
Again you must include the primary key (id) for it to work.
Upvotes: 1