Gate Define not working for other users except whose role_id is 1

1.4k Views Asked by At

The Below code in middleware is working fine when user has role_id 1, When I did the dd on role->permissions I get then the response is array.

But on this middleware line

if (in_array($role->permissions, $permission)) {

I get this error for all other users whose role_id is different

in_array(): Argument #2 ($haystack) must be of type array, string given where array was passed

My Roles Model has

protected $casts = [
        'permissions' => 'array',
    ];

My User Model has

protected function role()
    {
        return $this->hasOne(Roles::class, 'id', 'role_id');
    }

My web Middlewaregroup has

\App\Http\Middleware\RolePermissionCheck::class,

My Meddlware has

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;


class RolePermissionCheck
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (!empty(Auth::user()->role_id)) {
            $role = Auth::user()->role;

            Gate::before(
                function () {
                    if (Auth::user()->role_id === 1) {
                        return true;
                    }
                }
            );
            // dd($role->permissions);
            foreach ($role->permissions as $permission) {
                Gate::define(
                    $permission,
                    function ($role) use ($permission) {
                        if (in_array($role->permissions, $permission)) {
                            return true;
                        }
                    }
                );
            }
        }

        return $next($request);
    }
}
1

There are 1 best solutions below

35
On BEST ANSWER

Do not mark my answer as correct as user Autista_z told you the fix, I am going to share something to have a better code, really simple and "Laravel way" stuff to do.

As user Autista_z said: "the problem will be in foreach loop for Gate defining. In first iteration of loop (based on your sample array) you would have $action = 0 and $roles = 'admin_role_manage'. So the name of gate would be 0. So of course, then @can('admin_role_manage') is false".


So, You are setting up or getting a lot of stuff that is not needed, or worded other way, you can have a clearer code (at least for your Middleware class).

If you know (maybe you don't), you can cast models properties to a type you want, so instead of doing json_decode($user_role->permissions) you can simply do foreach ($user_role->permissions as $role), but before you do so you need to cast it.

So your model would have a property $casts as this:

protected $casts = [
    'permissions' => 'array',
];

This will allow you to do $model->permissions = ['role_1', 'role_2', ...]; without the need of doing $model->permissions = json_encode(['role_1', 'role_2', ...]); (and also this is the Laravel way of handling this).

So your middleware would end like:

namespace App\Http\Middleware;

use App\Models\User;
use App\Models\Roles;
use Closure;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;

class RolePermissionCheck
{
    public function handle($request, Closure $next)
    {
        if ($role = Auth::user()->role)) {
            Gate::before(
                function (User $user) {
                    if ($user->role_id === '1') {
                        return true;
                    }
                }
            );

            foreach ($role->permissions as $permission) {
                Gate::define(
                    $permission,
                    function ($role) use ($permission) {
                        if (in_array($permission, $role->permissions)) {
                            return true;
                        }
                    }
                );
            }
        }

        return $next($request);
    }
}

See that I have changed the wording of $role->permissions as $roles to $role->permissions as $permission, your role could be "Writer" and your permissions are newsletter_manage, brand_logos, quote_manage, and more. So this are not roles but permissions.

Also have in mind that I think you can even have better code for the foreach/define part.