Caraes_Naur's avatar

Spatie Permissions, Teams with Super-Admin

I think I've managed to get these features to get along, just looking for a sanity check.

Environment: Laravel 12, MySQL 8, Spatie Permissions 6.24.1

Enable Teams in config/permission.php. Set default_team_id = null

In the migration, make team_id nullable and omit from indexes:

@@ -48,7 +48,8 @@ return new class extends Migration
             $table->string('guard_name'); // For MyISAM use string('guard_name', 25);
             $table->timestamps();
             if ($teams || config('permission.testing')) {
-                $table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
+                //$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
+                $table->unique(['name', 'guard_name']);
             } else {
                 $table->unique(['name', 'guard_name']);
             }
@@ -68,10 +69,12 @@ return new class extends Migration
                 ->on($tableNames['permissions'])
                 ->onDelete('cascade');
             if ($teams) {
-                $table->unsignedBigInteger($columnNames['team_foreign_key']);
+                $table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
                 $table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
-
-                $table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'],
+                $table->index($pivotPermission, 'model_has_permissions_permission_id_foreign');
+                //$table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'],
+                //    'model_has_permissions_permission_model_type_primary');
+                $table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
                     'model_has_permissions_permission_model_type_primary');
             } else {
                 $table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
@@ -93,10 +96,12 @@ return new class extends Migration
                 ->on($tableNames['roles'])
                 ->onDelete('cascade');
             if ($teams) {
-                $table->unsignedBigInteger($columnNames['team_foreign_key']);
+                $table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
                 $table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
-
-                $table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'],
+                $table->index($pivotRole, 'model_has_roles_role_id_foreign');
+                //$table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'],
+                //    'model_has_roles_role_model_type_primary');
+                $table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'],
                     'model_has_roles_role_model_type_primary');
             } else {
                 $table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'],

Use Gate::before() as documented for Super-Admin in AuthServiceProvider.php.

Implement Middleware as documented for Teams. Register middleware in bootstrap/app.php.

The Super-Admin user is seeded:

$role = Role::findByName(RoleEnum::SuperAdmin->value);
$role->team_id = config('permission.default_team_id');
setPermissionsTeamId(config('permission.default_team_id')); // null
$superAdminUser  = User::updateOrCreate([...]);
$superAdminUser->assignRole($role);

Resulting in:

> select * from model_has_roles;
+---------+-----------------+----------+---------+
| role_id | model_type      | model_id | team_id |
+---------+-----------------+----------+---------+
|       5 | App\Models\User |        1 |    NULL |
+---------+-----------------+----------+---------+

This user is able to log in and use the site as intended, passing all permissions checks, without encountering integrity constraint violations (MySQL error 1452).

I realize there are redundant indexes, they are included for clarity here.

Is there anything I've failed to consider, or any concerns going forward?

0 likes
0 replies

Please or to participate in this conversation.