Skip to main content

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

ScenarioStrumento da UsareDescrizione
Permessi standard CRUD🤖 AutoPermissionsPermessi generati automaticamente dai controller (index, show, create, update, destroy)
Permessi personalizzati🛠️ PermissionServicePermessi 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

ParametroTipoDescrizione
$modulestringshort_name_snake del modulo (es: 'shared', 'ago', 'mc', 'bt')
$resourcestringNome della risorsa (es: 'users', 'companies')
$actionstringNome dell'azione (es: 'index', 'create', 'update')
$attributesarrayAttributi 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

ParametroTipoDescrizione
$modulestringshort_name_snake del modulo (es: 'shared', 'ago', 'mc', 'bt')
$resourcestringNome della risorsa
$actionstringNome dell'azione
$forceDeleteboolForza 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 ModuloNome Completoshort_name_snakeUso nel PermissionService
SharedSharedshared'shared'
AgoModuleCoreAgoraago'ago'
McModuleMetricCalculationsmc'mc'
BtModuleBudgetingToolbt'bt'
ContModuleContractscont'cont'
InvModuleInvoicesinv'inv'
PayModulePaymentspay'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,
]);