Conditional menu items based on User Role

Published 2 weeks ago by cmtiffani

I'm getting stuck on something that should be simple.

Using 5.3. I have middleware setup to check if a user is an Admin based on their roles (isAdmin) and I have a function setup for User::hasRole() that can both check if a user has a given role.

I have some conditional menu items that should only appear for admins. how can I check for a role?

gofish543

I personally have a blade file called authed.nav.blade.php and inside of it I have a section that generates certain lists based off of the role of the user

<ul class="nav navbar-nav">
    <?php $role = Auth::user()->role_id; ?>
    @if($role == 1)
        <li>Insert Lists Here</li>
    @else if($role == 2)
        <li>Insert Lists Here</li>
    @else if($role == 3)
        <li>Insert Lists Here</li>
    @endif 
</ul>

Middlewares are used for verifying requests sent to your application, but not for page specific items.

Another idea is adding functions to your User model like checkAdmin(), checkEmployee(), checkUser() where it compares the current role against the specific function role and returns true or false.

cmtiffani

I have a few questions about this:

I can't use Auth::user()->role_id as it's a many-to-many relationship, so that column isn't in the user's table. I have a function in my User model for isAdmin() but I'm not sure how to reference this within blade?

I get the error Class 'User' not found with this:

  {{ User::isAdmin() }}
gofish543

In the blade file access it like this

Auth::user()->isAdmin()

Auth::user() returns the current logged in user MODEL meaning you can access any functions within your User model.

cmtiffani

Still gives me an error:

 Call to undefined method Illuminate\Auth\GenericUser::isAdmin()
gofish543

Based off the error message it does not look like you have a User model created. Or Auth::user() is null.

Can you paste your User model here please.

cmtiffani
<?php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Role;

class User extends Authenticatable
{
    // use SoftDeletes;
    protected $table = 'users';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'first_name', 'last_name', 'company', 'email', 'tax_id', 'address', 'city', 'state', 'zip', 'phone','password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    public function roles()
    {
        return $this->belongsToMany('App\Role');
    }
    /**
     * Find specified user role by id or name
     * @param  [type]  $uid  user_id
     * @param  [type]  $role either name or id
     * @return boolean       [description]
     */
    static function hasRole($uid, $role){
        $user = User::find($uid);

        if(is_numeric($role)){
            foreach ($user->roles as $r) {
                // var_dump($r->id);
                if($r->id == $role){
                    return true;
                }
                return false;
            }
        }else{
            foreach ($user->roles as $r) {
                if($r->name == $role){
                    return true;
                }
                return false;
            }

        }
    }

    static function isAdmin(){
        $user = User::find(Auth::user()->id);

            foreach ($user->roles as $r) {
                if($r->id == 1){
                    return true;
                }
                return false;
            }
    }

}
gofish543

Problem is when you use Auth::user()->isAdmin() you are using an object to call a static method.

public function isAdmin(){
       foreach ($this->roles as $role) {
                if($role->id == 1){
                    return true;
                }
                return false;
            }
    }
}

Then if(Auth::user()->isAdmin()) will return an User object and call its isAdmin function and based off of the result will enter the if statement.

cmtiffani

hmm, tried that and I still get the same error.

gofish543

Auth.php

'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],
        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

This could be a problem as well.

You must un-comment driver and model under users as shown above, otherwise Laravel won't be able to know what Model YOU want to use as the front door.

cmtiffani

They were already uncommented.

My authentication works fine, it's just accessing it through Auth::user()->isAdmin() that doesn't work.

Auth::user() returns the full user model as I'd expect, and User::isAdmin() checks the role status as expected as well.

Any other ideas?

gofish543

Static references could be another idea If Auth::user() works, great that returns a user object. If User::isAdmin() works, you are accessing the method statically.

The isAdmin function needs to have 'public function isAdmin' as the method header.

Other than that I am out of ideas.

cmtiffani

You already suggested changing the function to public, so that's not it.

mvksastry

I am not an expert but I have done this using Middleware. I have created 5 roles. My coding skills/knowledge are below novice level but i could complete the package.

This is created with the structure as follows: An institution has an admin, it has many investigators and every investigator has many people working for him. So each role has a distinct menu and permissions etc.

class PermissionsRequiredMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */

public function handle($request, Closure $next)
{

    $user = $request->user();

    $login_id = $user['id'];

    //echo $login_id; echo "</br>";

    $institutional_id = $user['institutional_id']

    // Check if a user is logged in.
    if (!$user = $request->user())
    {
        return $next($request);
    }

    // Get the current route.
    $route = $request->route();

    // Get the current route actions.
    $actions = $route->getAction();
    
    // Check if we have any permissions to check the user has.

        foreach($actions['permissions'] as $value )
        {
            $permission_name = $value;
        }

        if (!$permissions = isset($actions['permissions']) ? $actions['permissions'] : null)
        {
            // No permissions to check, allow access.
            return $next($request);
        }

        //Fetch all of the matching user permissions.
        $userPermissions = array_pluck($user->Permissions()->whereIn('slug', (array) $permissions)->get()->toArray(), 'slug');

        $login_id = $user->where('institutional_id', '=', $institutional_id)->get();

        $inst_users = $user->where('institutional_id', '=', $institutional_id)->get();
    
        foreach($userPermissions as $value )
        {
            $userPermissionName = $value;
        
        }
                         
        $dashInfos = [];
            
        if ( $userPermissionName === 'superadmin' )
        {
            $dashInfo = $this->getAdminDashboardInfo($request);
        }
            
        if ( $userPermissionName === 'investigator' )
        {
            $dashInfo = $this->InvestigatorDashboardInfo($request, $login_id);
            // print_r(array_values($dashInfo));
        }
            
        ....
    ....
        
        //////////// role related code is inserted above only

        array_push($dashInfos, $dashInfo, $userPermissionName );
            
        $request->merge(array("myVar" => $userPermissionName));
            
        $request->merge(array("infos" => $dashInfo));

        return $next($request);

}

this goes back to home controller where the home page is constructed based on the dashinfo retrieved and menu files are chosen to display etc.

May this looks very crude but it is working

Krishna

cmtiffani

I have middleware setup, but I'm not returning the extra info that you are at in the myVar and infos arrays. That may be how I work around this.

Thanks. Will give it a try and see how it goes :)

cmtiffani

Finally got around to this. It worked, sort of.

Doing this still means I have to pass the roles feedback from the request into the view independently in order to access it in my blade file, which seems clunky and means repeating this code everywhere. There has to be a better way to do this....

Sign In or create a forum account to participate in this discussion.