3

In all of my views I am already able to access {{Auth::user()->name}} by default, I am trying to add the ability to access {{Profile::user()->...}} in my views as well but I am having some trouble. I don't really want to use view composers if I dont have to as this post suggests because it looks like I will need to list each view manually. Instead I opted in to use the AppServiceProvider boot method listed in the docs. The problem is I am still not able to call {{ Profile::user()->title }} for example. I am getting the following error:

ErrorException in AppServiceProvider.php line 19:
Non-static method App\Profile::user() should not be called statically, assuming $this from incompatible context

Here is my AppServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use View;
use App\Profile;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
        View::share('user', Profile::user());
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Here is my model Profile.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Profile extends Model
{
    //
    protected $fillable = [
        'bio',
        'linkedin_url',
        'facebook_url',
        'twitter_username',
        'title',
        'profile_image',
        'user_id',
    ];
    public function user()
    {
        return $this->belongsTo('user');
    }
}

What am I doing wrong? How can I have access to users profile data in all views? Can I see an example?

Community
  • 1
  • 1
Derek
  • 4,747
  • 7
  • 44
  • 79

4 Answers4

2

Both @Saumya and @martindilling are correct; you're binding to the $user variable in the service provider you're using. You just need to make your user() method static to access it the way you want:

public static function user(){
    if (auth()->user()) return auth()->user()->profile;
}

If you use that, then you don't need the View binding if you don't want it. You can just use {{ Profile::user() }} in any Blade template. But this is also kind of silly, because now you've overwritten your relationship method name.

If you really want super-easy access to the current user's profile, why not make a helper method you could access from anywhere? currentUserProfile() or something? I don't mind keeping a file with some shortcut methods for each project, but you have to have good discipline when adding things to it otherwise your code will quickly become unreadable.

I find the second answer here to be a pretty clear way to add your own custom helper methods.

Carter Fort
  • 953
  • 7
  • 14
  • Also a good answer,I had everything else working with the relationship, I just did not know it was as simple as calling `auth()->user()->profile` in my view (not realizing it was attached to user and thinking I needed a composer view, helper function or service provider to accomplish this) but I learned from your answer as well so thank you – Derek Dec 21 '16 at 21:07
1

According to your code, you are calling a non-static method statically. You shouldn't be doing that. Instead you should use a profile, for which you want a particular user like this:

View::share('user', Profile::find(1)->user);

You can also get all the users with profile like this & your models should look like this:

class User extends Model {

    public function profile() {
        return $this->hasOne(Profile::class);
    }

}

class Profile extends Model {

    public function user() {
        return $this->belongsTo(User::class);
    }

}

View::share('user', User::with('profile')->get()); // <----- Get all users with profile

Or if you want to get the profile of the authenticated user, you can do it like this:

View::share('user', auth()->user); // <---- Gets the authenticated User
View::share('user_profile', auth()->user()->profile); // <---- Gets the authenticated User's profile

Hope this helps!

Saumya Rastogi
  • 13,159
  • 5
  • 42
  • 45
  • When I try using `View::share('user_profile', auth()->user->profile);` in the boot method I get the following error: `Undefined property: Illuminate\Auth\AuthManager::$user` – Derek Dec 21 '16 at 17:21
  • Thank you, now I get the following error: `Trying to get property of non-object` I assume it is the `profile` part of `View::share('user_profile', auth()->user()->profile);` I made sure my profile model has user method and user model has profile method like your example above. – Derek Dec 21 '16 at 17:44
  • According to my code everything is fine, make sure that your `profile` table has the column `user_id` and the relationships are properly used & defined! – Saumya Rastogi Dec 21 '16 at 17:49
1

When you use View::share('user', Profile::user()); your profile user would be available in the view as {{ $user }} :)

And yes the error message you get is because of the reason Saumya Rastogi has written, that you need to get the user for a specific profile :)

martindilling
  • 2,839
  • 3
  • 16
  • 13
1

You don't need to share this variable at all since you only want to get profile of user (you always have user data loaded) and it's one-to-one relation. Just add proper relation:

public function profile()
{
    return $this->hasOne('\App\Profile');
}

And then use it anywhere in the app:

auth()->user()->profile->city

If you'll share the variable, you'll add second query to all views and in the real app you absolutely don't want to do that.

Alexey Mezenin
  • 158,981
  • 26
  • 290
  • 279