Search code examples
laravellaravel-5eloquentlaravel-5.3laravel-routing

Call to undefined method Illuminate\Database\Query\Builder::hasAnyRole() error on Laravel 5.3


So I'm trying to verify a user's role when accessing the web app upon log in. I have a users table, roles table, and a role_users table

users table --------| user_id | other important fields |

roles table --------| role_id | role_desc |

role_users table ---| role_id | user_id |


User.php model

class User extends Model implements Authenticatable{

    use \Illuminate\Auth\Authenticatable;

    public function roles(){
        return $this->belongsToMany('App\Role', 'role_users', 'user_id', 'role_id');
    }

    public function hasAnyRole($roles){
        if (is_array($roles)) {
            foreach ($roles as $role) {
                if ($this->hasRole($role)) {
                    return true;
                }
            }
        } else {
            if ($this->hasRole($roles)) {
                return true;
            }
        }
        return false;
    }



    public function hasRole($role){
        if ($this->roles()->where('role_desc', $role)->first()) {
            return true;
        }
        return false;
    }
}

Role.php model

class Role extends Model{

    public function users(){
        return $this->belongsToMany('App\User','role_users', 'role_id', 'user_id');
    }
}

Here's my route file

Route::group(['middleware' => 'web'], function () {
    Route::get('/{id}',[
        'uses' => 'MainController@dashboard',
        'as' => 'dashboard',
        'middleware' => 'roles',
        'roles' => ['Superadmin', 'Admin', 'Author', 'Editor']
    ]);
});

I also have this middleware file, CheckRole.php (already defined in the kernel file)

class CheckRole
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->user() === null) {
            return response("Insufficient permissions", 401);
        }

        $actions = $request->route()->getAction();
        $roles = isset($actions['roles']) ? $actions['roles'] : null;

        if ($request->user()->hasAnyRole($roles) || !$roles) {
            return $next($request);
        }
        return response("Insufficient permissions", 401);
    }
}

THE PROBLEM: I'm getting this "Call to undefined method Illuminate\Database\Query\Builder::hasAnyRole()" (which checks if the route is accessible for an array of roles) but as you can see, it is defined in my User.php model.

I've tried commenting all the lines from the hasAnyRole function and just simply echo out a string but the error persists.

Using print_r($roles) in the CheckRole.php file displays the correct array of roles in my route.

I'm guessing it's because of the id parameter in my route. But I really have no idea how to fix that one.

I think the error happens from the CheckRole.php file. Can anybody point out what I've been doing wrong here?


Solution

  • I think the only reason why it could fail is when you use other model for authentication than User model you showed before.

    If in config/auth.php I set model to copy of this model:

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User2::class,
        ],
    ],
    

    that doesn't have hasAnyRole method I've got exact same error:

    Call to undefined method Illuminate\Database\Query\Builder::hasAnyRole()

    So you should make sure that User model you showed above is really used for authentication.