No, that's supposed to work that way. You are explicitly querying for a role in the second snippet, which completely bypasses your default definition.
withDefault doesn't work with relation()->first()
I find it weird that when using withDefault() on a belongsTo relationship, I will receive the default model only when using a dynamic property. For example...
class User {
//...
public function role(): BelongsTo
{
return $this->belongsTo(Role::class)->withDefault(['name' => 'admin']);
}
}
$user = new User(); // having no role
$methodRole = $user->role()->first()->name; // ErrorException: Attempt to read property "name" on null
$propertyRole = $user->role->name // 'admin'
Is this supposed to be this way? Isn't this a bug?
Now I get it. Writing $user->role is the equivalent of writing $user->role()->getResults(), not $user->role()->first().
The getResults for BelongsTo class is this:
public function getResults()
{
if (is_null($this->child->{$this->foreignKey})) {
return $this->getDefaultFor($this->parent);
}
return $this->query->first() ?: $this->getDefaultFor($this->parent);
}
You don't have any getDefaultFor in BelongsToMany relationship, for instance.
So withDefault only works with dynamic properties. Maybe we should add a note on documentation to make it clear? https://laravel.com/docs/8.x/eloquent-relationships#default-models
Please or to participate in this conversation.