Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: spatie/laravel-permission
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 6.1.0
Choose a base ref
...
head repository: spatie/laravel-permission
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 6.2.0
Choose a head ref
  • 14 commits
  • 16 files changed
  • 3 contributors

Commits on Nov 9, 2023

  1. Update CHANGELOG

    drbyte authored and github-actions[bot] committed Nov 9, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    6376f7b View commit details
  2. Update CHANGELOG.md

    drbyte authored Nov 9, 2023
    Copy the full SHA
    641bc2f View commit details

Commits on Nov 13, 2023

  1. Copy the full SHA
    c66c0de View commit details

Commits on Nov 19, 2023

  1. Copy the full SHA
    3bf179b View commit details
  2. Middleware limitations

    drbyte authored Nov 19, 2023
    Copy the full SHA
    4011bf8 View commit details
  3. Copy the full SHA
    eb61a65 View commit details
  4. Copy the full SHA
    5e448d0 View commit details
  5. Do you really need a UI?

    drbyte authored Nov 19, 2023
    Copy the full SHA
    978cf24 View commit details

Commits on Dec 3, 2023

  1. Test suite updates

    drbyte committed Dec 3, 2023
    Copy the full SHA
    8ab6bb1 View commit details
  2. Fix styling

    drbyte authored and github-actions[bot] committed Dec 3, 2023
    Copy the full SHA
    373dcb4 View commit details
  3. Clean up comment

    drbyte committed Dec 3, 2023
    Copy the full SHA
    66638c1 View commit details
  4. Copy the full SHA
    b6b9f4f View commit details

Commits on Dec 9, 2023

  1. Copy the full SHA
    c24211a View commit details
  2. Fix styling

    drbyte authored and github-actions[bot] committed Dec 9, 2023
    Copy the full SHA
    299dd2c View commit details
2 changes: 1 addition & 1 deletion .github/workflows/dependabot-auto-merge.yml
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ jobs:

- name: Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v1.6.0
uses: dependabot/fetch-metadata@v1
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
compat-lookup: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ composer.lock
vendor
tests/temp
.idea
.phpunit.cache
.phpunit.result.cache
.php-cs-fixer.cache
tests/CreatePermissionCustomTables.php
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -2,6 +2,17 @@

All notable changes to `laravel-permission` will be documented in this file

## 6.1.0 - 2023-11-09

### What's Changed

- Reset teamId on Octane by @erikn69 in https://github.com/spatie/laravel-permission/pull/2547
NOTE: The `\Spatie\Permission\Listeners\OctaneReloadPermissions` listener introduced in 6.0.0 is removed in 6.1.0, because the logic is directly incorporated into the ServiceProvider now.

Thanks @jameshulse for the heads-up and code-review.

**Full Changelog**: https://github.com/spatie/laravel-permission/compare/6.0.1...6.1.0

## 6.0.1 - 2023-11-06

### What's Changed
@@ -713,6 +724,7 @@ The following changes are not "breaking", but worth making the updates to your a




```
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.

@@ -773,6 +785,7 @@ The following changes are not "breaking", but worth making the updates to your a




```
## 2.19.1 - 2018-09-14

12 changes: 6 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
@@ -23,15 +23,15 @@
"homepage": "https://github.com/spatie/laravel-permission",
"require": {
"php": "^8.0",
"illuminate/auth": "^8.12|^9.0|^10.0",
"illuminate/container": "^8.12|^9.0|^10.0",
"illuminate/contracts": "^8.12|^9.0|^10.0",
"illuminate/database": "^8.12|^9.0|^10.0"
"illuminate/auth": "^8.12|^9.0|^10.0|^11.0",
"illuminate/container": "^8.12|^9.0|^10.0|^11.0",
"illuminate/contracts": "^8.12|^9.0|^10.0|^11.0",
"illuminate/database": "^8.12|^9.0|^10.0|^11.0"
},
"require-dev": {
"laravel/passport": "^11.0",
"orchestra/testbench": "^6.23|^7.0|^8.0",
"phpunit/phpunit": "^9.4"
"orchestra/testbench": "^6.23|^7.0|^8.0|^9.0",
"phpunit/phpunit": "^9.4|^10.1"
},
"minimum-stability": "dev",
"prefer-stable": true,
8 changes: 6 additions & 2 deletions docs/advanced-usage/ui-options.md
Original file line number Diff line number Diff line change
@@ -5,11 +5,15 @@ weight: 11

## Need a UI?

The package doesn't come with any screens out of the box, you should build that yourself. Here are some options to get you started:
The package doesn't come with any UI/screens out of the box, you should build that yourself.

But: [do you really need a UI? Consider what Aaron and Joel have to say in this podcast episode](https://show.nocompromises.io/episodes/should-you-manage-roles-and-permissions-with-a-ui)

If you decide you need a UI, even if it's not for creating/editing role/permission names, but just for controlling which Users have access to which roles/permissions, following are some options to get you started:

- [Code With Tony - video series](https://www.youtube.com/watch?v=lGfV1ddMhHA) to create an admin panel for managing roles and permissions in Laravel 9.

- [FilamentPHP plugin](https://filamentphp.com/plugins/tharinda-rodrigo-spatie-roles-permissions) to manage roles and permissions using this package.
- [FilamentPHP plugin](https://filamentphp.com/plugins/tharinda-rodrigo-spatie-roles-permissions) to manage roles and permissions using this package. (There are a few other Filament plugins which do similarly; use whichever suits your needs best.)

- If you'd like to build your own UI, and understand the underlying logic for Gates and Roles and Users, the [Laravel 6 User Login and Management With Roles](https://www.youtube.com/watch?v=7PpJsho5aak&list=PLxFwlLOncxFLazmEPiB4N0iYc3Dwst6m4) video series by Mark Twigg of Penguin Digital gives thorough coverage to the topic, the theory, and implementation of a basic Roles system, independent of this Permissions Package.

29 changes: 17 additions & 12 deletions docs/basic-usage/wildcard-permissions.md
Original file line number Diff line number Diff line change
@@ -3,11 +3,12 @@ title: Wildcard permissions
weight: 6
---

When enabled, wildcard permissions offers you a flexible representation for a variety of permission schemes. The idea
behind wildcard permissions is inspired by the default permission implementation of
[Apache Shiro](https://shiro.apache.org/permissions.html).
When enabled, wildcard permissions offers you a flexible representation for a variety of permission schemes.

## Enabling Wildcard Feature
The wildcard permissions implementation is inspired by the default permission implementation of
[Apache Shiro](https://shiro.apache.org/permissions.html). See the Shiro documentation for more examples and deeper explanation of the concepts.

## Enabling Wildcard Features

Wildcard permissions can be enabled in the permission config file:

@@ -27,11 +28,11 @@ $permission = 'posts.create.1';
The meaning of each part of the string depends on the application layer.

> You can use as many parts as you like. So you are not limited to the three-tiered structure, even though
this is the common use-case, representing {resource}.{action}.{target}.
this is the common use-case, representing `{resource}.{action}.{target}`.

> NOTE: You must actually create the permissions (eg: `posts.create.1`) before you can assign them or check for them.
> **NOTE: You must actually create the wildcarded permissions** (eg: `posts.create.1`) before you can assign them or check for them.
> NOTE: You must create any wildcard permission patterns (eg: `posts.create.*`) before you can assign them or check for them.
> **NOTE: You must create any wildcard permission patterns** (eg: `posts.create.*`) before you can assign them or check for them.
## Using Wildcards

@@ -47,21 +48,22 @@ Permission::create(['name'=>'posts']);
$user->givePermissionTo('posts');
```

Everyone who is assigned to this permission will be allowed every action on posts. It is not necessary to use a
Given the example above, everyone who is assigned to this permission will be allowed every action on posts. It is not necessary to use a
wildcard on the last part of the string. This is automatically assumed.

```php
// will be true
$user->can('posts.create');
$user->can('posts.edit');
$user->can('posts.delete');
```
```
(Note that the `posts.create` and `posts.edit` and `posts.delete` permissions must also be created.)

## Meaning of the `*` Asterisk
## Meaning of the * Asterisk

The `*` means "ALL". It does **not** mean "ANY".

Thus `can('post.*')` will only pass if the user has been assigned `post.*` explicitly.
Thus `can('post.*')` will only pass if the user has been assigned `post.*` explicitly, and the `post.*` Permission has been created.


## Subparts
@@ -71,13 +73,16 @@ powerful feature that lets you create complex permission schemes.

```php
// user can only do the actions create, update and view on both resources posts and users
Permission::create(['name'=>'posts,users.create,update,view']);
$user->givePermissionTo('posts,users.create,update,view');

// user can do the actions create, update, view on any available resource
Permission::create(['name'=>'*.create,update,view']);
$user->givePermissionTo('*.create,update,view');

// user can do any action on posts with ids 1, 4 and 6
Permission::create(['name'=>'posts.*.1,4,6']);
$user->givePermissionTo('posts.*.1,4,6');
```

> As said before, the meaning of each part is determined by the application layer! So, you are free to use each part as you like. And you can use as many parts and subparts as you want.
> Remember: the meaning of each 'part' is determined by your application! So, you are free to use each part as you like. And you can use as many parts and subparts as you want.
12 changes: 7 additions & 5 deletions docs/installation-lumen.md
Original file line number Diff line number Diff line change
@@ -31,17 +31,19 @@ You will also need the `config/auth.php` file. If you don't already have it, cop
cp vendor/laravel/lumen-framework/config/auth.php config/auth.php
```

Then, in `bootstrap/app.php`, uncomment the `auth` middleware, and register this package's middleware:
Next, if you wish to use this package's middleware, clone whichever ones you want from `Spatie\Permission\Middleware` namespace into your own `App\Http\Middleware` namespace AND replace the `canAny()` call with `hasAnyPermission()` (because Lumen doesn't support `canAny()`).

Then, in `bootstrap/app.php`, uncomment the `auth` middleware, and register the middleware you've created. For example:

```php
$app->routeMiddleware([
'auth' => App\Http\Middleware\Authenticate::class,
'permission' => Spatie\Permission\Middleware\PermissionMiddleware::class,
'role' => Spatie\Permission\Middleware\RoleMiddleware::class,
'permission' => App\Http\Middleware\PermissionMiddleware::class, // cloned from Spatie\Permission\Middleware
'role' => App\Http\Middleware\RoleMiddleware::class, // cloned from Spatie\Permission\Middleware
]);
```

... and in the same file, in the ServiceProviders section, register the package configuration, service provider, and cache alias:
... and also in `bootstrap/app.php`, in the ServiceProviders section, register the package configuration, service provider, and cache alias:

```php
$app->configure('permission');
@@ -66,7 +68,7 @@ php artisan migrate

---
## User Model
NOTE: Remember that Laravel's authorization layer requires that your `User` model implement the `Illuminate\Contracts\Auth\Access\Authorizable` contract. In Lumen you will then also need to use the `Laravel\Lumen\Auth\Authorizable` trait.
NOTE: Remember that Laravel's authorization layer requires that your `User` model implement the `Illuminate\Contracts\Auth\Access\Authorizable` contract. In Lumen you will then also need to use the `Laravel\Lumen\Auth\Authorizable` trait. Note that Lumen does not support the `User::canAny()` authorization method.

---
## User Table
15 changes: 10 additions & 5 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false" backupStaticAttributes="false" colors="true" verbose="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="vendor/autoload.php"
colors="true"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.4/phpunit.xsd"
>
<source>
<include>
<directory suffix=".php">src/</directory>
</include>
</coverage>
</source>
<testsuites>
<testsuite name="Permissions Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<php>
<env name="CACHE_DRIVER" value="array"/>
<env name="APP_KEY" value="base64:W99w+5JYz8SVGf5sx17gmPR6uoNCtWiEVc+9qu8iGEg="/> <!-- Required for Passport client -->
<ini name="memory_limit" value="512M" />
<!-- APP_KEY required for Passport client -->
<env name="APP_KEY" value="base64:W99w+5JYz8SVGf5sx17gmPR6uoNCtWiEVc+9qu8iGEg="/>
<ini name="memory_limit" value="512M"/>
</php>
</phpunit>
6 changes: 3 additions & 3 deletions src/Models/Permission.php
Original file line number Diff line number Diff line change
@@ -86,7 +86,7 @@ public function users(): BelongsToMany
*
* @throws PermissionDoesNotExist
*/
public static function findByName(string $name, string $guardName = null): PermissionContract
public static function findByName(string $name, ?string $guardName = null): PermissionContract
{
$guardName = $guardName ?? Guard::getDefaultName(static::class);
$permission = static::getPermission(['name' => $name, 'guard_name' => $guardName]);
@@ -104,7 +104,7 @@ public static function findByName(string $name, string $guardName = null): Permi
*
* @throws PermissionDoesNotExist
*/
public static function findById(int|string $id, string $guardName = null): PermissionContract
public static function findById(int|string $id, ?string $guardName = null): PermissionContract
{
$guardName = $guardName ?? Guard::getDefaultName(static::class);
$permission = static::getPermission([(new static())->getKeyName() => $id, 'guard_name' => $guardName]);
@@ -121,7 +121,7 @@ public static function findById(int|string $id, string $guardName = null): Permi
*
* @return PermissionContract|Permission
*/
public static function findOrCreate(string $name, string $guardName = null): PermissionContract
public static function findOrCreate(string $name, ?string $guardName = null): PermissionContract
{
$guardName = $guardName ?? Guard::getDefaultName(static::class);
$permission = static::getPermission(['name' => $name, 'guard_name' => $guardName]);
8 changes: 4 additions & 4 deletions src/Models/Role.php
Original file line number Diff line number Diff line change
@@ -95,7 +95,7 @@ public function users(): BelongsToMany
*
* @throws RoleDoesNotExist
*/
public static function findByName(string $name, string $guardName = null): RoleContract
public static function findByName(string $name, ?string $guardName = null): RoleContract
{
$guardName = $guardName ?? Guard::getDefaultName(static::class);

@@ -113,7 +113,7 @@ public static function findByName(string $name, string $guardName = null): RoleC
*
* @return RoleContract|Role
*/
public static function findById(int|string $id, string $guardName = null): RoleContract
public static function findById(int|string $id, ?string $guardName = null): RoleContract
{
$guardName = $guardName ?? Guard::getDefaultName(static::class);

@@ -131,7 +131,7 @@ public static function findById(int|string $id, string $guardName = null): RoleC
*
* @return RoleContract|Role
*/
public static function findOrCreate(string $name, string $guardName = null): RoleContract
public static function findOrCreate(string $name, ?string $guardName = null): RoleContract
{
$guardName = $guardName ?? Guard::getDefaultName(static::class);

@@ -176,7 +176,7 @@ protected static function findByParam(array $params = []): ?RoleContract
*
* @throws PermissionDoesNotExist|GuardDoesNotMatch
*/
public function hasPermissionTo($permission, string $guardName = null): bool
public function hasPermissionTo($permission, ?string $guardName = null): bool
{
if ($this->getWildcardClass()) {
return $this->hasWildcardPermission($permission, $guardName);
4 changes: 2 additions & 2 deletions src/PermissionRegistrar.php
Original file line number Diff line number Diff line change
@@ -145,7 +145,7 @@ public function forgetCachedPermissions()
return $this->cache->forget($this->cacheKey);
}

public function forgetWildcardPermissionIndex(Model $record = null): void
public function forgetWildcardPermissionIndex(?Model $record = null): void
{
if ($record) {
unset($this->wildcardPermissionsIndex[get_class($record)][$record->getKey()]);
@@ -187,7 +187,7 @@ public function clearClassPermissions()

/**
* Load permissions from cache
* This get cache and turns array into \Illuminate\Database\Eloquent\Collection
* And turns permissions array into a \Illuminate\Database\Eloquent\Collection
*/
private function loadPermissions(): void
{
7 changes: 4 additions & 3 deletions src/Traits/HasPermissions.php
Original file line number Diff line number Diff line change
@@ -370,9 +370,10 @@ private function collectPermissions(...$permissions): array
return $array;
}

$this->ensureModelSharesGuard($permission);

$array[] = $permission->getKey();
if (! in_array($permission->getKey(), $array)) {
$this->ensureModelSharesGuard($permission);
$array[] = $permission->getKey();
}

return $array;
}, []);
13 changes: 7 additions & 6 deletions src/Traits/HasRoles.php
Original file line number Diff line number Diff line change
@@ -129,9 +129,10 @@ private function collectRoles(...$roles): array
return $array;
}

$this->ensureModelSharesGuard($role);

$array[] = $role->getKey();
if (! in_array($role->getKey(), $array)) {
$this->ensureModelSharesGuard($role);
$array[] = $role->getKey();
}

return $array;
}, []);
@@ -217,7 +218,7 @@ public function syncRoles(...$roles)
*
* @param string|int|array|Role|Collection|\BackedEnum $roles
*/
public function hasRole($roles, string $guard = null): bool
public function hasRole($roles, ?string $guard = null): bool
{
$this->loadMissing('roles');

@@ -281,7 +282,7 @@ public function hasAnyRole(...$roles): bool
*
* @param string|array|Role|Collection|\BackedEnum $roles
*/
public function hasAllRoles($roles, string $guard = null): bool
public function hasAllRoles($roles, ?string $guard = null): bool
{
$this->loadMissing('roles');

@@ -323,7 +324,7 @@ public function hasAllRoles($roles, string $guard = null): bool
*
* @param string|array|Role|Collection $roles
*/
public function hasExactRoles($roles, string $guard = null): bool
public function hasExactRoles($roles, ?string $guard = null): bool
{
$this->loadMissing('roles');

10 changes: 10 additions & 0 deletions tests/HasPermissionsTest.php
Original file line number Diff line number Diff line change
@@ -541,6 +541,16 @@ public function it_can_sync_multiple_permissions()
$this->assertFalse($this->testUser->hasDirectPermission('edit-news'));
}

/** @test */
public function it_can_avoid_sync_duplicated_permissions()
{
$this->testUser->syncPermissions('edit-articles', 'edit-blog', 'edit-blog');

$this->assertTrue($this->testUser->hasDirectPermission('edit-articles'));

$this->assertTrue($this->testUser->hasDirectPermission('edit-blog'));
}

/** @test */
public function it_can_sync_multiple_permissions_by_id()
{
10 changes: 10 additions & 0 deletions tests/HasRolesTest.php
Original file line number Diff line number Diff line change
@@ -259,6 +259,16 @@ public function it_can_sync_roles_from_a_string_on_a_permission()
$this->assertTrue($this->testUserPermission->hasRole('testRole2'));
}

/** @test */
public function it_can_avoid_sync_duplicated_roles()
{
$this->testUser->syncRoles('testRole', 'testRole', 'testRole2');

$this->assertTrue($this->testUser->hasRole('testRole'));

$this->assertTrue($this->testUser->hasRole('testRole2'));
}

/** @test */
public function it_can_sync_multiple_roles()
{
Loading