Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

isAbleTo function is very slow #645

Open
joh3rd opened this issue Jul 6, 2023 · 2 comments
Open

isAbleTo function is very slow #645

joh3rd opened this issue Jul 6, 2023 · 2 comments

Comments

@joh3rd
Copy link

joh3rd commented Jul 6, 2023

  • Laravel Version: 10.0
  • Laratrust Version: 8.0

Describe the bug
The isAbleTofunction is very slow. I have many users with many teams and many permissions. In one case, a user has more than 8000 rows in the permission_user table. This is because of the user is assigned to many teams with a lot of permissions in every team. I'm checking permissions like that:

$user->isAbleTo(['permission_one', 'permission_two'], $teamId, true);

The DB query itself is super fast. I logged the raw query and tried that. But the isAbleTo function is very slow (more than two seconds in this case).

@websitevirtuoso
Copy link

Please provide repo with 8000 records and we are able to help to debug and improve code

@GregPeden
Copy link
Contributor

GregPeden commented Oct 20, 2023

I happened across this issue while looking for anotherr... I fixed this by re-writing the "isAbleTo" method on User model:

  public function isAbleToOptimized($permissions, $team = null, $excludeGlobalRoles = false, $withDirectPermissions = false)
  {
    $teamId = Helper::getIdFor($team, 'team');
    return $this->roles()->hasByNonDependentSubquery('permissions', function (Builder $q) use ($permissions, $excludeGlobalRoles) {
      if (is_array($permissions)) {
        $q->whereIn('name', $permissions);
      } else {
        $q->where('name', $permissions);
      }
    })->where(function ($q) use ($teamId, $excludeGlobalRoles) {
      $q->where('role_user.team_id', $teamId)
        ->when(!$excludeGlobalRoles && $teamId !== null, function (Builder $q) {
          $q->orWhere('role_user.team_id', null);
        });
    })->exists();
  }

I wrote this to make use of this package: https://github.com/mpyw/eloquent-has-by-non-dependent-subquery

But I think you can do it with built-in Laravel methods now since MySQL has been updated to optimize queries that Laravel generates much better.

This makes better use of the SQL index. I can't remember if I made changes to the indexing on the laratrust tables as well... but the execution time of this is completely fixed and scales with many records.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants