CookieMonster's avatar

laravel - display avatar if user upload it or use default image

I am allowing user to upload an avatar (profile image) in their profile. While uploading avatar is entirely optional, if user does not have avatar, a default image will be used. However, checking whether a user has an avatar uploaded or not in my

show.blade.php:

 @if($user->userInfo->avatar)
                        <img src="{{asset('/images/uploads/avatars/'. $user->userInfo->avatar)}}"  class="img-circle" height="120" width="120" alt="avatar">      
                        @else
                        <img src="{{asset('/images/uploads/avatars/default.jpeg')}}"  class="img-circle" height="120" width="120" alt="avatar">      
                        @endif

It throws the error:

Trying to get property 'avatar' of non-object

I understand my user info is null but why would it throw the error since if it's null then it shall execute the else statement and display the default image..?

0 likes
25 replies
tykus's avatar

One line (using the null coalescing operator)

<img src="{{asset('/images/uploads/avatars/'. ($user->userInfo->avatar ?? 'default.jpeg'))}}" class="img-circle" height="120" width="120" alt="avatar">
1 like
CookieMonster's avatar

Based on the doc, it means it will return the default pic if the "less hand side" is null or otherwise?

automica's avatar

@nickywan123 yup. Both of these are functionally similar but first is more efficient as it only needs to parse first expression once.

$foo = $bar ?? 'something';
$foo = isset($bar) ? $bar : 'something';
tykus's avatar

It will mitigate for $user->userInfo or $user->userInfo->avatar being null

CookieMonster's avatar

Thanks, didn't know I can resolve this using null coalescing operator.

tykus's avatar

Because your code exits when you attempt to get the avatar of null ($user->userInfo). The null coalescing operator mitigates this situation.

Wakanda's avatar

@nickywan123


 @if($user->userInfo->avatar != null)
                        <img src="{{asset('/images/uploads/avatars/'. $user->userInfo->avatar)}}"  class="img-circle" height="120" width="120" alt="avatar">      
                        @else
                        <img src="{{asset('/images/uploads/avatars/default.jpeg')}}"  class="img-circle" height="120" width="120" alt="avatar">      
                        @endif

automica's avatar

@wakanda not a very DRY way of doing that TBH. all you need to do is alter the image src not duplicate the image tag. As @tykus answer best demonstrates.

tykus's avatar

Does not handle the OP's exact situation @wakanda because $user->userInfo is null, not $user->userInfo->avatar

MichalOravec's avatar
Level 75

@nickywan123 Use default model for userInfo

/**
 * Get the author of the post.
 */
public function userInfo()
{
    return $this->hasOne(UserInfo::class)->withDefault([
        'avatar' => 'default.jpeg'
    ]);
}

Docs: https://laravel.com/docs/8.x/eloquent-relationships#default-models

Then in the view

<img src="{{ asset("images/uploads/avatars/{$user->userInfo->avatar}") }}" class="img-circle" height="120" width="120" alt="avatar">

But better will be to rename that relationship to info

public function info()
{
    return $this->hasOne(UserInfo::class)->withDefault([
        'avatar' => 'default.jpeg'
    ]);
}

and you can use it like

$user->info->avatar
2 likes
CookieMonster's avatar

You mean change:

public function userInfo()
{
    return $this->hasOne(UserInfo::class)->withDefault([
        'avatar' => 'default.jpeg'
    ]);
}

to

public function info()
{
    return $this->hasOne(UserInfo::class)->withDefault([
        'avatar' => 'default.jpeg'
    ]);
}

?

Or do you mean to add these two as well?

tykus's avatar

Given userInfo is a relationship on the User model (which wasn't clear from your original post), then this returns a default object from an otherwise null relation:

public function userInfo()
{
    return $this->hasOne(UserInfo::class)->withDefault([
        'avatar' => 'default.jpeg'
    ]);
}
CookieMonster's avatar

Yes I didn't mention.

I have this relationship in my User model

public function userInfo()
{
    return $this->hasOne(UserInfo::class);
}

Will his solution be better?

tykus's avatar

Either one works. If you need a default UserInfo model in other circumstances then the relationship approach is likely preferable. However, sometimes you may want a null result for the relationship which this will prevent. It is really up to each individual use case.

MichalOravec's avatar

@nickywan123 I meant change it to info()

Because I don't like when I have a code like

$user->userInfo->avatar;

The word user is duplicated in this case.

I prefer to have

$user->info->avatar;

But also info is a little bit for me. I would change it to profile, so my model would be UserProfile instead of UserInfo.

automica's avatar

@michaloravec

Because I don't like when I have a code like $user->userInfo->avatar; The word user is duplicated in this case.

I call this ‘stutter’ . If sounds like you are repeating yourself then the method needs to be renamed.

1 like
CookieMonster's avatar

Okay. What if I change my migration for user info instead of the relationship model like :

$table -> string(‘avatar’”)->default(default.jpeg)

Is this the same as your solution ?

sirch's avatar

I believe in php8 you can use the nullsafe operator $user->userInfo?->avata

1 like

Please or to participate in this conversation.