Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

StarShines's avatar

Optimizing Code in Middleware

Hello, this is my AuthGates middleware code:

class AuthGates
{
    public function handle($request, Closure $next)
    {
        // Get the currently authenticated user:
        $user = auth()->user();

        // If there is no authenticated user, pass the request to the next middleware.
        if (!$user) {
            return $next($request);
        }

        // Define a cache key for the user's permissions based on their ID.
        $cacheKey = 'user_permissions_' . $user->id;

        // Use the cache to retrieve the user's permissions.
        $permissionsArray = Cache::remember($cacheKey, now()->addMinutes(3), function () use ($user) {
            // Eager load roles with their permissions
            $user = User::with('roles.permissions')->find($user->id);

            // Build an array of permissions grouped by title and roles:
            $permissionsArray = [];

            foreach ($user->roles as $role) {
                foreach ($role->permissions as $permission) {
                    $permissionsArray[$permission->title][] = $role->id;
                }
            }

            return $permissionsArray;
        });

        // For each permission title found in the $permissionsArray, a Gate is defined using Laravel's Gate::define method, 
        // and those gates are used for authorization checks.
        foreach ($permissionsArray as $title => $roles) {
            Gate::define($title, function (User $user) use ($roles) {
                return count(array_intersect($user->roles->pluck('id')->toArray(), $roles)) > 0;
            });
        }

        return $next($request);
    }

}

I am already caching the permissions and no models are being instantiated on subsequent request, however, the gates are being defined and on debugbar, I can see more than 250 gates.

How can I optimize defining gates ?

Many thanks

0 likes
4 replies
netconnect's avatar

You have few techniques, like:

  1. Grouping permissions.

For example, if multiple roles have the same "edit_post" permission, you can define a single gate for "edit_post" and check if the user has any role that grants this permission.

  1. Dynamic gate definitions

Instead of defining gates for all permissions during middleware execution, you can define gates dynamically when they are actually needed. This reduces the number of gates loaded into memory at once.

	class AuthGates
	{
	  		public function handle($request, Closure $next)
			 {
   				 $user = auth()->user();

   						 if ($user) {
        				$permissions = $this->getUserPermissions($user);
        
       					 foreach ($permissions as $permission) {
           				 Gate::define($permission->title, function (User $user) use ($permission) {
                		return $user->hasPermission($permission);
           		 });
       			 }
  		  }

    return $next($request);
}

protected function getUserPermissions(User $user)
{
    $cacheKey = 'user_permissions_' . $user->id;

    return Cache::remember($cacheKey, now()->addMinutes(3), function () use ($user) {
        // Fetch and return the user's permissions here
    });
}

}

StarShines's avatar

@marian-andreiasi

Thank you for your reply. But point 2, dynamic gate definition, i am still trying to understand this

StarShines's avatar

@marian-andreiasi I think this is specific for Spatie package.

What I need to is to reduce the number of gate checks on every request basically.

Please or to participate in this conversation.