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);
}
}
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.