Repository: spatie/laravel-permission (php)

Issue:
revokePermissionTo incorrect behaviour with Contracts\Permission[] argument
**Description**
When called with an argument of Permission[] rather than string[] or int[] when revoking multiple permissions, revokePermissionsTo does not revoke any permissions.

givePermissionTo does work correctly with an argument of Permission[] though, so this is a bit confusing.

**Versions**
- spatie/laravel-permission package version: 5.5.0
- laravel/framework package version: 8.79.0

PHP version: 8.1

**To Reproduce**
1. Assign permissions to model with HasPermissions trait
`$u->givePermissionTo([Permission::firstWhere('name', 'view articles'), Permission::firstWhere('name', 'edit articles'), Permission::firstWhere('name', 'delete articles')])`
2. Revoke permissions
`$u->revokePermissionTo([Permission::firstWhere('name', 'edit articles'), Permission::firstWhere('name', 'delete articles')])`
3. Check model's permissions. No permissions will have been revoked.

**Expected Behavior**
The specified permissions are removed from the model.

**Environment:**
 - OS: Linux x86_64
 - Version 5.10.76
 


Pull request:
[V5] Allow revokePermissionTo to accept Permission[]
Another alternative for #2011 (With tests and without breaking changes)
Closes #2010

Patch:
diff --git a/.gitattributes b/.gitattributes
index 5a0aa16..993e0d2 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -14,3 +14,5 @@
 /.editorconfig      export-ignore
 /.php_cs.dist.php   export-ignore
 /.styleci.yml       export-ignore
+/CHANGELOG.md       export-ignore
+/CONTRIBUTING.md    export-ignore
diff --git a/.github/SECURITY.md b/.github/SECURITY.md
deleted file mode 100644
index ca91343..0000000
--- a/.github/SECURITY.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Security Policy
-
-If you discover any security related issues, please email freek@spatie.be instead of using the issue tracker.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e164c37..727ace7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,34 @@
 
 All notable changes to `laravel-permission` will be documented in this file
 
-## 5.5.0 - 2021-01-11
+## 5.5.2 - 2022-03-09
+
+## What's Changed
+
+- [Fixes BIG bug] register blade directives after resolving blade compiler by @tabacitu in https://github.com/spatie/laravel-permission/pull/2048
+
+## New Contributors
+
+- @tabacitu made their first contribution in https://github.com/spatie/laravel-permission/pull/2048
+
+**Full Changelog**: https://github.com/spatie/laravel-permission/compare/5.5.1...5.5.2
+
+## 5.5.1 - 2022-03-03
+
+## What's Changed
+
+- Spelling correction by @gergo85 in https://github.com/spatie/laravel-permission/pull/2024
+- update broken link to laravel exception by @kingzamzon in https://github.com/spatie/laravel-permission/pull/2023
+- Fix Blade Directives incompatibility with renderers by @erikn69 in https://github.com/spatie/laravel-permission/pull/2039
+
+## New Contributors
+
+- @gergo85 made their first contribution in https://github.com/spatie/laravel-permission/pull/2024
+- @kingzamzon made their first contribution in https://github.com/spatie/laravel-permission/pull/2023
+
+**Full Changelog**: https://github.com/spatie/laravel-permission/compare/5.5.0...5.5.1
+
+## 5.5.0 - 2022-01-11
 
 - add support for Laravel 9
 
@@ -302,6 +329,8 @@ The following changes are not "breaking", but worth making the updates to your a
 + $this->app->make(\Spatie\Permission\PermissionRegistrar::class)->forgetCachedPermissions();
 
 
+
+
 ```
 1. Also this is a good time to point out that now with v2.25.0 and v2.26.0 most permission-cache-reset scenarios may no longer be needed in your app, so it's worth reviewing those cases, as you may gain some app speed improvement by removing unnecessary cache resets.
 
@@ -351,6 +380,8 @@ The following changes are not "breaking", but worth making the updates to your a
 @endrole
 
 
+
+
 ```
 ## 2.19.1 - 2018-09-14
 
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index 2ceb084..0000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# Contributing
-
-Contributions are **welcome** and will be fully **credited**.
-
-We accept contributions via Pull Requests on [Github](https://github.com/spatie/laravel-permission).
-
-
-## Pull Requests
-
-- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer).
-
-- **Add tests!** - Your patch won't be accepted if it doesn't have tests.
-
-- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.
-
-- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.
-
-- **Create feature branches** - Don't ask us to pull from your master branch.
-
-- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
-
-- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting.
-
-
-## Running Tests
-
-``` bash
-$ phpunit
-```
-
-
-**Happy coding**!
diff --git a/README.md b/README.md
index 141fb33..d090b8b 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
+
+[<img src="https://github-ads.s3.eu-central-1.amazonaws.com/support-ukraine.svg?t=1" />](https://supportukrainenow.org)
+
 <p align="center"><img src="/art/socialcard.png" alt="Social Card of Laravel Permission"></p>
 
 # Associate users with permissions and roles
@@ -61,11 +64,11 @@ Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recen
 
 ## Contributing
 
-Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
+Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details.
 
 ### Security
 
-If you discover any security-related issues, please email [freek@spatie.be](mailto:freek@spatie.be) instead of using the issue tracker.
+If you discover any security-related issues, please email [security@spatie.be](mailto:security@spatie.be) instead of using the issue tracker.
 
 ## Postcardware
 
diff --git a/database/migrations/add_teams_fields.php.stub b/database/migrations/add_teams_fields.php.stub
index 6df2378..6abdf8d 100644
--- a/database/migrations/add_teams_fields.php.stub
+++ b/database/migrations/add_teams_fields.php.stub
@@ -41,7 +41,7 @@ class AddTeamsFields extends Migration
 
         if (! Schema::hasColumn($tableNames['model_has_permissions'], $columnNames['team_foreign_key'])) {
             Schema::table($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames) {
-                $table->unsignedBigInteger($columnNames['team_foreign_key'])->default('1');;
+                $table->unsignedBigInteger($columnNames['team_foreign_key'])->default('1');
                 $table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
 
                 if (DB::getDriverName() !== 'sqlite') {
diff --git a/docs/advanced-usage/exceptions.md b/docs/advanced-usage/exceptions.md
index b71939a..6134ed5 100644
--- a/docs/advanced-usage/exceptions.md
+++ b/docs/advanced-usage/exceptions.md
@@ -7,7 +7,7 @@ If you need to override exceptions thrown by this package, you can simply use no
 
 An example is shown below for your convenience, but nothing here is specific to this package other than the name of the exception.
 
-You can find all the exceptions added by this package in the code here: https://github.com/spatie/laravel-permission/tree/main/src/Exceptions
+You can find all the exceptions added by this package in the code here: [https://github.com/spatie/laravel-permission/tree/main/src/Exceptions](https://github.com/spatie/laravel-permission/tree/main/src/Exceptions)
 
 
 **app/Exceptions/Handler.php**
diff --git a/src/PermissionServiceProvider.php b/src/PermissionServiceProvider.php
index db7bb6c..61fc132 100644
--- a/src/PermissionServiceProvider.php
+++ b/src/PermissionServiceProvider.php
@@ -40,7 +40,9 @@ class PermissionServiceProvider extends ServiceProvider
             'permission'
         );
 
-        $this->registerBladeExtensions();
+        $this->callAfterResolving('blade.compiler', function (BladeCompiler $bladeCompiler) {
+            $this->registerBladeExtensions($bladeCompiler);
+        });
     }
 
     protected function offerPublishing()
@@ -82,67 +84,65 @@ class PermissionServiceProvider extends ServiceProvider
         $this->app->bind(RoleContract::class, $config['role']);
     }
 
-    protected function registerBladeExtensions()
+    protected function registerBladeExtensions($bladeCompiler)
     {
-        $this->app->afterResolving('blade.compiler', function (BladeCompiler $bladeCompiler) {
-            $bladeCompiler->directive('role', function ($arguments) {
-                list($role, $guard) = explode(',', $arguments.',');
-
-                return "<?php if(auth({$guard})->check() && auth({$guard})->user()->hasRole({$role})): ?>";
-            });
-            $bladeCompiler->directive('elserole', function ($arguments) {
-                list($role, $guard) = explode(',', $arguments.',');
-
-                return "<?php elseif(auth({$guard})->check() && auth({$guard})->user()->hasRole({$role})): ?>";
-            });
-            $bladeCompiler->directive('endrole', function () {
-                return '<?php endif; ?>';
-            });
-
-            $bladeCompiler->directive('hasrole', function ($arguments) {
-                list($role, $guard) = explode(',', $arguments.',');
-
-                return "<?php if(auth({$guard})->check() && auth({$guard})->user()->hasRole({$role})): ?>";
-            });
-            $bladeCompiler->directive('endhasrole', function () {
-                return '<?php endif; ?>';
-            });
-
-            $bladeCompiler->directive('hasanyrole', function ($arguments) {
-                list($roles, $guard) = explode(',', $arguments.',');
-
-                return "<?php if(auth({$guard})->check() && auth({$guard})->user()->hasAnyRole({$roles})): ?>";
-            });
-            $bladeCompiler->directive('endhasanyrole', function () {
-                return '<?php endif; ?>';
-            });
-
-            $bladeCompiler->directive('hasallroles', function ($arguments) {
-                list($roles, $guard) = explode(',', $arguments.',');
-
-                return "<?php if(auth({$guard})->check() && auth({$guard})->user()->hasAllRoles({$roles})): ?>";
-            });
-            $bladeCompiler->directive('endhasallroles', function () {
-                return '<?php endif; ?>';
-            });
-
-            $bladeCompiler->directive('unlessrole', function ($arguments) {
-                list($role, $guard) = explode(',', $arguments.',');
-
-                return "<?php if(!auth({$guard})->check() || ! auth({$guard})->user()->hasRole({$role})): ?>";
-            });
-            $bladeCompiler->directive('endunlessrole', function () {
-                return '<?php endif; ?>';
-            });
-
-            $bladeCompiler->directive('hasexactroles', function ($arguments) {
-                list($roles, $guard) = explode(',', $arguments.',');
-
-                return "<?php if(auth({$guard})->check() && auth({$guard})->user()->hasExactRoles({$roles})): ?>";
-            });
-            $bladeCompiler->directive('endhasexactroles', function () {
-                return '<?php endif; ?>';
-            });
+        $bladeCompiler->directive('role', function ($arguments) {
+            list($role, $guard) = explode(',', $arguments.',');
+
+            return "<?php if(auth({$guard})->check() && auth({$guard})->user()->hasRole({$role})): ?>";
+        });
+        $bladeCompiler->directive('elserole', function ($arguments) {
+            list($role, $guard) = explode(',', $arguments.',');
+
+            return "<?php elseif(auth({$guard})->check() && auth({$guard})->user()->hasRole({$role})): ?>";
+        });
+        $bladeCompiler->directive('endrole', function () {
+            return '<?php endif; ?>';
+        });
+
+        $bladeCompiler->directive('hasrole', function ($arguments) {
+            list($role, $guard) = explode(',', $arguments.',');
+
+            return "<?php if(auth({$guard})->check() && auth({$guard})->user()->hasRole({$role})): ?>";
+        });
+        $bladeCompiler->directive('endhasrole', function () {
+            return '<?php endif; ?>';
+        });
+
+        $bladeCompiler->directive('hasanyrole', function ($arguments) {
+            list($roles, $guard) = explode(',', $arguments.',');
+
+            return "<?php if(auth({$guard})->check() && auth({$guard})->user()->hasAnyRole({$roles})): ?>";
+        });
+        $bladeCompiler->directive('endhasanyrole', function () {
+            return '<?php endif; ?>';
+        });
+
+        $bladeCompiler->directive('hasallroles', function ($arguments) {
+            list($roles, $guard) = explode(',', $arguments.',');
+
+            return "<?php if(auth({$guard})->check() && auth({$guard})->user()->hasAllRoles({$roles})): ?>";
+        });
+        $bladeCompiler->directive('endhasallroles', function () {
+            return '<?php endif; ?>';
+        });
+
+        $bladeCompiler->directive('unlessrole', function ($arguments) {
+            list($role, $guard) = explode(',', $arguments.',');
+
+            return "<?php if(!auth({$guard})->check() || ! auth({$guard})->user()->hasRole({$role})): ?>";
+        });
+        $bladeCompiler->directive('endunlessrole', function () {
+            return '<?php endif; ?>';
+        });
+
+        $bladeCompiler->directive('hasexactroles', function ($arguments) {
+            list($roles, $guard) = explode(',', $arguments.',');
+
+            return "<?php if(auth({$guard})->check() && auth({$guard})->user()->hasExactRoles({$roles})): ?>";
+        });
+        $bladeCompiler->directive('endhasexactroles', function () {
+            return '<?php endif; ?>';
         });
     }
 
diff --git a/src/Traits/HasPermissions.php b/src/Traits/HasPermissions.php
index ecf0741..d116e8a 100644
--- a/src/Traits/HasPermissions.php
+++ b/src/Traits/HasPermissions.php
@@ -384,7 +384,7 @@ trait HasPermissions
     }
 
     /**
-     * Revoke the given permission.
+     * Revoke the given permission(s).
      *
      * @param \Spatie\Permission\Contracts\Permission|\Spatie\Permission\Contracts\Permission[]|string|string[] $permission
      *
@@ -426,6 +426,10 @@ trait HasPermissions
         }
 
         if (is_array($permissions)) {
+            $permissions = array_map(function ($permission) use ($permissionClass) {
+                return is_a($permission, get_class($permissionClass)) ? $permission->name : $permission;
+            }, $permissions);
+
             return $permissionClass
                 ->whereIn('name', $permissions)
                 ->whereIn('guard_name', $this->getGuardNames())


Test patch:
diff --git a/tests/HasPermissionsTest.php b/tests/HasPermissionsTest.php
index df793e4..40151b6 100644
--- a/tests/HasPermissionsTest.php
+++ b/tests/HasPermissionsTest.php
@@ -240,6 +240,34 @@ class HasPermissionsTest extends TestCase
         $this->assertEquals(0, $this->testUserRole->permissions()->count());
     }
 
+    /** @test */
+    public function it_can_give_and_revoke_permissions_models_array()
+    {
+        $models = [app(Permission::class)::where('name', 'edit-articles')->first(), app(Permission::class)::where('name', 'edit-news')->first()];
+
+        $this->testUserRole->givePermissionTo($models);
+
+        $this->assertEquals(2, $this->testUserRole->permissions()->count());
+
+        $this->testUserRole->revokePermissionTo($models);
+
+        $this->assertEquals(0, $this->testUserRole->permissions()->count());
+    }
+
+    /** @test */
+    public function it_can_give_and_revoke_permissions_models_collection()
+    {
+        $models = app(Permission::class)::whereIn('name', ['edit-articles', 'edit-news'])->get();
+
+        $this->testUserRole->givePermissionTo($models);
+
+        $this->assertEquals(2, $this->testUserRole->permissions()->count());
+
+        $this->testUserRole->revokePermissionTo($models);
+
+        $this->assertEquals(0, $this->testUserRole->permissions()->count());
+    }
+
     /** @test */
     public function it_can_determine_that_the_user_does_not_have_a_permission()
     {