I recently looked at the performance of projects created on TOP of SWIS. Surprisingly, one of the most performance-draining approaches is the result of the excellent Spatie/laravel-Permission package.

After looking at more data and research, we found a performance problem that could be significantly improved. Now that the solution is clearly stated, it’s easy to write code to improve and submit requests.

Now that the solution has been consolidated and released, here’s an analysis of the performance problem and how to avoid it in your own projects.

TL; DR: Jump to the conclusion.

Performance bottleneck

If we look at spatie/ laravel-Permission abstractly it does two main things:

  1. Keep a list of permissions that belong to a model.
  2. Check whether a model has permissions.

The first point is that performance bottlenecks are a bit of a stretch. The permission data is stored in the database and will be read when needed. This process is a bit slow but it’s only done once. The results are cached and can be used by subsequent requests.

The second point is really a bottleneck from the performance bottleneck point of view. The bottleneck depends on the nature of the permissions and the size of the project, because permissions are checked frequently. Any slowness in this review process can become a performance bottleneck for the entire project.

Filter set class

The method of filtering permission sets was cited as the cause of the low performance. It does the following:

$permission = $permissions
    ->where('id', $id)
    ->where('guard_name', $guardName)
    ->first();
Copy the code

Revised:

$permission = $permissions
    ->filter(function ($permission) use ($id, $guardName) {
        return $permission->id === $id && $permission->guard_name === $guardName;
    })
    ->first();
Copy the code

These two snippets accomplish the same thing, but the second is faster.

The performance test

The app I’m working on has about 150 different permissions. In a typical request, there are about 50 permissions that need to be checked using the hasPermissionTo method. Of course, some pages may need to check about 200 permissions.

Here are some Settings to use for performance testing.

$users = factory(User::class, 150)->make(); $searchForTheseUsers = $users->shuffle()->take(50); $result = $users->where('id', '=', $user->id)->first(); } # 2: Filtering, Foreach ($searchForTheseUsers as $searchUser) {$result = $users->filter(function($user) use ($searchUser) { return $user->id === $searchUser->id; })->first(); Foreach ($searchForTheseUsers as $user) {$searchId = $user->id; $result = $users->filter(function($user) use ($searchId) { return $user->id === $searchId; })->first(); }Copy the code

All three methods are used to test and filter 1 attribute, 2 attribute, 3 attribute, so using method 1 to filter three attributes looks like this:

foreach($searchForTheseUsers as $user) {
    $result = $users
        ->where('id', '=', $user->id)
        ->where('firstname', '=', $user->firstname)
        ->where('lastname', '=', $user->lastname)->first();
}
Copy the code

The results of

| | method # 1 # 3 # 2 | | method method | | — – | — – | — – | — – | | | | 0.190 0.139 1 attribute (27%), 0.072 (62%) | | | | | 0.499 two attributes 0.372 0.196 (61%) (25%) | | | | | 0.488 three attributes (+ 25%) 0.603 0.198 (59%) | |

conclusion

We can conclude that repeatedly filtering a large collection can cause serious performance bottlenecks for a project.

Multi-attribute filtering significantly increases the computational cost.

Using Collection:: Filter () instead of Collection:: Where () improves performance by 60%.

Warning: Passing complete models to filter callbacks is performance-costly; it is better to pass individual properties.

Thank you

Thanks to Spatie and the contributors at Spatie/Laravel-Permissions for creating such an excellent package that I enjoyed using! Thanks to Andru Beldie for pointing out these performance issues, I had the opportunity to investigate and correct them.

link

  • spatie/laravel-permission package.
  • Issue #550 addressing performance problem.
  • Pull request #710 that fixes problems.

For more on modern PHP, go to
Laravel/PHP knowledge community