Veljko Stefanovic
Veljko Stefanovic

Reputation: 511

Roles in Laravel aren't working as intended

I've made by the book, roles for my laravel program. Problem occurs in one particular instance, one of methods in User model always "pop-up" ... Whatever user have for role_id, method always shows certain role's name, in this case "moderator". Don't know what is wrong with it, or at least i can't see it ...

Here is User model:

<?php

    namespace App;

    use Illuminate\Notifications\Notifiable;
    use Illuminate\Contracts\Auth\MustVerifyEmail;
    use Illuminate\Foundation\Auth\User as Authenticatable;

    class User extends Authenticatable
    {
        use Notifiable;

        /**
         * The attributes that are mass assignable.
         *
         * @var array
         */
        protected $fillable = [
            'name', 'email', 'password',"avatar"
        ];

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

        /**
         * The attributes that should be cast to native types.
         *
         * @var array
         */
        protected $casts = [
            'email_verified_at' => 'datetime',
        ];

        public function rola(){
            return $this->belongsTo("App\Roles", "id");
        }

        public function posts(){
            return $this->hasMany("App\Post");
        }

        public function comments(){
            return $this->hasMany("App\Comment");
        }

        public function isAdmin()
        {//dd($user);

            return $this->rola()->where('role', 'administrator');
        }

        public function isModerator()
        {//dd($user);

            return $this->rola()->where('role', 'moderator');
        }

        public function isUser()
        {//dd($user);

            return $this->rola()->where('role', 'user');
        }

        public function isPeon()
        {//dd($user);

            return $this->rola()->where('role', 'peon');        
        }

}

Here is Roles model:

<?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Roles extends Model
    {
        public function rola(){
            return $this->hasMany("App\User", "role_id");
        }
    }

And for example if just display in any view:

    {{auth()->user()->rola->id}} <br> // 2 <- correct
    {{auth()->user()->role_id}} // 3 <- this should be 2 also.

Here is a image of my db schema: schema

And image of roles table: roles

By default, whenever new user get registered, it automatically receives role of "peon" which has id 4. Not sure where my mistake lies, maybe i'm not seeing something ...

Edit1:

Here is a link to github repo for those who want to take a gander at it.

Upvotes: 1

Views: 1945

Answers (3)

Mateus Junges
Mateus Junges

Reputation: 2602

To improve your application, don't use one function for each role you have. Supposed you have 100 roles on roles table, with the current code, you will also need 100 functions like isAdmin or isSomething.

Add something like this:

    public function hasRole($roleName)
    {
        return $this->rola()->where('role', $roleName);
    }

    /**
    * Check if the user has any of the given roles.
    */
    public function hasAnyRole(array $roleNames)
    {
        $userRole = $this->rola;
        return in_array($userRole->name, $roleNames);
    }

Now you can check for roles:

    $user->hasRole('admin'); //If the user has the admin role, returns true. Otherwise returns false.

To check for roles on blade view:

@if(Auth::check())
    @if(Auth::user()->hasRole('role-name') || Auth::user()->hasRoles('another-role-name'))
        //Your markup here
    @endif
@endif

And for multiple roles:

@if(Auth::check())
    @if(Auth::user()->hasAnyRoles(['role-name', 'another-role-name']))
        //Your markup here
    @endif
@endif

Hope it helps.

Upvotes: 3

Mateus Junges
Mateus Junges

Reputation: 2602

The problem is in your rola() function. You are using the wrong foreign key with the belongsTo. It should be role_id, not id (which it currently is).

Here is a code snippet with some improvements:

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',"avatar"
    ];
     /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
    * The attributes that should be cast to native types.
    *
    * @var array
    */

    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public function rola(){
        return $this->belongsTo("App\Roles", "role_id");
        //Or just return $this->belongsTo(Roles::class);
    }

    public function posts(){
        return $this->hasMany("App\Post");
    }

    public function comments(){
        return $this->hasMany("App\Comment");
    }

    public function isAdmin()
    {//dd($user);
        return $this->hasRole('admin');
    }

    public function isModerator()
    {//dd($user);
       return $this->hasRole('moderator');
    }

    public function isUser()
    {//dd($user);
        return 
        return $this->hasRole('user');
    }

    public function isPeon()
    {//dd($user);
        return $this->hasRole('peon');
    }

    public function hasRole($role)
    {
        return $this->rola->role === $role;
    }
}

I suggest you to rename your rola function within Roles model to users, since it return all users who has some role.

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;

class Roles extends Model
{
    public function users(){
        return $this->hasMany(User::class, 'role_id');
    }
}

One more thing: take a look at this package. It really helps you to works with users, permissions and permission groups.

Hope it helps.

Upvotes: 0

Alexandre G&#233;rault
Alexandre G&#233;rault

Reputation: 338

Well, I think the problem is in your rola() function in your User.php file: you are defining a foreign key to the belongsTo relationship which here is id.

It should be role_id as this is the key Eloquent would try to map to the id of the Roles' model. See the documentation for more informations

Upvotes: 3

Related Questions