
Gestire le pagine e i cluster in Filament
By
Non sempre in Filament dobbiamo avere voci di menu associate a Model e quindi delle Resource, talvolta abbiamo bisogno di pagine che usano uno o più modelli e che non vengano gestiti solo tramite le Resources. E ancora, spesso abbiamo bisogno di raggruppare delle pagine che hanno in comune alcune funzionalità o manipolazione dei dati ed in Filament questi si chiamano Cluster.
Per avere un po’ la situazione sotto controllo e capire come “ragiona” Filament, dai un’occhiata a AdminPanelProvider.php dentro app/Providers/Filament, trovdrai qualcosa del genere:
->discoverResources(in: app_path('Filament/Resources'), for: 'App\Filament\Resources')
->discoverClusters(in: app_path('Filament/Clusters'), for: 'App\Filament\Clusters')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\Filament\Pages')Come si vede viene esplicitamente detto a Filament dove si trovano queste classi, quindi è anche… personalizzabile, ma non ce n’è per ora bisogno 😉
I Cluster
Anche se questo è opzionale, ovvero delle pagine possono esistere anche senza far parte di cluster, parto da qui perché è nelle pagine (che vedremo dopo) che si definisce il cluster a cui appartiene se deve essere inserito in questo.
Ovviamente esiste il comando per crearlo:
php artisan make:filament-cluster NomeCluster
Verranno create le cartelle app/Filament/Clusters/Pages e il file NomeCluster.php al suo interno. La struttura del file è semplice e standard, si definisce l’icona, il nome nel menu, l’ordine ecc. come si farebbe con una resource.
Le pagine
Adesso invece creiamo la pagina e inseriamola nel cluster:
php artisan make:filament-page UsersManual
Se vogliamo che questa pagina si aggiunga ad un cluster, basta valorizzare la variabile corrispondente così:
protected static ?string $cluster = NomeCluster::class;
Opppure ancora meglio, se Filament riconosce la presenza di clusters ti chiederà se questa pagina fa parte di un cluster e rispondendo sì, ti mostra le classi che trova. Scelto il cluster, alla generazione della pagina viene anche creata la view per la nuova pagina e questa viene inserita in resources/views/filament/clusters/nome/pages/user-manula-page.php
Ti consiglio di provare sia creare pagine che cluster per vedere come si posizionano nel menu, ma sicuramente rimarrai soddisfatto del risultato anche dal punto di vista estetico.
La view
Anche la view ha la sua importanza: deve richiamare i dati e la struttura del form:
<x-filament-panels::page>
<p class="text-sm text-gray-500">
Seleziona la pagina del manuale.
</p>
<form wire:submit="save" class="space-y-6">
{{ $this->form }}
<div class="flex justify-end pt-6 mt-6">
<x-filament::button type="submit">
Seleziona
</x-filament::button>
</div>
</form>
</x-filament-panels::page>In questo modo la struttura del form segue quanto faremo nel form sotto, e i dati saranno gestiti correttamente.
Le resources
Naturalmente è possibile aggiungere anche le resources oltre alle pages nei cluster e lo faremo alla stessa maniera (definendo la variabile $cluster) ma non nelle singole pagine bensì nella classe “genitrice” SettingsResource.php (seguendo la nomenclatura dell’esempio). Come si vede non solo Filament è molto potente, ma sono veramente pochi i casi in cui una richiesta che possiamo fare non venga esaudita da una configurazione adeguata dei file di Filament. Sono sempre più convinto che FilamentPHP sia una scelta obbligata e sensata per un backend moderno e versatile.
Bonus: i Forms
Ma non voglio fermarmi all’argomento del post perché quello dei Form è uno strumento “troppo” utile per non parlarne.
Una pagina, come abbiamo detto, non è necessariamente e nel modo “tradizionale” associato ad un Model del database, quindi che funzione avrà? Ok, è una pagina, quindi forse basterà che visualizzi del testo, immagini, ecc. Ma non sempre è così, io spesso le creo per interagire con l’utente in una maniera non “consona” al tradizionale CRUD.
Creando un Form e andandolo ad associare alla pagina, ecco che questa diventa “attiva”, ovvero può interagire con l’utente e fare operazioni sul database come una resource, ma non come… una resource!
Non essendoci un comando come php artisan make:filament-form (o meglio non fa quello che vogliamo noi, provare per credere), procediamo manualmente creando la cartella app/Filament/Forms e poi il file UserManualForm.php.
Diciamo alla pagina di usare questo form custom aggiungendo l’interfaccia HasForm:
class UserManualPage extends Page implements HasForms
{
use InteractsWithForms;
...
public ?array $data = [];
public function mount(): void
{
$this->form->fill();
}
public function form(Schema $schema): Schema
{
return UserManualForm::configure($schema)->statePath('data');
}
...
}Come si vede si implementa l’interfaccia HasForm e si aggiunge il Trait InteractWithForms (vedi questo articolo).
Dentro al form appena creato possiamo inserire quello che vogliamo, senza problemi legati a CRUD vari…