laravel-permission: slow hasPermissionTo

Hi,

I have the following context: 142 permissions attached to 27 roles, 2000 users - vast majority with one or more roles, only few with direct permissions, and a blade template that use @can for 101 times in order to generate a menu according to current user’s permissions.

rendering this menu is very time consuming (~4 seconds) and I discovered that problem is with hasPermissionTo.

in order to not touch laravel-permissions files the solution was to overwrite the method in the my model and to do some cache:

public function hasPermissionTo($permission, $guardName = null): bool
    {
        if (is_string($permission)) {
            $permission = \Cache::remember('spatie.permissions.'.$permission.'.'.$guardName, 3600, function()use($permission, $guardName){
                return app(Permission::class)->findByName(
                    $permission,
                    $guardName ?? $this->getDefaultGuardName()
                );
            });
        }
        return $this->hasDirectPermission($permission) || $this->hasPermissionViaRole($permission);
    }

what I achieved with this cache is to render that menu in 0.03 seconds.

I write you in hope you’ll find a way to optimize this method inside this awesome laravel module 😃

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 15 (5 by maintainers)

Most upvoted comments

@andrubeldie is this what you envisioned, converting where to filter ?

    public static function findByName(string $name, $guardName = null): PermissionContract
    {
        $guardName = $guardName ?? config('auth.defaults.guard');

-        $permission = static::getPermissions()->where('name', $name)->where('guard_name', $guardName)->first();
+        $permission = static::getPermissions()
+            ->filter(function ($value, $key) use ($name, $guardName) {
+                if (! is_null($guardName)) {
+                    return $value['name'] === $name && $value['guard_name'] === $guardName;
+                }
+
+                return $value['name'] === $name;
+            })->first();

        if (! $permission) {
            throw PermissionDoesNotExist::create($name, $guardName);
        }

        return $permission;
    }

Hello @AlexVanderbist,

Is this issue fixed in the latest version? Our use case is the same as @andrubeldie and we have an overhead of 200% 😕

Thank you!

Hey, sorry for not checking in on this issue earlier. Feel free to PR a fix and add me as a reviewer and we’ll take a look 👍