Permission Service
Il PermissionService è un service utility che semplifica la creazione e gestione di permessi extra durante le migration e i seeder. Questo service è progettato per creare permessi aggiuntivi oltre a quelli già automaticamente generati dal sistema AutoPermissions. Fornisce metodi convenienti per i developer che devono creare o eliminare permessi personalizzati manualmente nel database.
Quando Usare PermissionService
🤖 AutoPermissions vs 🛠️ PermissionService
| Scenario | Strumento da Usare | Descrizione |
|---|---|---|
| Permessi standard CRUD | 🤖 AutoPermissions | Permessi generati automaticamente dai controller (index, show, create, update, destroy) |
| Permessi personalizzati | 🛠️ PermissionService | Permessi per funzionalità extra |
❌ Evita Duplicazioni
// ❌ NON creare manualmente permessi già gestiti da AutoPermissions
PermissionService::createPermission('shared', 'users', 'index'); // Già auto-generato
PermissionService::createPermission('shared', 'users', 'create'); // Già auto-generato
Installazione e Setup
Il PermissionService è già registrato nell'AutoPermissionsServiceProvider e si utilizza come facade unificata.
Utilizzo
use App\Shared\Services\Permissions\Support\PermissionService;
// Utilizzo diretto del service
PermissionService::createPermission('shared', 'users', 'export');
// Oppure utilizzando l'alias registrato
use PermissionService;
PermissionService::createPermission('shared', 'users', 'export');
Metodi Principali
createPermission()
Crea un singolo permesso specificando modulo, risorsa e azione.
public function createPermission(
string $module,
string $resource,
string $action,
array $attributes = []
): Permission
Parametri
| Parametro | Tipo | Descrizione |
|---|---|---|
$module | string | short_name_snake del modulo (es: 'shared', 'ago', 'mc', 'bt') |
$resource | string | Nome della risorsa (es: 'users', 'companies') |
$action | string | Nome dell'azione (es: 'index', 'create', 'update') |
$attributes | array | Attributi aggiuntivi (title, description, order, ecc) |
Esempio Base
// Crea il permesso: shared.users.export
$permission = PermissionService::createPermission(
'shared',
'users',
'export'
);
Esempio con Attributi
// Crea permesso con attributi personalizzati
$permission = PermissionService::createPermission(
'shared',
'users',
'bulk_delete',
[
'title' => 'Eliminazione multipla utenti',
'description' => 'Permette di eliminare più utenti contemporaneamente',
'order' => 100,
'is_auto_generated' => false
]
);
deletePermission()
Elimina un permesso specificando modulo, risorsa e azione.
public function deletePermission(
string $module,
string $resource,
string $action,
bool $forceDelete = false
): bool
Parametri
| Parametro | Tipo | Descrizione |
|---|---|---|
$module | string | short_name_snake del modulo (es: 'shared', 'ago', 'mc', 'bt') |
$resource | string | Nome della risorsa |
$action | string | Nome dell'azione |
$forceDelete | bool | Forza l'eliminazione anche di permessi manuali (default: false) |
Esempio Base
// Elimina il permesso: shared.users.export
$deleted = PermissionService::deletePermission(
'shared',
'users',
'export'
);
Eliminazione Forzata
// Elimina anche permessi manuali
$deleted = PermissionService::deletePermission(
'shared',
'users',
'custom_action',
true // forceDelete = true
);
createResourcePermissions()
Crea multiple permessi per una risorsa in una sola chiamata.
public function createResourcePermissions(
string $module,
string $resource,
array $actions
): array
Esempio con Array Semplice
// Crea permessi standard per la risorsa users
$permissions = PermissionService::createResourcePermissions(
'shared',
'users',
['index', 'show', 'create', 'store', 'edit', 'update', 'destroy']
);
Esempio con Attributi Personalizzati
// Crea permessi con attributi specifici per azione
$permissions = PermissionService::createResourcePermissions(
'shared',
'reports',
[
'index' => [
'title' => 'Visualizzare elenco report',
'order' => 10
],
'generate_pdf' => [
'title' => 'Generare report PDF',
'description' => 'Crea report in formato PDF',
'order' => 50
],
'export_excel' => [
'title' => 'Esportare in Excel',
'order' => 60
]
]
);
deleteResourcePermissions()
Elimina multiple permessi per una risorsa.
public function deleteResourcePermissions(
string $module,
string $resource,
array $actions,
bool $forceDelete = false
): array
Esempio
// Elimina permessi specifici per la risorsa
$results = PermissionService::deleteResourcePermissions(
'shared',
'users',
['export', 'bulk_delete', 'advanced_search']
);
// $results = ['export' => true, 'bulk_delete' => true, 'advanced_search' => false]
permissionExists()
Controlla se un permesso esiste.
public function permissionExists(string $module, string $resource, string $action): bool
Esempio
if (PermissionService::permissionExists('shared', 'users', 'export')) {
// Il permesso esiste già
} else {
// Crea il permesso
PermissionService::createPermission('shared', 'users', 'export');
}
Utilizzo nelle Migration
Migration Up/Down Completa
<?php
use App\Shared\Services\Permissions\Support\PermissionService;
use Illuminate\Database\Migrations\Migration;
class CreateUserExtraPermissions extends Migration
{
protected array $extraPermissions = [
'export_users' => [
'title' => 'Esportare utenti',
'description' => 'Permette di esportare l\'elenco utenti in vari formati',
'order' => 50
],
'bulk_operations' => [
'title' => 'Operazioni multiple',
'description' => 'Esegue operazioni su più utenti contemporaneamente',
'order' => 60
]
];
/**
* Run the migrations.
*/
public function up(): void
{
foreach ($this->extraPermissions as $action => $attributes) {
PermissionService::createPermission(
'shared',
'users',
$action,
$attributes
);
}
}
/**
* Reverse the migrations.
*/
public function down(): void
{
foreach (array_keys($this->extraPermissions) as $action) {
PermissionService::deletePermission(
'shared',
'users',
$action,
true // forceDelete per permessi manuali
);
}
}
}
Migration con Controllo Esistenza
public function up(): void
{
// Controlla se il permesso esiste prima di crearlo
if (!PermissionService::permissionExists('shared', 'users', 'advanced_search')) {
PermissionService::createPermission(
'shared',
'users',
'advanced_search',
[
'title' => 'Ricerca avanzata utenti',
'description' => 'Accesso alla ricerca avanzata con filtri multipli'
]
);
}
}
Utilizzo nei Seeder
Seeder Base
<?php
namespace Database\Seeders;
use App\Shared\Services\Permissions\Support\PermissionService;
use Illuminate\Database\Seeder;
class UserPermissionsSeeder extends Seeder
{
public function run(): void
{
PermissionService::createResourcePermissions(
'shared',
'users',
[
'index' => ['title' => 'Elenco utenti', 'order' => 10],
'show' => ['title' => 'Dettaglio utente', 'order' => 20],
'create' => ['title' => 'Creare utente', 'order' => 30],
'store' => ['title' => 'Salvare utente', 'order' => 31],
'edit' => ['title' => 'Modificare utente', 'order' => 40],
'update' => ['title' => 'Aggiornare utente', 'order' => 41],
'destroy' => ['title' => 'Eliminare utente', 'order' => 50],
]
);
PermissionService::createPermission(
'shared',
'users',
'impersonate',
[
'title' => 'Impersonificare utente',
'description' => 'Permette di accedere come un altro utente',
'order' => 100
]
);
}
}
Identificazione Moduli
Come Identificare il Modulo Corretto
Il parametro $module deve sempre essere il short_name_snake del modulo come definito in config/modules.php:
| Chiave Modulo | Nome Completo | short_name_snake | Uso nel PermissionService |
|---|---|---|---|
Shared | Shared | shared | ✅ 'shared' |
AgoModule | CoreAgora | ago | ✅ 'ago' |
McModule | MetricCalculations | mc | ✅ 'mc' |
BtModule | BudgetingTool | bt | ✅ 'bt' |
ContModule | Contracts | cont | ✅ 'cont' |
InvModule | Invoices | inv | ✅ 'inv' |
PayModule | Payments | pay | ✅ 'pay' |
Helper per Conversione Moduli
Se hai la chiave del modulo e vuoi ottenere il short_name_snake:
use App\Shared\Services\Permissions\Support\PermissionServiceManager;
// Converte chiave modulo → short_name_snake
$shortName = PermissionServiceManager::getModuleShortNameSnake('AgoModule'); // 'ago'
$shortName = PermissionServiceManager::getModuleShortNameSnake('Shared'); // 'shared'
$shortName = PermissionServiceManager::getModuleShortNameSnake('Invalid'); // null
// Poi usa il risultato nel PermissionService
if ($shortName) {
PermissionService::createPermission($shortName, 'users', 'create');
}
Esempi di Utilizzo per Modulo
// ✅ CORRETTO - Usa short_name_snake
PermissionService::createPermission('shared', 'users', 'export');
PermissionService::createPermission('ago', 'projects', 'create');
PermissionService::createPermission('mc', 'calculations', 'run');
// ❌ ERRATO - Usa chiave modulo
PermissionService::createPermission('Shared', 'users', 'export'); // InvalidArgumentException
PermissionService::createPermission('AgoModule', 'projects', 'create'); // InvalidArgumentException
PermissionService::createPermission('McModule', 'calculations', 'run'); // InvalidArgumentException
Validazione e Sicurezza
Regole di Validazione
Il PermissionService applica automaticamente le seguenti validazioni:
Nomi Modulo, Risorsa e Azione
- Caratteri consentiti: solo lettere minuscole, numeri e underscore (
a-z0-9_) - Lunghezza massima: 50 caratteri
- Non consentiti: punti (
.), underscore consecutivi, underscore iniziale/finale
Attributi
- Title: massimo 255 caratteri, no caratteri HTML pericolosi (
<>"'&) - Description: massimo 1000 caratteri
- Order: intero tra 0 e 9999
Gestione Errori
try {
$permission = PermissionService::createPermission(
'invalid-module', // ❌ Contiene trattino
'users',
'create'
);
} catch (\InvalidArgumentException $e) {
// Gestisci errore di validazione
logger()->error('Permission creation failed: ' . $e->getMessage());
}
Protezione Eliminazione
// ❌ Questo fallirà se il permesso non è auto-generato
PermissionService::deletePermission('shared', 'users', 'manual_permission');
// ✅ Questo funzionerà anche per permessi manuali
PermissionService::deletePermission('shared', 'users', 'manual_permission', true);
Best Practices
1. Documenta i Permessi Personalizzati
// ✅ Sempre includi description per permessi non standard
PermissionService::createPermission(
'shared',
'users',
'bulk_status_change',
[
'title' => 'Modifica stato multipla',
'description' => 'Permette di attivare/disattivare più utenti contemporaneamente',
'order' => 70
]
);
2. Gestisci Rollback nelle Migration
public function down(): void
{
// Memorizza i permessi da eliminare
$permissionsToDelete = ['export', 'bulk_delete', 'advanced_search'];
foreach ($permissionsToDelete as $action) {
try {
PermissionService::deletePermission(
'shared',
'users',
$action,
true
);
} catch (\Exception $e) {
// Log ma non bloccare il rollback
logger()->warning("Failed to delete permission during rollback: {$action}");
}
}
}
3. Controlla Esistenza prima della Creazione
public function up(): void
{
$permissions = [
'export' => ['title' => 'Esportare utenti'],
'bulk_operations' => ['title' => 'Operazioni multiple']
];
foreach ($permissions as $action => $attributes) {
if (!PermissionService::permissionExists('shared', 'users', $action)) {
PermissionService::createPermission('shared', 'users', $action, $attributes);
}
}
}
Troubleshooting
Errore: "Module does not exist"
// ❌ Problema: modulo inesistente o formato errato
PermissionService::createPermission('invalid_module', 'users', 'create');
PermissionService::createPermission('Shared', 'users', 'create'); // Usa chiave invece di short_name_snake
// ✅ Soluzione: usa short_name_snake valido
PermissionService::createPermission('shared', 'users', 'create');
// ✅ Oppure converti prima la chiave
$shortName = PermissionServiceManager::getModuleShortNameSnake('Shared');
if ($shortName) {
PermissionService::createPermission($shortName, 'users', 'create');
}
Errore: "Permission is not auto-generated"
// Problema: tentativo di eliminare permesso manuale senza flag force
PermissionService::deletePermission('shared', 'users', 'manual_permission');
// Soluzione: usa forceDelete
PermissionService::deletePermission('shared', 'users', 'manual_permission', true);
Errore: "Module name must contain only lowercase letters"
// ❌ Problema
PermissionService::createPermission('Admin-Module', 'users', 'create');
// ✅ Soluzione
PermissionService::createPermission('admin_module', 'users', 'create');
Errore: "Action name cannot contain dots"
// ❌ Problema
PermissionService::createPermission('shared', 'users', 'users.export');
// ✅ Soluzione
PermissionService::createPermission('shared', 'users', 'export');
// Risultato: shared.users.export
Logging e Debug
Il PermissionService logga automaticamente solo errori e situazioni problematiche:
// Log di warning - permesso non trovato per eliminazione
Log::warning('Permission not found for deletion', [
'permission' => 'shared.users.export',
'module' => 'shared',
'resource' => 'resource',
'action' => 'action',
]);
// Log di warning - tentativo di eliminazione permesso manuale senza force
Log::warning('Attempted to delete manual permission without force flag', [
'permission' => 'shared.users.export',
'is_auto_generated' => false,
]);