<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dev-Iadicola</title>
    <description>The latest articles on DEV Community by Dev-Iadicola (@dev_iadicola).</description>
    <link>https://dev.to/dev_iadicola</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2138925%2F6dd30c44-71a1-4568-a668-759ac9486600.png</url>
      <title>DEV Community: Dev-Iadicola</title>
      <link>https://dev.to/dev_iadicola</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dev_iadicola"/>
    <language>en</language>
    <item>
      <title>Symfony 8.1: le novità in arrivo con la release di maggio 2026</title>
      <dc:creator>Dev-Iadicola</dc:creator>
      <pubDate>Sun, 20 Sep 2026 17:00:20 +0000</pubDate>
      <link>https://dev.to/dev_iadicola/symfony-81-le-novita-in-arrivo-con-la-release-di-maggio-2026-22jk</link>
      <guid>https://dev.to/dev_iadicola/symfony-81-le-novita-in-arrivo-con-la-release-di-maggio-2026-22jk</guid>
      <description>&lt;h2&gt;
  
  
  Cosa porta Symfony 8.1 agli sviluppatori PHP
&lt;/h2&gt;

&lt;p&gt;Symfony 8.1 e la prima minor release dopo la major 8.0, prevista per maggio 2026. Come ogni minor release, non introduce breaking changes — l'upgrade dalla 8.0 e trasparente e garantito dalla backward compatibility promise. Continua a richiedere &lt;strong&gt;PHP 8.4&lt;/strong&gt; e porta miglioramenti incrementali ma significativi su controller, sicurezza, Messenger e i componenti JSON introdotti con la 8.0. Il supporto regolare per la 8.1 dura fino a gennaio 2027.&lt;/p&gt;

&lt;p&gt;Le minor release di Symfony sono spesso sottovalutate, ma contengono miglioramenti alla &lt;strong&gt;developer experience&lt;/strong&gt; che hanno un impatto quotidiano sul lavoro degli sviluppatori. Symfony 8.1 non fa eccezione: quasi ogni novità e orientata a ridurre il codice boilerplate nei controller e a dare più controllo sugli strumenti già esistenti.&lt;/p&gt;

&lt;h2&gt;
  
  
  Novità principali di Symfony 8.1
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Controller metadata esposti nel ciclo di vita della richiesta
&lt;/h3&gt;

&lt;p&gt;I metadati del controller — nome della classe, metodo invocato, attributi applicati — sono ora accessibili durante &lt;strong&gt;tutto il ciclo di vita della richiesta HTTP&lt;/strong&gt;, non solo nel controller stesso. Questo apre scenari interessanti per middleware, event listener e logiche trasversali.&lt;/p&gt;

&lt;p&gt;Un esempio pratico: un event listener che logga automaticamente quale controller ha gestito ogni richiesta, con quale metodo e quali attributi di sicurezza erano applicati. Prima di Symfony 8.1, ottenere queste informazioni fuori dal controller richiedeva workaround tramite il router o introspezione manuale. Ora sono disponibili come dato di prima classe nell'oggetto request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Espressioni avanzate in IsGranted
&lt;/h3&gt;

&lt;p&gt;L'attributo &lt;code&gt;#[IsGranted]&lt;/code&gt; supporta ora la variabile &lt;code&gt;this&lt;/code&gt; nelle espressioni, permettendo di referenziare il controller stesso nelle regole di autorizzazione. Questo e particolarmente utile quando le regole di accesso dipendono dallo stato del controller o da proprieta iniettate nel costruttore.&lt;/p&gt;

&lt;p&gt;Consideriamo un controller che gestisce risorse per tenant diversi. Con &lt;code&gt;this&lt;/code&gt; nelle espressioni, si può scrivere &lt;code&gt;#[IsGranted(new Expression('this.getCurrentTenant() == subject.getTenant()'))]&lt;/code&gt; direttamente sull'azione, senza voter custom dedicati. La logica di autorizzazione resta dichiarativa e visibile nella signature del metodo.&lt;/p&gt;

&lt;h3&gt;
  
  
  MapRequestHeader: header HTTP come parametri
&lt;/h3&gt;

&lt;p&gt;Il nuovo attributo &lt;code&gt;#[MapRequestHeader]&lt;/code&gt; permette di &lt;strong&gt;mappare header HTTP direttamente nei parametri del metodo controller&lt;/strong&gt;. Niente più &lt;code&gt;$request-&amp;gt;headers-&amp;gt;get('X-Api-Key')&lt;/code&gt;: l'header viene iniettato come parametro tipizzato del metodo.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tipo automatico&lt;/strong&gt;: il tipo del parametro determina la conversione. Un header mappato a &lt;code&gt;int&lt;/code&gt; viene convertito automaticamente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validazione integrata&lt;/strong&gt;: combinabile con constraint di validazione per verificare formato, lunghezza e pattern dell'header.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Valore default&lt;/strong&gt;: un parametro con valore default rende l'header opzionale. Senza default, un header mancante genera un errore 400.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Naming personalizzabile&lt;/strong&gt;: il nome dell'header può differire dal nome del parametro, gestendo la convenzione X-Header-Name vs $headerName automaticamente.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Espressioni in MapRequestPayload
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;#[MapRequestPayload]&lt;/code&gt; accetta ora espressioni per i &lt;strong&gt;gruppi di validazione dinamici&lt;/strong&gt;. Questo permette di cambiare le regole di validazione in base al contesto senza logica nel controller. Ad esempio, validare un payload diversamente per utenti admin e utenti normali, o applicare regole diverse in base a un header della richiesta — tutto dichiarato nell'attributo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eventi su attributi controller
&lt;/h3&gt;

&lt;p&gt;Symfony 8.1 introduce il &lt;strong&gt;dispatch automatico di eventi basati sugli attributi&lt;/strong&gt; del controller. Applicare un attributo custom a un'azione del controller può automaticamente triggerare un evento, senza codice esplicito nel controller. Questo e potente per cross-cutting concerns come audit logging, rate limiting, feature flags e caching condizionale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deprecation e segnali per il futuro
&lt;/h2&gt;

&lt;p&gt;Symfony 8.1 depreca la funzionalita &lt;code&gt;eraseCredentials&lt;/code&gt; nel componente Security. Questa funzionalita, presente fin dalle prime versioni di Symfony, cancellava le credenziali sensibili dall'oggetto utente dopo l'autenticazione. La deprecation e un segnale chiaro: &lt;strong&gt;verra rimossa in Symfony 9&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Chi usa &lt;code&gt;eraseCredentials()&lt;/code&gt; in custom user provider o authenticator ha tempo per adeguarsi durante l'intero ciclo 8.x (fino a novembre 2029 con la LTS 8.4). L'approccio consigliato e spostare la logica di pulizia delle credenziali in un event listener sull'evento di autenticazione.&lt;/p&gt;

&lt;h2&gt;
  
  
  Miglioramenti a componenti esistenti
&lt;/h2&gt;

&lt;p&gt;Oltre alle novità principali, Symfony 8.1 porta miglioramenti incrementali a diversi componenti.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HttpClient&lt;/strong&gt;: nuove opzioni per retry e timeout granulari per richiesta.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache&lt;/strong&gt;: supporto migliorato per cache tagging e invalidazione selettiva.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Translation&lt;/strong&gt;: performance migliorate per cataloghi di traduzione grandi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mailer&lt;/strong&gt;: supporto per nuovi provider di invio email.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notifier&lt;/strong&gt;: nuovi canali di notifica e miglioramenti ai canali esistenti.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conviene aggiornare dalla 8.0 alla 8.1?
&lt;/h2&gt;

&lt;p&gt;Si, senza riserve. L'upgrade da una minor alla successiva in Symfony e sempre sicuro grazie alla backward compatibility promise. Non ci sono breaking changes, solo nuove funzionalita e bugfix. Il processo e semplice: aggiornare le dipendenze in &lt;code&gt;composer.json&lt;/code&gt;, eseguire &lt;code&gt;composer update&lt;/code&gt;, verificare con la test suite. Per uno sviluppatore freelance PHP, restare sulla minor più recente significa accedere ai bugfix più rapidamente e avere la documentazione più aggiornata come riferimento.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://iadicola.it/articoli/symfony-81-novita-release-maggio-2026?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Leggi l'articolo completo su iadicola.it&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>symfony</category>
      <category>php</category>
      <category>aggiornamenti</category>
    </item>
    <item>
      <title>MapRequestHeader e controller attributes: la DX di Symfony 8.1</title>
      <dc:creator>Dev-Iadicola</dc:creator>
      <pubDate>Sat, 19 Sep 2026 21:20:20 +0000</pubDate>
      <link>https://dev.to/dev_iadicola/maprequestheader-e-controller-attributes-la-dx-di-symfony-81-4aag</link>
      <guid>https://dev.to/dev_iadicola/maprequestheader-e-controller-attributes-la-dx-di-symfony-81-4aag</guid>
      <description>&lt;h2&gt;
  
  
  Il problema del boilerplate nei controller Symfony
&lt;/h2&gt;

&lt;p&gt;Ogni controller in un'applicazione Symfony ripete le stesse operazioni: estrarre dati dalla richiesta HTTP, validarli, controllare i permessi, delegare al service layer, costruire la risposta. Gran parte di questo codice e &lt;strong&gt;infrastrutturale, non di business&lt;/strong&gt; — e identico (o quasi) in ogni azione di ogni controller dell'applicazione.&lt;/p&gt;

&lt;p&gt;Symfony ha affrontato questo problema progressivamente. Symfony 6.3 ha introdotto &lt;code&gt;#[MapRequestPayload]&lt;/code&gt; e &lt;code&gt;#[MapQueryString]&lt;/code&gt; per la deserializzazione automatica del body e dei query parameter. Symfony 7 ha aggiunto miglioramenti alla validazione integrata. Symfony 8.1 porta il concetto ancora più avanti con nuovi attributi che coprono gli header HTTP e la logica di autorizzazione.&lt;/p&gt;

&lt;h2&gt;
  
  
  MapRequestHeader in dettaglio
&lt;/h2&gt;

&lt;p&gt;Il nuovo attributo &lt;code&gt;#[MapRequestHeader]&lt;/code&gt; completa la famiglia degli attributi di mapping che Symfony mette a disposizione nei controller. Il suo funzionamento e coerente con gli altri attributi della famiglia: un parametro del metodo controller viene decorato con l'attributo, e Symfony si occupa di estrarre, convertire e validare il dato dalla richiesta HTTP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sintassi e utilizzo pratico
&lt;/h3&gt;

&lt;p&gt;L'utilizzo e diretto e intuitivo. Un parametro del metodo controller decorato con &lt;code&gt;#[MapRequestHeader]&lt;/code&gt; riceve automaticamente il valore dell'header HTTP corrispondente. Il nome dell'header viene derivato dal nome del parametro, con conversione automatica da camelCase a kebab-case con prefisso standard.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mapping diretto&lt;/strong&gt;: &lt;code&gt;#[MapRequestHeader] string $apiKey&lt;/code&gt; mappa l'header &lt;code&gt;Api-Key&lt;/code&gt;. Niente più &lt;code&gt;$request-&amp;gt;headers-&amp;gt;get('Api-Key')&lt;/code&gt; nel body del metodo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nome custom&lt;/strong&gt;: &lt;code&gt;#[MapRequestHeader(name: 'X-Custom-Token')] string $token&lt;/code&gt; permette di specificare il nome esatto dell'header quando non segue la convenzione standard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conversione di tipo&lt;/strong&gt;: il tipo del parametro guida la conversione. &lt;code&gt;int $rateLimit&lt;/code&gt; converte automaticamente il valore dell'header in intero. &lt;code&gt;?string $optional&lt;/code&gt; gestisce header assenti.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Array di valori&lt;/strong&gt;: &lt;code&gt;array $acceptLanguage&lt;/code&gt; gestisce header con valori multipli separati da virgola, splittandoli automaticamente in un array.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Validazione degli header
&lt;/h3&gt;

&lt;p&gt;Gli header mappati possono essere validati con gli stessi &lt;strong&gt;constraint di validazione&lt;/strong&gt; usati per qualsiasi altro dato in Symfony. Si possono applicare constraint come &lt;code&gt;#[Assert\NotBlank]&lt;/code&gt;, &lt;code&gt;#[Assert\Length(max: 255)]&lt;/code&gt; o &lt;code&gt;#[Assert\Regex]&lt;/code&gt; direttamente sul parametro del controller. Un header che non supera la validazione genera una risposta 400 Bad Request con dettagli sull'errore, senza che il controller debba gestire manualmente la validazione.&lt;/p&gt;

&lt;h2&gt;
  
  
  Miglioramenti a IsGranted con espressioni
&lt;/h2&gt;

&lt;p&gt;L'attributo &lt;code&gt;#[IsGranted]&lt;/code&gt; in Symfony 8.1 guadagna il supporto alla variabile &lt;code&gt;this&lt;/code&gt; nelle espressioni. Questo e un cambiamento apparentemente piccolo ma con implicazioni significative per la gestione delle autorizzazioni.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prima di Symfony 8.1
&lt;/h3&gt;

&lt;p&gt;Per regole di autorizzazione che dipendevano dallo stato del controller (ad esempio, un tenant corrente iniettato nel costruttore), serviva un &lt;strong&gt;security voter custom&lt;/strong&gt;: una classe separata, registrata come servizio, che implementava l'interfaccia &lt;code&gt;VoterInterface&lt;/code&gt;. Per logiche semplici, il costo in termini di codice e complessità era sproporzionato rispetto al problema risolto.&lt;/p&gt;

&lt;h3&gt;
  
  
  Con Symfony 8.1
&lt;/h3&gt;

&lt;p&gt;La variabile &lt;code&gt;this&lt;/code&gt; nelle espressioni permette di accedere a metodi e proprieta del controller direttamente nell'espressione di autorizzazione. Pattern comuni come verificare che l'utente appartenga allo stesso tenant della risorsa, o che abbia un ruolo specifico nel contesto dell'organizzazione corrente, si risolvono con un'espressione inline senza classi aggiuntive.&lt;/p&gt;

&lt;h2&gt;
  
  
  MapRequestPayload con gruppi di validazione dinamici
&lt;/h2&gt;

&lt;p&gt;L'attributo &lt;code&gt;#[MapRequestPayload]&lt;/code&gt; in Symfony 8.1 accetta &lt;strong&gt;espressioni per i gruppi di validazione&lt;/strong&gt;. Questo risolve un problema comune: validare lo stesso DTO con regole diverse in contesti diversi.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Validazione per ruolo&lt;/strong&gt;: un admin può inviare campi che un utente normale non può. I gruppi di validazione dinamici applicano le constraint corrette in base al ruolo, senza logica nel controller.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validazione per contesto&lt;/strong&gt;: creazione vs aggiornamento dello stesso oggetto possono avere regole diverse. L'espressione determina il gruppo a runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validazione per header&lt;/strong&gt;: combinando con &lt;code&gt;#[MapRequestHeader]&lt;/code&gt;, si possono applicare regole di validazione diverse in base alla versione dell'API dichiarata nell'header.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Opzioni per dati vuoti in MapQueryString e MapRequestPayload
&lt;/h2&gt;

&lt;p&gt;Symfony 8.1 introduce opzioni dedicate per gestire i &lt;strong&gt;casi edge dei dati vuoti&lt;/strong&gt;. Cosa succede quando un query string e presente ma vuoto? O quando il body della richiesta e un oggetto JSON vuoto? Prima di Symfony 8.1, questi scenari richiedevano gestione manuale. Ora le opzioni &lt;code&gt;acceptEmptyBody&lt;/code&gt; e il valore di default per query string vuoti sono configurabili direttamente nell'attributo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Il pattern emergente: controller come dichiarazione di intenti
&lt;/h2&gt;

&lt;p&gt;Guardando l'evoluzione degli attributi controller da Symfony 6.3 a Symfony 8.1, emerge un pattern chiaro. Il controller sta diventando una &lt;strong&gt;dichiarazione di intenti&lt;/strong&gt; piuttosto che un'implementazione procedurale. Gli attributi descrivono cosa il controller deve ricevere (payload, query, header), come validarlo (constraint, gruppi), chi può accedervi (IsGranted, espressioni) e cosa restituire.&lt;/p&gt;

&lt;p&gt;Il framework si occupa dell'esecuzione. Il controller si concentra sull'orchestrazione della business logic. Per chi sviluppa API REST con Symfony, questo approccio riduce drasticamente il codice infrastrutturale e rende i controller più leggibili, testabili e manutenibili. Come sviluppatore freelance PHP, apprezzo particolarmente questo trend perché rende il codice auto-documentante — un nuovo sviluppatore che legge il controller capisce immediatamente cosa fa, senza dover navigare service class e configuration file.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://iadicola.it/articoli/map-request-header-controller-attributes-dx-symfony-81?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Leggi l'articolo completo su iadicola.it&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>symfony</category>
      <category>backend</category>
      <category>php</category>
    </item>
    <item>
      <title>Messenger e JsonPath in Symfony 8.1: miglioramenti pratici</title>
      <dc:creator>Dev-Iadicola</dc:creator>
      <pubDate>Fri, 18 Sep 2026 17:00:10 +0000</pubDate>
      <link>https://dev.to/dev_iadicola/messenger-e-jsonpath-in-symfony-81-miglioramenti-pratici-g4o</link>
      <guid>https://dev.to/dev_iadicola/messenger-e-jsonpath-in-symfony-81-miglioramenti-pratici-g4o</guid>
      <description>&lt;h2&gt;
  
  
  Messenger in Symfony 8.1: più controllo sul consumer
&lt;/h2&gt;

&lt;p&gt;Il componente &lt;strong&gt;Messenger&lt;/strong&gt; di Symfony e il cuore della gestione asincrona in qualsiasi applicazione Symfony moderna. Code di messaggi, event-driven architecture, processing in background — tutto passa da Messenger. Symfony 8.1 migliora il comando &lt;code&gt;messenger:consume&lt;/code&gt; con nuove opzioni che danno più controllo sul comportamento del worker in ambienti di produzione, dove la stabilita e l'osservabilita sono cruciali.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nuove opzioni per messenger:consume
&lt;/h3&gt;

&lt;p&gt;Il comando &lt;code&gt;messenger:consume&lt;/code&gt; e quello che gira permanentemente sui server di produzione, consumando messaggi dalle code. In Symfony 8.0, le opzioni disponibili coprivano gli scenari base: limite di messaggi, limite di tempo, limite di memoria. Symfony 8.1 aggiunge opzioni per scenari avanzati.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Opzioni di deploy avanzate&lt;/strong&gt;: configurazione per graceful shutdown durante i deploy, con possibilita di completare il messaggio corrente prima di terminare. Fondamentale per deploy zero-downtime con strumenti come Deployer, Envoyer o Kubernetes rolling updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring granulare&lt;/strong&gt;: nuove metriche esposte dal worker che permettono di monitorare non solo quanti messaggi vengono processati, ma anche il tempo medio per messaggio, il tasso di errori e la dimensione della coda. Integrabile con strumenti di monitoring come Prometheus, Datadog o New Relic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Priorità dinamiche&lt;/strong&gt;: possibilita di cambiare la priorità di consumo tra code diverse senza riavviare il worker, utile in scenari dove il carico varia nel tempo e alcune code devono essere svuotate con priorità durante picchi specifici.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Accesso agli argomenti e opzioni originali del comando
&lt;/h3&gt;

&lt;p&gt;Una novità apparentemente minore ma estremamente utile: il worker ora espone gli &lt;strong&gt;argomenti e le opzioni originali&lt;/strong&gt; con cui il comando e stato avviato. Questo e fondamentale per diversi scenari operativi.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Logging contestuale&lt;/strong&gt;: i log del worker possono includere con quale configurazione e stato avviato, facilitando il debugging di problemi in produzione. "Perché questo worker non processa la coda X?" diventa una domanda con risposta immediata nei log.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry intelligente&lt;/strong&gt;: un supervisore (Supervisor, systemd) che riavvia il worker può passare gli stessi argomenti originali, garantendo consistenza dopo un crash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dashboard operativo&lt;/strong&gt;: un pannello di controllo può mostrare lo stato di ogni worker con la sua configurazione corrente, senza dover ispezionare i processi del sistema operativo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  JsonPath: funzioni custom per il tuo dominio
&lt;/h2&gt;

&lt;p&gt;Il componente &lt;strong&gt;JsonPath&lt;/strong&gt;, introdotto con Symfony 8.0 per navigare strutture JSON complesse, guadagna in Symfony 8.1 il supporto per &lt;strong&gt;funzioni custom&lt;/strong&gt;. Questa estensione trasforma JsonPath da semplice strumento di navigazione a un vero linguaggio di query per dati JSON.&lt;/p&gt;

&lt;h3&gt;
  
  
  Come registrare funzioni custom
&lt;/h3&gt;

&lt;p&gt;Le funzioni custom sono normali funzioni PHP registrate come estensioni del motore JsonPath. La registrazione avviene tramite il service container di Symfony, con tag dedicati che associano il nome della funzione JsonPath alla funzione PHP corrispondente.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Funzioni di trasformazione&lt;/strong&gt;: normalizzare stringhe, convertire formati di date, arrotondare valori numerici — operazioni che si applicano durante l'estrazione, non dopo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Funzioni di aggregazione&lt;/strong&gt;: somme, medie, conteggi su sottoinsiemi di dati selezionati dall'espressione JsonPath. Utile per report e dashboard che consumano API esterne.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Funzioni di dominio&lt;/strong&gt;: logiche specifiche dell'applicazione. Un e-commerce potrebbe registrare una funzione &lt;code&gt;calculateDiscount&lt;/code&gt; usabile nelle espressioni JsonPath per calcolare sconti sui prezzi estratti da un feed di prodotti.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Combinare navigazione e trasformazione
&lt;/h3&gt;

&lt;p&gt;La potenza delle funzioni custom emerge quando vengono combinate con le espressioni di navigazione. Un'espressione come &lt;code&gt;$.products[?(@.price &amp;gt; 100)].price.avg()&lt;/code&gt; naviga ai prodotti costosi, estrae i prezzi e calcola la media — tutto in una singola espressione dichiarativa. Senza funzioni custom, questo richiederebbe codice PHP procedurale dopo l'estrazione.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deep Cloner nel componente VarExporter
&lt;/h2&gt;

&lt;p&gt;Il componente &lt;strong&gt;VarExporter&lt;/strong&gt; guadagna un &lt;strong&gt;deep cloner&lt;/strong&gt;: clonazione profonda di oggetti complessi senza implementare &lt;code&gt;__clone()&lt;/code&gt; manualmente. Questo e più significativo di quanto sembri, perché la clonazione profonda in PHP e storicamente problematica.&lt;/p&gt;

&lt;h3&gt;
  
  
  Il problema della clonazione in PHP
&lt;/h3&gt;

&lt;p&gt;L'operatore &lt;code&gt;clone&lt;/code&gt; di PHP esegue una &lt;strong&gt;copia superficiale&lt;/strong&gt;: le proprieta scalari vengono copiate, ma le proprieta che referenziano oggetti mantengono il riferimento all'oggetto originale. Modificare un oggetto annidato nel clone modifica anche l'originale — un bug subdolo e difficile da diagnosticare.&lt;/p&gt;

&lt;p&gt;La soluzione classica e implementare &lt;code&gt;__clone()&lt;/code&gt; in ogni classe, clonando manualmente ogni proprieta oggetto. Ma per grafi di oggetti complessi con relazioni circolari, l'implementazione corretta di &lt;code&gt;__clone()&lt;/code&gt; e tutt'altro che banale.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenari d'uso del deep cloner
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Snapshot di stato&lt;/strong&gt;: salvare lo stato corrente di un oggetto complesso prima di modificarlo, per poter annullare le modifiche in caso di errore. Pattern comune in form wizard e processi multi-step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Undo/redo&lt;/strong&gt;: mantenere una cronologia di stati precedenti per funzionalita di undo. Ogni stato deve essere una copia completamente indipendente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test isolation&lt;/strong&gt;: nei test, clonare un fixture object per ogni test case garantisce che le modifiche in un test non influenzino gli altri. Il deep cloner rende questo pattern affidabile senza implementare &lt;code&gt;__clone()&lt;/code&gt; in ogni classe del dominio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel processing&lt;/strong&gt;: in scenari di processing parallelo, ogni worker deve operare su una copia indipendente dei dati. Il deep cloner garantisce l'indipendenza senza serializzazione/deserializzazione.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  L'impatto cumulativo dei miglioramenti incrementali
&lt;/h2&gt;

&lt;p&gt;Singolarmente, ogni miglioramento in Symfony 8.1 sembra piccolo. Ma l'impatto e cumulativo. Un worker Messenger più controllabile in produzione significa meno incident e meno tempo di debugging. Funzioni JsonPath custom significano meno codice procedurale per elaborare dati JSON. Un deep cloner affidabile significa meno bug di condivisione stato nei test e nelle logiche di undo.&lt;/p&gt;

&lt;p&gt;Per chi lavora come freelance PHP su progetti Symfony, questi miglioramenti si traducono in codice più robusto, meno ore di debugging e applicazioni che si comportano in modo più prevedibile in produzione. L'upgrade alla 8.1 e un investimento minimo (nessun breaking change) con un ritorno tangibile sulla qualità del codice.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://iadicola.it/articoli/messenger-json-path-symfony-81-miglioramenti-pratici?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Leggi l'articolo completo su iadicola.it&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>symfony</category>
      <category>backend</category>
      <category>performance</category>
    </item>
    <item>
      <title>Filament 5 e Laravel: pannelli admin in meta tempo</title>
      <dc:creator>Dev-Iadicola</dc:creator>
      <pubDate>Thu, 17 Sep 2026 17:00:19 +0000</pubDate>
      <link>https://dev.to/dev_iadicola/filament-5-e-laravel-pannelli-admin-in-meta-tempo-448g</link>
      <guid>https://dev.to/dev_iadicola/filament-5-e-laravel-pannelli-admin-in-meta-tempo-448g</guid>
      <description>&lt;h2&gt;
  
  
  Cos e Filament e perché e diventato lo standard per i pannelli admin Laravel
&lt;/h2&gt;

&lt;p&gt;Filament e un framework open source per costruire pannelli admin, dashboard e interfacce CRUD sopra Laravel. Non e un template preconfezionato e non e un page builder: e un ecosistema completo di componenti Livewire che generano interfacce professionali a partire dal codice PHP, senza scrivere HTML, CSS o JavaScript manualmente.&lt;/p&gt;

&lt;p&gt;La filosofia di Filament e chiara: lo sviluppatore dichiara cosa vuole in PHP e il framework si occupa del rendering, della reattivita e dell esperienza utente. Questo approccio riduce drasticamente i tempi di sviluppo e mantiene il codice manutenibile, perché tutto vive in classi PHP con una struttura prevedibile.&lt;/p&gt;

&lt;p&gt;Con la versione 5, Filament compie un salto di maturita significativo. Il redesign dell architettura interna porta miglioramenti concreti in performance, estensibilita e developer experience. Il supporto nativo per Laravel 12 e 13 garantisce compatibilità con le versioni più recenti del framework, mentre il nuovo sistema di rendering sfrutta il lazy loading dei componenti per ridurre il tempo di caricamento delle pagine più complesse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cosa cambia concretamente con Filament 5
&lt;/h2&gt;

&lt;p&gt;Le novità della versione 5 non sono cosmetiche. Ogni cambiamento risolve problemi reali che gli sviluppatori affrontavano con la v4.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compatibilità piena con Laravel 12/13 e Livewire 3.x&lt;/strong&gt; — nessun workaround necessario, tutto funziona out of the box con le ultime versioni di Laravel e Livewire&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rendering più veloce con lazy loading&lt;/strong&gt; — i componenti vengono caricati solo quando visibili nel viewport, riducendo il tempo di primo rendering del 40-60% su pagine con molti widget&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sistema di temi basato su CSS custom properties&lt;/strong&gt; — personalizzare colori, font e spacing non richiede più la ricompilazione degli asset, basta cambiare le variabili CSS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action modali con wizard multi-step&lt;/strong&gt; — le azioni che richiedono più passaggi (conferma, raccolta dati, preview) si gestiscono con wizard integrati nelle modal, senza pagine dedicate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plugin ecosystem maturo&lt;/strong&gt; — oltre 200 pacchetti community disponibili, con un sistema di registrazione plugin più pulito e documentato&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Miglioramenti al table builder&lt;/strong&gt; — nuovi tipi di colonne, filtri più potenti e supporto nativo per l export in background di grandi dataset&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form builder potenziato&lt;/strong&gt; — nuovi componenti come il color picker avanzato, il markdown editor e il file upload con drag and drop multiplo&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Come Filament 5 accelera lo sviluppo di un pannello admin
&lt;/h2&gt;

&lt;p&gt;Il vantaggio principale di Filament non e solo la velocità iniziale, ma la velocità di iterazione. Quando il cliente chiede una modifica — una colonna in più nella tabella, un filtro nuovo, un campo nel form — la modifica si fa in poche righe di PHP, senza toccare frontend, senza scrivere query SQL, senza gestire stato JavaScript.&lt;/p&gt;

&lt;p&gt;Un esempio concreto: per aggiungere un campo "priorità" a una risorsa ordini, servono tre passaggi. Primo, aggiungere la colonna nel database con una migration. Secondo, aggiungere il campo nel form della Resource con &lt;code&gt;Select::make('priority')-&amp;gt;options([...])&lt;/code&gt;. Terzo, aggiungere la colonna nella tabella con &lt;code&gt;TextColumn::make('priority')-&amp;gt;badge()&lt;/code&gt;. Tempo totale: 5 minuti, incluso il test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Il confronto con lo sviluppo tradizionale
&lt;/h3&gt;

&lt;p&gt;Senza Filament, lo stesso pannello admin richiederebbe: progettazione del layout HTML, integrazione di un framework CSS, sviluppo dei componenti JavaScript per tabelle interattive, filtri e ordinamento, creazione dei form con validazione client-side e server-side, gestione delle rotte e dei controller, implementazione dell autenticazione e dei permessi. Settimane di lavoro per funzionalita che Filament offre in ore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quando ha senso usare Filament 5
&lt;/h2&gt;

&lt;p&gt;Filament e la scelta giusta quando il progetto richiede un pannello admin strutturato con queste caratteristiche:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gestione risorse CRUD&lt;/strong&gt; — tabelle con ricerca, filtri, ordinamento e azioni in bulk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form complessi&lt;/strong&gt; — campi dinamici, relazioni, upload file, editor rich text&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dashboard con metriche&lt;/strong&gt; — KPI, grafici, tabelle riepilogative aggiornate in tempo reale&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ruoli e permessi&lt;/strong&gt; — accesso differenziato per tipo di utente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-tenancy&lt;/strong&gt; — più aziende o clienti sullo stesso applicativo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Non ha senso usare Filament per landing page, siti vetrina o applicazioni dove il pannello admin e un semplice CRUD con due tabelle. In quei casi, un controller Laravel con qualche view Blade e più che sufficiente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Filament nel contesto freelance
&lt;/h3&gt;

&lt;p&gt;Come sviluppatore freelance PHP, Filament 5 ha cambiato il modo in cui affronto i preventivi. Dove prima stimavo 3-4 settimane per un pannello admin completo, ora stimo 1-2 settimane con un risultato qualitativamente superiore. Il cliente ottiene un interfaccia professionale, reattiva e mobile-friendly senza costi aggiuntivi di design o sviluppo frontend.&lt;/p&gt;

&lt;p&gt;Il risparmio di tempo si traduce in margini migliori sui progetti e nella possibilita di dedicare più ore alla logica di business specifica del cliente — che e dove si crea il vero valore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Risorse per iniziare con Filament 5
&lt;/h2&gt;

&lt;p&gt;La documentazione ufficiale di Filament e tra le migliori nell ecosistema Laravel: completa, con esempi pratici e organizzata per caso d uso. Il sito &lt;strong&gt;filamentphp.com&lt;/strong&gt; include una sezione dedicata ai plugin, un marketplace di temi e una community Discord attiva con migliaia di sviluppatori.&lt;/p&gt;

&lt;p&gt;Per chi arriva da zero, il consiglio e partire dalla guida "Getting Started" e costruire una Resource completa seguendo il tutorial. In meno di un ora si ha un pannello funzionante con tabella, form e autenticazione — la base per capire come Filament ragiona e come estenderlo per le proprie esigenze.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://iadicola.it/articoli/filament-5-e-laravel-pannelli-admin-in-meta-tempo?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Leggi l'articolo completo su iadicola.it&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>filament</category>
      <category>laravel</category>
      <category>admin</category>
    </item>
    <item>
      <title>Anatomia del bootstrap: come Mvc.php orchestra una richiesta</title>
      <dc:creator>Dev-Iadicola</dc:creator>
      <pubDate>Wed, 16 Sep 2026 22:50:08 +0000</pubDate>
      <link>https://dev.to/dev_iadicola/anatomia-del-bootstrap-come-mvcphp-orchestra-una-richiesta-ami</link>
      <guid>https://dev.to/dev_iadicola/anatomia-del-bootstrap-come-mvcphp-orchestra-una-richiesta-ami</guid>
      <description>&lt;h2&gt;
  
  
  Il punto di ingresso: index.php
&lt;/h2&gt;

&lt;p&gt;Tutto inizia da &lt;code&gt;index.php&lt;/code&gt;, un file di poche righe che fa tre cose: carica l'autoloader di Composer, legge la configurazione (file &lt;code&gt;.env&lt;/code&gt; e directory &lt;code&gt;config/&lt;/code&gt;), e istanzia &lt;code&gt;Mvc&lt;/code&gt; passandogli la &lt;code&gt;ConfigCollection&lt;/code&gt;. Poi chiama &lt;code&gt;$mvc-&amp;gt;run()&lt;/code&gt; e la richiesta prende vita.&lt;/p&gt;

&lt;p&gt;Questa separazione tra costruzione e avvio e intenzionale. Il costruttore prepara gli oggetti fondamentali — Request, Response, View, Router — senza effetti collaterali. Il metodo &lt;code&gt;run()&lt;/code&gt; attiva i provider, connette il database, e risolve la richiesta. Se qualcosa va storto nella fase di boot, il framework può reagire prima di tentare di risolvere una route.&lt;/p&gt;

&lt;h2&gt;
  
  
  Il costruttore: preparare il terreno
&lt;/h2&gt;

&lt;p&gt;Il costruttore di &lt;code&gt;Mvc&lt;/code&gt; inizializza gli error handler per primi. &lt;code&gt;NativeErrorProvider&lt;/code&gt; registra un handler PHP che intercetta errori e warning nativi e li scrive nel file &lt;code&gt;app.log&lt;/code&gt;. Subito dopo, &lt;code&gt;WhoopsProvider&lt;/code&gt; registra Whoops come exception handler — in modalita sviluppo, Whoops fornisce stack trace dettagliati e interattivi nel browser; in produzione viene disattivato a favore di pagine di errore pulite.&lt;/p&gt;

&lt;p&gt;L'ordine conta: gli error handler devono essere attivi prima di qualsiasi altra inizializzazione. Se il database fallisce o una configurazione e errata, vogliamo un messaggio di errore leggibile, non un fatal error di PHP.&lt;/p&gt;

&lt;p&gt;Poi vengono creati gli oggetti HTTP. &lt;code&gt;Request&lt;/code&gt; incapsula la richiesta corrente: metodo, URI, parametri GET/POST, header, body. &lt;code&gt;View&lt;/code&gt; riceve il riferimento a &lt;code&gt;Mvc&lt;/code&gt; per accedere alla configurazione durante il rendering. &lt;code&gt;Response&lt;/code&gt; riceve la &lt;code&gt;View&lt;/code&gt; per poter renderizzare le pagine. &lt;code&gt;Router&lt;/code&gt; riceve l'intero &lt;code&gt;Mvc&lt;/code&gt; perché deve orchestrare la risoluzione delle route e il dispatch ai controller.&lt;/p&gt;

&lt;p&gt;Infine, &lt;code&gt;self::$mvc = $this&lt;/code&gt; rende l'istanza accessibile globalmente. La funzione helper &lt;code&gt;mvc()&lt;/code&gt; restituisce &lt;code&gt;Mvc::$mvc&lt;/code&gt;, permettendo a qualsiasi parte del codice di accedere a Request, Response, Config e agli altri servizi senza dependency injection esplicita. E un Service Locator — un compromesso pragmatico: non ha l'eleganza della pura DI, ma evita di passare sei parametri a ogni costruttore in un framework dove il container non e un full-blown DI container.&lt;/p&gt;

&lt;h2&gt;
  
  
  La sequenza di boot in run()
&lt;/h2&gt;

&lt;p&gt;Il metodo &lt;code&gt;run()&lt;/code&gt; avvia i servizi nell'ordine in cui dipendono l'uno dall'altro. Ogni step ha una ragione precisa per la sua posizione nella sequenza:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SessionStorage&lt;/strong&gt; — primo, perché tutto il resto (CSRF, auth, flash messages) dipende dalla sessione. Il singleton configura cookie sicuri (HttpOnly, Strict mode, Secure su HTTPS, SameSite=Lax) e avvia la sessione PHP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EncryptionService&lt;/strong&gt; — secondo, perché valida la &lt;code&gt;APP_KEY&lt;/code&gt; immediatamente. Se manca o e malformata, l'applicazione si ferma qui con un messaggio chiaro, prima di qualsiasi query al database o rendering di view&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DatabaseProvider&lt;/strong&gt; — crea la connessione PDO attraverso il &lt;code&gt;DatabaseDriverFactory&lt;/code&gt;. Se la connessione fallisce, il provider gestisce l'errore in base all'ambiente: in debug mostra l'eccezione, in produzione redirige a una pagina di errore. Il PDO viene salvato in &lt;code&gt;$this-&amp;gt;pdo&lt;/code&gt; per essere accessibile globalmente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ORM Runtime&lt;/strong&gt; — riceve il PDO e il nome del driver (mysql, pgsql, sqlite, mariadb). Questo registry e il punto di verità per tutti i componenti ORM: modelli, query builder, migrazioni. Separarlo dal DatabaseProvider permette di cambiare driver senza modificare il codice ORM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CacheManager&lt;/strong&gt; — inizializzato con la configurazione da &lt;code&gt;config/cache.php&lt;/code&gt;. Supporta cache file-based con invalidazione per tag (tabella). Deve venire dopo il database perché alcune operazioni di cache possono richiedere query&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SmtpProvider&lt;/strong&gt; — carica le credenziali SMTP dall'ambiente e crea il trasporto mail. Viene dopo il database perché in alcuni scenari i template email possono accedere a dati dal database&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CsrfService&lt;/strong&gt; — ultimo prima del routing, genera il token CSRF se non ne esiste uno in sessione. Dipende da SessionStorage (per salvare il token) e da EncryptionService (per la chiave HMAC)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Risoluzione della route e dispatch
&lt;/h2&gt;

&lt;p&gt;Dopo il boot dei provider, &lt;code&gt;$this-&amp;gt;router-&amp;gt;resolve()&lt;/code&gt; prende il controllo. Il Router legge il metodo HTTP e l'URI dalla Request, cerca un match nella route collection (caricata dagli attributi dei controller o dalla cache), applica i middleware globali e poi quelli specifici della route, e infine chiama il metodo del controller.&lt;/p&gt;

&lt;p&gt;L'intera risoluzione e avvolta in un &lt;code&gt;try/catch&lt;/code&gt; per &lt;code&gt;Throwable&lt;/code&gt;. Se il controller o un middleware lanciano un'eccezione, &lt;code&gt;ExceptionHandler::handle()&lt;/code&gt; la intercetta, la mappa a un codice HTTP appropriato (404 per &lt;code&gt;NotFoundException&lt;/code&gt;, 422 per &lt;code&gt;ValidationException&lt;/code&gt;, 401 per &lt;code&gt;UnauthorizedException&lt;/code&gt;), e genera la risposta di errore — JSON per le API, pagina HTML per il web.&lt;/p&gt;

&lt;p&gt;Dopo la risoluzione (riuscita o fallita), &lt;code&gt;$this-&amp;gt;response-&amp;gt;send()&lt;/code&gt; invia gli header HTTP e il body al client. La Response accumula header e contenuto durante tutto il ciclo, e li emette in un unico momento alla fine. Questo permette ai middleware di modificare la risposta anche dopo che il controller ha scritto il suo output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Il pattern Provider
&lt;/h2&gt;

&lt;p&gt;I Provider sono classi con un metodo &lt;code&gt;register()&lt;/code&gt; che incapsulano la logica di inizializzazione di un servizio. &lt;code&gt;DatabaseProvider&lt;/code&gt; gestisce la connessione PDO con error handling specifico per ambiente. &lt;code&gt;SmtpProvider&lt;/code&gt; configura il trasporto mail. &lt;code&gt;WhoopsProvider&lt;/code&gt; registra l'exception handler.&lt;/p&gt;

&lt;p&gt;Il vantaggio del pattern Provider e l'isolamento: se la configurazione SMTP cambia, modifico solo &lt;code&gt;SmtpProvider&lt;/code&gt;. Se aggiungo un nuovo servizio (un client Redis, un message broker), creo un nuovo Provider e lo inserisco nella sequenza di boot al punto giusto. Ogni provider sa come inizializzare il suo servizio e come gestire i fallimenti — il &lt;code&gt;run()&lt;/code&gt; non deve preoccuparsi dei dettagli.&lt;/p&gt;

&lt;h2&gt;
  
  
  Perché non un vero DI Container
&lt;/h2&gt;

&lt;p&gt;Framework come Laravel e Symfony usano container di dependency injection completi con binding, risoluzione automatica e autowiring. Soft PHP MVC usa un approccio più semplice: un Service Locator (&lt;code&gt;Mvc::$mvc&lt;/code&gt;) con provider manuali. La ragione e pragmatica: un DI container aggiunge complessità che si giustifica in applicazioni con centinaia di servizi e team di decine di sviluppatori. In un framework personale con una dozzina di servizi, sapere esattamente cosa viene inizializzato, in che ordine e perché, vale più dell'eleganza del container automatico.&lt;/p&gt;

&lt;p&gt;Il compromesso e consapevole: il codice dipende dall'helper &lt;code&gt;mvc()&lt;/code&gt; invece che da interfacce iniettate. Se un giorno servira un container, la migrazione sara graduale — i provider già incapsulano la logica di creazione, basterebbe registrarli in un container invece che chiamarli manualmente nel &lt;code&gt;run()&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://iadicola.it/articoli/anatomia-del-bootstrap-come-mvc-php-orchestra-una-richiesta?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Leggi l'articolo completo su iadicola.it&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>architettura</category>
      <category>bootstrap</category>
      <category>php</category>
    </item>
    <item>
      <title>CRUD con Filament 5: da migration a pannello in 15 minuti</title>
      <dc:creator>Dev-Iadicola</dc:creator>
      <pubDate>Wed, 16 Sep 2026 21:45:12 +0000</pubDate>
      <link>https://dev.to/dev_iadicola/crud-con-filament-5-da-migration-a-pannello-in-15-minuti-o15</link>
      <guid>https://dev.to/dev_iadicola/crud-con-filament-5-da-migration-a-pannello-in-15-minuti-o15</guid>
      <description>&lt;h2&gt;
  
  
  Il flusso di lavoro CRUD con Filament 5: dalla migration al pannello funzionante
&lt;/h2&gt;

&lt;p&gt;Con Filament 5 il percorso per creare un interfaccia CRUD completa e lineare e ripetibile. Si parte dalla migration del database, si crea il model Eloquent e poi si genera la Resource con un comando Artisan. Il risultato e una pagina di listing con tabella interattiva, filtri e ricerca, più pagine di creazione e modifica con form validato — tutto generato dal codice PHP senza toccare una riga di HTML o JavaScript.&lt;/p&gt;

&lt;p&gt;Questo flusso non e solo veloce la prima volta: e il modo in cui si lavora costantemente con Filament. Ogni nuova entita del progetto segue lo stesso pattern, il che rende il codice prevedibile e facile da manutenere anche per chi si aggiunge al team mesi dopo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cosa ottieni immediatamente con una Resource Filament
&lt;/h2&gt;

&lt;p&gt;Generare una Resource con &lt;code&gt;php artisan make:filament-resource&lt;/code&gt; produce una struttura completa che include già tutto il necessario per un CRUD professionale:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tabella con colonne sortabili&lt;/strong&gt; — ogni colonna e cliccabile per ordinare i dati in modo ascendente o discendente, con indicatore visivo dell ordinamento attivo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ricerca globale e per campo&lt;/strong&gt; — la barra di ricerca cerca su tutti i campi configurati come searchable, con debounce automatico per non sovraccaricare il database&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filtri per campo&lt;/strong&gt; — select, date range, toggle e filtri custom che si applicano in tempo reale grazie a Livewire&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form con campi tipizzati&lt;/strong&gt; — text input, textarea, select, date picker, file upload, rich editor, toggle, radio, checkbox group e molti altri&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validazione integrata&lt;/strong&gt; — usa le stesse regole di validazione di Laravel, dichiarate direttamente nel form schema&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azioni in bulk&lt;/strong&gt; — seleziona più record e applica azioni come elimina, esporta o cambia stato con un click&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Soft delete e restore&lt;/strong&gt; — con un semplice toggle nella Resource, i record eliminati vengono nascosti ma recuperabili&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paginazione configurabile&lt;/strong&gt; — numero di record per pagina, stile di paginazione e contatore totale&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Esempio pratico: gestionale ordini da zero
&lt;/h2&gt;

&lt;p&gt;Vediamo un caso concreto. Il cliente ha bisogno di un gestionale ordini con queste funzionalita: lista ordini con filtri per stato e data, dettaglio ordine con dati cliente e prodotti, modifica stato e note, export in CSV.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: migration e model
&lt;/h3&gt;

&lt;p&gt;Si crea la migration con i campi necessari: &lt;code&gt;customer_id&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;total&lt;/code&gt;, &lt;code&gt;notes&lt;/code&gt;, &lt;code&gt;created_at&lt;/code&gt;. Il model &lt;code&gt;Order&lt;/code&gt; definisce le relazioni con &lt;code&gt;Customer&lt;/code&gt; e &lt;code&gt;OrderItem&lt;/code&gt;, i cast per i campi monetari e gli scope per i filtri.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: generare la Resource
&lt;/h3&gt;

&lt;p&gt;Il comando &lt;code&gt;php artisan make:filament-resource Order --generate&lt;/code&gt; analizza il model e genera automaticamente la Resource con form e tabella basati sui campi del database. Il flag &lt;code&gt;--generate&lt;/code&gt; e il punto di partenza: produce codice funzionante che poi si personalizza.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: personalizzare la tabella
&lt;/h3&gt;

&lt;p&gt;Nella classe &lt;code&gt;OrderResource&lt;/code&gt;, il metodo &lt;code&gt;table()&lt;/code&gt; definisce le colonne visibili. Si aggiungono colonne calcolate come il nome del cliente dalla relazione, badge colorati per lo stato dell ordine, formattazione monetaria per il totale e filtri per data e stato. Il tutto con metodi chainable che rendono il codice leggibile e dichiarativo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: personalizzare il form
&lt;/h3&gt;

&lt;p&gt;Il metodo &lt;code&gt;form()&lt;/code&gt; definisce i campi di creazione e modifica. Si configura un select con ricerca per il cliente, un select per lo stato con colori associati, un campo monetario per il totale e un textarea per le note. La validazione si aggiunge inline: &lt;code&gt;-&amp;gt;required()&lt;/code&gt;, &lt;code&gt;-&amp;gt;numeric()&lt;/code&gt;, &lt;code&gt;-&amp;gt;min(0)&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gestione delle relazioni nel CRUD
&lt;/h2&gt;

&lt;p&gt;Uno degli aspetti più potenti di Filament e la gestione delle relazioni Eloquent direttamente nel pannello admin. Non serve scrivere controller separati per le entita correlate: tutto si gestisce dalla Resource principale.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BelongsTo&lt;/strong&gt; — select con ricerca che carica i record dalla tabella correlata, con possibilita di creare nuovi record inline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HasMany&lt;/strong&gt; — relation manager che mostra una tabella dei record figli con CRUD completo nella stessa pagina&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BelongsToMany&lt;/strong&gt; — gestione della tabella pivot con attach, detach e sync, con possibilita di aggiungere campi extra alla pivot&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MorphMany&lt;/strong&gt; — supporto per relazioni polimorfiche, utili per commenti, tag e media associati a più entita&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nel caso del gestionale ordini, la relazione &lt;code&gt;HasMany&lt;/code&gt; con &lt;code&gt;OrderItem&lt;/code&gt; permette di gestire le righe d ordine direttamente nella pagina dell ordine, con tabella dedicata e possibilita di aggiungere, modificare ed eliminare righe senza navigare via dalla pagina.&lt;/p&gt;

&lt;h2&gt;
  
  
  Il vantaggio reale: la velocità di iterazione
&lt;/h2&gt;

&lt;p&gt;Il vero punto di forza del CRUD con Filament non e solo la velocità di setup iniziale — che comunque e notevole — ma la velocità con cui si risponde alle richieste di modifica del cliente.&lt;/p&gt;

&lt;p&gt;Il cliente chiede una nuova colonna nella tabella? Una riga di codice. Un filtro aggiuntivo? Tre righe. Un campo nel form con validazione? Cinque righe. Un export CSV? Un plugin da installare e configurare in 10 minuti.&lt;/p&gt;

&lt;p&gt;Questa velocità di iterazione cambia la dinamica del rapporto con il cliente. Invece di accumulare richieste per la prossima release, si implementano le modifiche in tempo reale durante la call. Il cliente vede il risultato subito, conferma o corregge il tiro, e si va avanti. Meno email, meno malintesi, meno ore buttate su specifiche fraintese.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quanto codice serve davvero?
&lt;/h3&gt;

&lt;p&gt;Per dare un idea concreta: un CRUD completo per una risorsa con 10 campi, relazioni, filtri e azioni richiede mediamente 80-120 righe di PHP. Lo stesso risultato costruito a mano con controller, form request, view Blade e JavaScript richiederebbe 500-800 righe distribuite su 8-10 file. Il rapporto e circa 1 a 6 in termini di codice da scrivere e manutenere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best practice per CRUD scalabili con Filament
&lt;/h2&gt;

&lt;p&gt;Dopo diversi progetti con Filament, queste sono le pratiche che fanno la differenza sulla manutenibilità a lungo termine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Usare gli Enum per gli stati&lt;/strong&gt; — invece di stringhe sparse nel codice, definire un PHP Enum per ogni campo con valori fissi. Filament supporta gli Enum nativamente nei select e nei badge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separare la logica pesante in Action&lt;/strong&gt; — le operazioni complesse (invio email, calcoli, integrazioni esterne) vanno in classi Action dedicate, non inline nella Resource&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configurare i global scope con attenzione&lt;/strong&gt; — se il model ha global scope (es. soft delete, tenant), assicurarsi che la Resource li gestisca correttamente con i filtri appropriati&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testare le Resource&lt;/strong&gt; — Filament fornisce helper per i test: &lt;code&gt;assertCanSeeTableRecords&lt;/code&gt;, &lt;code&gt;assertFormFieldExists&lt;/code&gt; e simili rendono i test delle Resource veloci da scrivere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Queste pratiche non sono specifiche di Filament, ma la struttura del framework le rende naturali da applicare. Il codice dichiarativo delle Resource spinge verso un design pulito, dove ogni pezzo ha il suo posto e le responsabilità sono chiare.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://iadicola.it/articoli/crud-con-filament-5-da-migration-a-pannello-in-15-minuti?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Leggi l'articolo completo su iadicola.it&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>filament</category>
      <category>laravel</category>
      <category>crud</category>
    </item>
    <item>
      <title>Dashboard personalizzate con Filament 5 e widget Livewire</title>
      <dc:creator>Dev-Iadicola</dc:creator>
      <pubDate>Wed, 16 Sep 2026 20:40:07 +0000</pubDate>
      <link>https://dev.to/dev_iadicola/dashboard-personalizzate-con-filament-5-e-widget-livewire-b6e</link>
      <guid>https://dev.to/dev_iadicola/dashboard-personalizzate-con-filament-5-e-widget-livewire-b6e</guid>
      <description>&lt;h2&gt;
  
  
  Filament oltre il CRUD: dashboard operative in tempo reale
&lt;/h2&gt;

&lt;p&gt;Filament non serve solo per gestire tabelle e form. Uno degli aspetti più sottovalutati del framework e il sistema di widget, che permette di costruire dashboard operative con statistiche, grafici e dati aggregati che si aggiornano in tempo reale grazie a Livewire. Per molti clienti, la dashboard e la pagina più importante dell intero pannello admin: e quella che aprono ogni mattina per capire come sta andando il business.&lt;/p&gt;

&lt;p&gt;Ogni widget in Filament e un componente PHP autonomo che definisce i propri dati, il layout e la logica di aggiornamento. Si compongono nella dashboard come blocchi, senza toccare HTML. La potenza sta nella semplicità: dichiari i dati in PHP e Filament si occupa del rendering, della reattivita e del layout responsive.&lt;/p&gt;

&lt;h2&gt;
  
  
  I tipi di widget disponibili in Filament 5
&lt;/h2&gt;

&lt;p&gt;Filament 5 mette a disposizione quattro tipi di widget principali, ognuno ottimizzato per un caso d uso specifico. Combinandoli si costruiscono dashboard che coprono qualsiasi esigenza informativa.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stat widget: KPI e metriche chiave
&lt;/h3&gt;

&lt;p&gt;Il widget più usato nelle dashboard business. Mostra un valore numerico con label, icona opzionale e indicatore di trend (percentuale di variazione rispetto al periodo precedente). Ideale per fatturato, numero ordini, utenti attivi, ticket aperti e qualsiasi metrica che il cliente vuole monitorare a colpo d occhio.&lt;/p&gt;

&lt;p&gt;Ogni stat widget può avere un colore che cambia in base al valore — verde se il trend e positivo, rosso se negativo — e un link che porta alla pagina di dettaglio per approfondire il dato.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chart widget: grafici interattivi con Chart.js
&lt;/h3&gt;

&lt;p&gt;Filament integra Chart.js per generare grafici a linee, barre, torta, area e radar. Il widget chart si dichiara in PHP specificando i dataset e le label, e Filament si occupa del rendering JavaScript. I grafici sono interattivi: hover per il dettaglio, click per filtrare, zoom su periodi specifici.&lt;/p&gt;

&lt;p&gt;Per un e-commerce, un grafico a linee con l andamento del fatturato giornaliero degli ultimi 30 giorni, sovrapposto allo stesso periodo dell anno precedente, si implementa in una classe PHP di 30-40 righe. Senza Filament, lo stesso grafico richiederebbe un controller per i dati, una chiamata AJAX, la configurazione di Chart.js nel frontend e la gestione del layout responsive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Table widget: tabelle compatte per dati recenti
&lt;/h3&gt;

&lt;p&gt;Una versione ridotta del table builder di Filament, pensata per mostrare dati tabulari direttamente nella dashboard. Perfetta per gli ultimi ordini, i ticket più urgenti, i prodotti in esaurimento o qualsiasi lista che richiede attenzione immediata.&lt;/p&gt;

&lt;p&gt;Il table widget supporta le stesse colonne e formattazioni del table builder completo, ma in un formato compatto che si integra nel layout della dashboard senza dominare la pagina.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom widget: componenti Livewire personalizzati
&lt;/h3&gt;

&lt;p&gt;Quando i widget standard non bastano, si crea un custom widget che e a tutti gli effetti un componente Livewire. Si ha accesso completo al rendering Blade, alla reattivita di Livewire e a qualsiasi libreria JavaScript necessaria. Questo e utile per mappe interattive, timeline di eventi, feed in tempo reale o integrazioni con servizi esterni.&lt;/p&gt;

&lt;h2&gt;
  
  
  Esempio reale: dashboard per un e-commerce
&lt;/h2&gt;

&lt;p&gt;Un caso concreto che ho implementato per un cliente. La richiesta: una dashboard che mostri la situazione del business in tempo reale, senza bisogno di aprire report o fogli di calcolo.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Riga superiore con 4 stat widget&lt;/strong&gt; — fatturato giornaliero con trend rispetto alla settimana precedente, ordini del giorno, carrelli abbandonati e tasso di conversione&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grafico a linee&lt;/strong&gt; — andamento fatturato ultimi 30 giorni con confronto anno precedente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grafico a torta&lt;/strong&gt; — distribuzione ordini per stato (in lavorazione, spediti, consegnati, resi)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tabella ultimi 10 ordini&lt;/strong&gt; — con nome cliente, importo, stato e link al dettaglio&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alert prodotti in esaurimento&lt;/strong&gt; — tabella dei prodotti con stock sotto la soglia minima, con link diretto alla pagina di modifica&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Il cliente apre il browser ogni mattina e ha subito la fotografia completa del business. Nessun export, nessun foglio di calcolo, nessuna email con report allegati. I dati sono sempre aggiornati e la dashboard si aggiorna automaticamente ogni 30 secondi grazie al polling di Livewire.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aggiornamento in tempo reale: polling e WebSocket
&lt;/h2&gt;

&lt;p&gt;Filament offre due strategie per mantenere i widget aggiornati. La prima e il polling: ogni widget può definire un intervallo di aggiornamento (es. ogni 10 secondi) e Livewire si occupa di fare la richiesta al server e aggiornare il DOM. Semplice e funziona senza configurazione aggiuntiva.&lt;/p&gt;

&lt;p&gt;La seconda strategia e l integrazione con Laravel Echo e WebSocket per aggiornamenti push in tempo reale. Quando un evento viene dispatchato — un nuovo ordine, un pagamento confermato — il widget si aggiorna istantaneamente senza aspettare il polling. Questa strategia e ideale per dashboard di monitoraggio operativo dove anche pochi secondi di ritardo contano.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quale strategia scegliere?
&lt;/h3&gt;

&lt;p&gt;Il polling e sufficiente per la maggior parte dei casi: dashboard business, report giornalieri, metriche che cambiano lentamente. I WebSocket servono quando i dati cambiano frequentemente e l utente ha bisogno di vederli subito: monitoraggio ordini in tempo reale, chat di supporto, sistemi di alerting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Organizzazione delle dashboard: pagine multiple e filtri globali
&lt;/h2&gt;

&lt;p&gt;Un pannello admin complesso può avere bisogno di più dashboard: una per le vendite, una per il magazzino, una per il marketing. Filament supporta pagine dashboard multiple, ognuna con i propri widget e il proprio layout. Il menu laterale del pannello mostra le varie dashboard come voci separate.&lt;/p&gt;

&lt;p&gt;I filtri globali permettono di cambiare il periodo temporale — oggi, ultima settimana, ultimo mese, custom range — e tutti i widget della dashboard si aggiornano di conseguenza. Questo evita di dover implementare filtri individuali per ogni widget e garantisce consistenza nei dati mostrati.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance delle dashboard con molti widget
&lt;/h2&gt;

&lt;p&gt;Una dashboard con 10-15 widget può diventare lenta se ogni widget esegue query pesanti al caricamento. Filament 5 risolve questo problema con il lazy loading: i widget vengono caricati in modo asincrono, mostrando uno skeleton placeholder mentre i dati vengono recuperati. L utente vede la pagina subito e i widget si popolano man mano.&lt;/p&gt;

&lt;p&gt;Per query particolarmente pesanti — aggregazioni su milioni di record, join complessi — il consiglio e usare tabelle materializzate o cache Redis con invalidazione basata su eventi. Il widget legge dalla cache e la cache viene aggiornata quando i dati cambiano. Il risultato: dashboard che caricano in meno di un secondo anche con dataset enormi.&lt;/p&gt;

&lt;p&gt;In definitiva, le dashboard di Filament 5 trasformano un pannello admin da semplice strumento di gestione dati a centro di comando operativo. Il cliente smette di chiedere report via email e inizia a prendere decisioni basate su dati aggiornati in tempo reale — e questo e il valore più grande che un pannello admin può offrire.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://iadicola.it/articoli/dashboard-personalizzate-con-filament-5-e-widget-livewire?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Leggi l'articolo completo su iadicola.it&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>filament</category>
      <category>laravel</category>
      <category>dashboard</category>
    </item>
    <item>
      <title>La filosofia Unix nella CLI di un framework PHP</title>
      <dc:creator>Dev-Iadicola</dc:creator>
      <pubDate>Wed, 16 Sep 2026 19:35:11 +0000</pubDate>
      <link>https://dev.to/dev_iadicola/la-filosofia-unix-nella-cli-di-un-framework-php-13k8</link>
      <guid>https://dev.to/dev_iadicola/la-filosofia-unix-nella-cli-di-un-framework-php-13k8</guid>
      <description>&lt;h2&gt;
  
  
  Do one thing and do it well
&lt;/h2&gt;

&lt;p&gt;Nel 1978 Doug McIlroy sintetizzo la filosofia Unix in tre righe. La prima — &lt;em&gt;fai una cosa sola e falla bene&lt;/em&gt; — e forse il principio di design più citato e meno applicato nella storia del software. E facile da capire, difficile da rispettare: la tentazione di aggiungere "un'altra piccola cosa" a un componente e costante, e prima che te ne accorga hai un oggetto che fa tutto e non fa niente bene.&lt;/p&gt;

&lt;p&gt;Quando ho riscritto la CLI di Soft PHP MVC, questa tensione era ovunque. I vecchi comandi avevano cinque implementazioni diverse per il parsing degli argomenti. Ogni comando leggeva le opzioni a modo suo, gestiva gli errori a modo suo, produceva output a modo suo. Funzionava, ma ogni nuovo comando richiedeva di reinventare le stesse soluzioni — o peggio, di copiare codice da un comando esistente sperando che reggesse.&lt;/p&gt;

&lt;p&gt;Il problema non era solo tecnico. Era &lt;strong&gt;concettuale&lt;/strong&gt;: mancava un linguaggio condiviso tra i comandi. Senza una base comune, ogni sviluppatore (anche quando lo sviluppatore sei solo tu, sei mesi dopo) deve decifrare le convenzioni locali di quel singolo comando prima di poterlo modificare. La filosofia Unix non e solo efficienza — e comunicazione.&lt;/p&gt;

&lt;h2&gt;
  
  
  #[CliCommand]: dare un nome alle cose
&lt;/h2&gt;

&lt;p&gt;Ludwig Wittgenstein scrisse che i limiti del linguaggio sono i limiti del mondo. Nel codice, dare un nome esplicito a qualcosa — un attributo, una classe, un metodo — non e solo una questione estetica: e un atto di comprensione. &lt;code&gt;#[CliCommand('migrate:fresh', 'Drop all tables and re-run migrations', group: 'database')]&lt;/code&gt; non e solo metadata: e una dichiarazione di intenti. Il comando sa chi e, cosa fa, e dove appartiene.&lt;/p&gt;

&lt;p&gt;L'uso degli attributi PHP 8.4 per dichiarare i comandi CLI rappresenta una scelta architetturale precisa. A differenza di un file di configurazione YAML o di un array centralizzato, l'attributo &lt;strong&gt;vive accanto al codice che descrive&lt;/strong&gt;. Non c'e disallineamento possibile tra la dichiarazione e l'implementazione: se sposti il file, la dichiarazione si sposta con lui. Se rinomini la classe, il comando resta definito nel posto giusto.&lt;/p&gt;

&lt;p&gt;L'auto-discovery via &lt;code&gt;CommandDiscovery&lt;/code&gt; e il corollario naturale: se ogni comando si dichiara esplicitamente tramite attributi, il framework non ha bisogno di una registrazione manuale. Scansiona, riflette, raccoglie. Il Kernel non mantiene più una lista hardcoded di 25 comandi — la genera da cio che trova. Meno codice da mantenere, meno possibilita di dimenticare una registrazione.&lt;/p&gt;

&lt;h3&gt;
  
  
  Il ruolo della Reflection API
&lt;/h3&gt;

&lt;p&gt;Sotto il cofano, &lt;code&gt;CommandDiscovery&lt;/code&gt; usa la &lt;strong&gt;Reflection API&lt;/strong&gt; di PHP per leggere gli attributi a runtime. Questo e un esempio di &lt;em&gt;metaprogrammazione pragmatica&lt;/em&gt;: il codice ispeziona se stesso per costruire la mappa dei comandi disponibili. Non serve un compilatore separato, non serve un passo di build — il framework si auto-configura ogni volta che parte, leggendo la struttura delle proprie classi.&lt;/p&gt;

&lt;h2&gt;
  
  
  Input e Output: i confini del comando
&lt;/h2&gt;

&lt;p&gt;La classe &lt;code&gt;Input&lt;/code&gt; unifica cinque pattern di parsing in uno solo: argomenti posizionali, flag booleani, coppie chiave-valore, flag corti combinati (&lt;code&gt;-mcs&lt;/code&gt;), lookahead. La classe &lt;code&gt;Output&lt;/code&gt; offre metodi tipizzati — &lt;code&gt;info()&lt;/code&gt;, &lt;code&gt;success()&lt;/code&gt;, &lt;code&gt;error()&lt;/code&gt;, &lt;code&gt;table()&lt;/code&gt; — senza chiamare mai &lt;code&gt;exit()&lt;/code&gt; direttamente. Un comando che non chiama &lt;code&gt;exit()&lt;/code&gt; e un comando testabile.&lt;/p&gt;

&lt;p&gt;Questa separazione ricorda la distinzione kantiana tra fenomeno e noumeno, trasposta nel software: il comando non conosce il "mondo esterno" (lo stdin, lo stdout, il terminale). Conosce solo le astrazioni che Input e Output gli presentano. Potrebbe girare in un terminale, in un test, in un pipe — non gli interessa e non dovrebbe interessargli.&lt;/p&gt;

&lt;h3&gt;
  
  
  Perché i metodi tipizzati contano
&lt;/h3&gt;

&lt;p&gt;La differenza tra &lt;code&gt;echo "Migrazione completata"&lt;/code&gt; e &lt;code&gt;$output-&amp;gt;success('Migrazione completata')&lt;/code&gt; sembra cosmetica, ma ha conseguenze profonde. Il metodo tipizzato &lt;strong&gt;codifica l'intenzione semantica&lt;/strong&gt; del messaggio: success indica un risultato positivo, error un fallimento, info un dato neutro. Questa semantica può essere usata in molti modi: colorare l'output nel terminale, filtrare i log in produzione, formattare i risultati in JSON per un consumatore automatico. Con &lt;code&gt;echo&lt;/code&gt;, il messaggio e solo una stringa — il significato si perde.&lt;/p&gt;

&lt;h2&gt;
  
  
  Command base class: il contratto implicito
&lt;/h2&gt;

&lt;p&gt;La classe astratta &lt;code&gt;Command&lt;/code&gt; stabilisce un lifecycle chiaro: &lt;code&gt;handle(Input, Output): int&lt;/code&gt;. Il codice di ritorno e un intero — 0 per successo, qualsiasi altro valore per errore. E il contratto più semplice possibile, e proprio per questo e il più robusto. Non c'e ambiguita su cosa significhi "il comando e riuscito": restituisce zero.&lt;/p&gt;

&lt;p&gt;Il metodo factory &lt;code&gt;make()&lt;/code&gt; garantisce che ogni comando venga istanziato allo stesso modo. L'help auto-generato legge gli attributi e le definizioni di argomenti e opzioni, eliminando la necessita di scrivere manualmente la documentazione di ogni comando. Se il codice e la documentazione divergono, la documentazione mente — generarla dal codice elimina questa classe di bug.&lt;/p&gt;

&lt;h3&gt;
  
  
  L'help auto-generato come documentazione vivente
&lt;/h3&gt;

&lt;p&gt;Quando esegui &lt;code&gt;php soft help migrate:fresh&lt;/code&gt;, il framework non legge un file markdown o una stringa hardcoded. Legge gli attributi &lt;code&gt;#[CliCommand]&lt;/code&gt;, gli argomenti definiti via &lt;code&gt;addArgument()&lt;/code&gt; e le opzioni definite via &lt;code&gt;addOption()&lt;/code&gt;, e compone l'help screen in tempo reale. Questa e &lt;strong&gt;documentazione vivente&lt;/strong&gt;: non può divergere dal codice perché &lt;em&gt;e&lt;/em&gt; il codice. Un principio che Martin Fowler chiamerebbe "executable specification" — la specifica che si esegue da sola.&lt;/p&gt;

&lt;h2&gt;
  
  
  26 comandi, un solo pattern
&lt;/h2&gt;

&lt;p&gt;Migrare 26 comandi alla nuova architettura non e stato un esercizio di refactoring cosmetico. E stato un esercizio di disciplina: trovare cio che era comune, estrarlo, e lasciare a ogni comando solo cio che lo rende unico. &lt;code&gt;make:model&lt;/code&gt; genera file da stub. &lt;code&gt;migrate:fresh&lt;/code&gt; ricrea il database. &lt;code&gt;key:generate&lt;/code&gt; produce una chiave crittografica. Tre comandi completamente diversi che condividono la stessa infrastruttura senza che questa li vincoli.&lt;/p&gt;

&lt;h3&gt;
  
  
  Elenco dei gruppi di comandi in Soft PHP MVC
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;database&lt;/strong&gt; — migrate, migrate:fresh, migrate:rollback, seed: gestione completa del ciclo di vita del database&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;make&lt;/strong&gt; — make:model, make:controller, make:middleware, make:command: generazione di codice da stub con placeholder&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cache&lt;/strong&gt; — cache:clear, view:clear: gestione della cache applicativa e delle view compilate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;security&lt;/strong&gt; — key:generate, csrf:rotate: operazioni crittografiche e di sicurezza&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;maintenance&lt;/strong&gt; — up, down, serve: gestione dello stato dell'applicazione&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ogni gruppo condivide convenzioni di naming (&lt;code&gt;verbo:risorsa&lt;/code&gt;), stile di output, gestione degli errori. Un nuovo sviluppatore che ha visto un comando sa come funzionano tutti gli altri. Questa prevedibilita e il vero valore della filosofia Unix applicata al codice PHP.&lt;/p&gt;

&lt;p&gt;La filosofia Unix non e solo un principio tecnico. E un'etica del design: rispetta chi verra dopo di te. Un comando che fa una cosa sola, con un'interfaccia chiara e un output prevedibile, e un comando che qualcuno potra usare, estendere e debuggare senza dover leggere tutto il codice del framework. In un'epoca in cui la complessità cresce esponenzialmente, la semplicità e un atto di resistenza — e forse l'unico che ha davvero impatto duraturo.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://iadicola.it/articoli/la-filosofia-unix-nella-cli-di-un-framework-php?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Leggi l'articolo completo su iadicola.it&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>php84</category>
      <category>architettura</category>
      <category>cli</category>
      <category>filosofia</category>
    </item>
    <item>
      <title>Multi-tenancy con Filament 5: un pannello, più aziende</title>
      <dc:creator>Dev-Iadicola</dc:creator>
      <pubDate>Wed, 16 Sep 2026 18:30:07 +0000</pubDate>
      <link>https://dev.to/dev_iadicola/multi-tenancy-con-filament-5-un-pannello-piu-aziende-42ak</link>
      <guid>https://dev.to/dev_iadicola/multi-tenancy-con-filament-5-un-pannello-piu-aziende-42ak</guid>
      <description>&lt;h2&gt;
  
  
  Il problema della multi-tenancy nello sviluppo web
&lt;/h2&gt;

&lt;p&gt;Quando lo stesso applicativo deve servire più aziende o clienti, ogni tenant deve vedere solo i propri dati, avere i propri utenti e potenzialmente un branding diverso. Costruire questa separazione da zero e complesso, soggetto a errori di sicurezza e richiede un architettura pensata fin dal primo giorno. Un errore nello scope delle query significa che un azienda vede i dati di un altra — uno scenario inaccettabile.&lt;/p&gt;

&lt;p&gt;Il problema non e solo tecnico: e anche organizzativo. Ogni tenant può avere esigenze diverse in termini di permessi, workflow e personalizzazione dell interfaccia. Gestire questa variabilita senza che il codice diventi un groviglio di if-else e una sfida architetturale seria.&lt;/p&gt;

&lt;h2&gt;
  
  
  Come Filament 5 risolve la multi-tenancy
&lt;/h2&gt;

&lt;p&gt;Filament 5 ha il supporto multi-tenancy integrato nel core del framework, non come plugin esterno. Ogni panel può essere configurato con un tenant model — tipicamente &lt;code&gt;Team&lt;/code&gt;, &lt;code&gt;Organization&lt;/code&gt; o &lt;code&gt;Company&lt;/code&gt; — e tutte le query vengono automaticamente filtrate per il tenant attivo. Non serve aggiungere &lt;code&gt;where&lt;/code&gt; manuali in ogni query: Filament applica il filtro a livello globale.&lt;/p&gt;

&lt;p&gt;L implementazione si basa su un concetto semplice: l utente appartiene a uno o più tenant tramite una relazione Eloquent, e il pannello filtra tutto in base al tenant selezionato. Il cambio di tenant avviene tramite un menu nel pannello, senza logout e senza perdere il contesto di navigazione.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cosa si ottiene con la multi-tenancy di Filament
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scope automatico su tutte le query&lt;/strong&gt; — ogni Resource, ogni widget, ogni relazione viene automaticamente filtrata per il tenant attivo. Non serve ricordare di aggiungere il filtro: Filament lo fa per te&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Switch tenant senza logout&lt;/strong&gt; — l utente che appartiene a più organizzazioni passa dall una all altra con un click, mantenendo la sessione attiva&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Registrazione tenant con onboarding&lt;/strong&gt; — flusso di creazione nuovo tenant personalizzabile con wizard multi-step per raccogliere i dati iniziali&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permessi per tenant&lt;/strong&gt; — lo stesso utente può avere ruoli diversi in organizzazioni diverse. Admin in un azienda, viewer in un altra&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branding per tenant&lt;/strong&gt; — logo, colori, nome e favicon personalizzati per ogni tenant, senza deployment separati&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Billing e subscription&lt;/strong&gt; — integrazione con sistemi di pagamento per gestire piani e limiti per tenant&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architettura: database condiviso vs separato
&lt;/h2&gt;

&lt;p&gt;La multi-tenancy di Filament supporta entrambi gli approcci, ma con trade-off diversi.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database condiviso con colonna tenant_id
&lt;/h3&gt;

&lt;p&gt;Approccio più comune e semplice da gestire. Tutte le tabelle hanno una colonna &lt;code&gt;team_id&lt;/code&gt; (o equivalente) e Filament applica un global scope su ogni query. Vantaggi: una sola istanza del database, migration centralizzate, backup semplificato. Svantaggi: se lo scope viene dimenticato in una query custom, i dati di un tenant possono fuoriuscire.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database separato per tenant
&lt;/h3&gt;

&lt;p&gt;Ogni tenant ha il proprio database. Isolamento totale dei dati, performance prevedibili per tenant e possibilita di backup e restore individuali. Svantaggi: complessità operativa maggiore, migration da eseguire su ogni database, query cross-tenant impossibili senza logica aggiuntiva. Questo approccio ha senso per SaaS enterprise dove l isolamento dei dati e un requisito contrattuale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configurazione pratica: i passaggi chiave
&lt;/h2&gt;

&lt;p&gt;Configurare la multi-tenancy in Filament 5 richiede pochi passaggi ben definiti:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Creare il model tenant&lt;/strong&gt; — una classe Eloquent come &lt;code&gt;Team&lt;/code&gt; con i campi necessari (nome, slug, logo, impostazioni)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Definire la relazione utente-tenant&lt;/strong&gt; — tipicamente una BelongsToMany attraverso una tabella pivot con ruolo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configurare il panel&lt;/strong&gt; — nel PanelProvider, chiamare &lt;code&gt;-&amp;gt;tenant(Team::class)&lt;/code&gt; per attivare la multi-tenancy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aggiungere il trait ai model&lt;/strong&gt; — ogni model che deve essere filtrato per tenant implementa il trait &lt;code&gt;HasTenantScope&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personalizzare la registrazione&lt;/strong&gt; — opzionalmente, definire un form di registrazione tenant con i campi necessari per l onboarding&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Gestione dei permessi per tenant
&lt;/h3&gt;

&lt;p&gt;Il plugin Shield di Filament si integra perfettamente con la multi-tenancy. Si definiscono ruoli e permessi a livello di tenant, così lo stesso utente può essere amministratore in un organizzazione e avere accesso limitato in un altra. Questo e fondamentale per consulenti, agenzie e professionisti che lavorano con più clienti contemporaneamente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quando serve la multi-tenancy
&lt;/h2&gt;

&lt;p&gt;La multi-tenancy non e sempre necessaria e aggiunge complessità. Ha senso in questi scenari specifici:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SaaS multi-azienda&lt;/strong&gt; — la stessa applicazione venduta a più clienti, ognuno con i propri dati e utenti&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gestionali multi-filiale&lt;/strong&gt; — un azienda con più sedi o divisioni che devono operare in modo indipendente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Piattaforme white-label&lt;/strong&gt; — applicazioni brandizzate diversamente per ogni cliente, con funzionalita e limiti configurabili&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Marketplace con vendor&lt;/strong&gt; — ogni venditore gestisce il proprio catalogo, ordini e clienti in modo separato&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se il progetto serve una sola azienda con un solo set di dati, la multi-tenancy e overkill. In quel caso, un semplice sistema di ruoli e permessi copre le esigenze senza complessità aggiuntiva.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sicurezza e testing nella multi-tenancy
&lt;/h2&gt;

&lt;p&gt;Il rischio più grande in un sistema multi-tenant e il data leaking: un tenant che vede o modifica i dati di un altro. Per questo motivo, il testing diventa critico.&lt;/p&gt;

&lt;p&gt;Filament facilità il testing della multi-tenancy con helper dedicati. Si può simulare l accesso come utente di un tenant specifico e verificare che le query restituiscano solo i dati corretti. E buona pratica scrivere test che tentano esplicitamente di accedere a dati di un altro tenant e verificano che l accesso venga negato.&lt;/p&gt;

&lt;p&gt;A livello infrastrutturale, e consigliabile usare middleware dedicati che verificano il tenant attivo a ogni richiesta e monitorare i log per accessi anomali. La sicurezza della multi-tenancy non e un aspetto da dare per scontato: va verificata attivamente con test automatizzati e audit periodici.&lt;/p&gt;

&lt;h2&gt;
  
  
  La multi-tenancy come valore per il freelance
&lt;/h2&gt;

&lt;p&gt;Come sviluppatore freelance, la multi-tenancy di Filament apre opportunità interessanti. Invece di sviluppare un applicativo custom per ogni cliente, si sviluppa una piattaforma multi-tenant e la si vende come servizio. Il costo di sviluppo si ammortizza su più clienti, la manutenzione e centralizzata e ogni nuovo tenant e un ricavo aggiuntivo con costo marginale vicino allo zero.&lt;/p&gt;

&lt;p&gt;Filament 5 rende questo modello di business praticabile anche per un freelance o un piccolo team, perché la complessità della multi-tenancy viene gestita dal framework invece che dal codice custom.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://iadicola.it/articoli/multi-tenancy-con-filament-5-un-pannello-piu-aziende?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Leggi l'articolo completo su iadicola.it&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>filament</category>
      <category>laravel</category>
      <category>saas</category>
    </item>
    <item>
      <title>GDPR: quando il codice incontra l'etica</title>
      <dc:creator>Dev-Iadicola</dc:creator>
      <pubDate>Wed, 16 Sep 2026 17:25:11 +0000</pubDate>
      <link>https://dev.to/dev_iadicola/gdpr-quando-il-codice-incontra-letica-1dpc</link>
      <guid>https://dev.to/dev_iadicola/gdpr-quando-il-codice-incontra-letica-1dpc</guid>
      <description>&lt;h2&gt;
  
  
  La privacy non e una feature: e un diritto
&lt;/h2&gt;

&lt;p&gt;C'e una tentazione ricorrente nello sviluppo software: trattare la privacy come una checkbox da spuntare. Aggiungi un banner cookie, metti un link alla privacy policy, e hai "fatto il GDPR". Ma il Regolamento Generale sulla Protezione dei Dati non e una specifica tecnica da implementare — e un framework etico tradotto in legge. Dietro ogni articolo c'e un principio: i dati delle persone appartengono alle persone, non a chi gestisce il server.&lt;/p&gt;

&lt;p&gt;Quando ho implementato la compliance GDPR in Soft PHP MVC, ho dovuto confrontarmi con questa distinzione. Non bastava aggiungere un popup: serviva ripensare come il codice tratta i dati degli utenti in ogni punto del flusso. La domanda non era "come aggiungo un cookie banner?" ma "cosa succede ai dati dell'utente dal momento in cui visita il sito fino a quando quei dati vengono cancellati?".&lt;/p&gt;

&lt;p&gt;Questa prospettiva cambia tutto. Un &lt;strong&gt;approccio tecnico&lt;/strong&gt; alla privacy si concentra sui requisiti minimi. Un &lt;strong&gt;approccio etico&lt;/strong&gt; si chiede: "Se io fossi l'utente, mi sentirei rispettato da come questo software tratta i miei dati?" La risposta a questa domanda guida ogni decisione implementativa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Il consenso come precondizione, non come default
&lt;/h2&gt;

&lt;p&gt;Il &lt;code&gt;VisitorTrackingMiddleware&lt;/code&gt; ora controlla &lt;code&gt;$_COOKIE['cookie-consent'] === 'accepted'&lt;/code&gt; prima di registrare qualsiasi dato. Senza consenso esplicito, nessun IP viene salvato, nessun user agent viene tracciato. Sembra banale, ma il vecchio comportamento era l'opposto: tracciava tutto e il consenso era un'aggiunta cosmetica.&lt;/p&gt;

&lt;p&gt;Questa inversione — da opt-out a opt-in — non e solo una questione legale. E un cambio di prospettiva filosofico che richiama il concetto kantiano di trattare le persone come fini, mai come mezzi. L'utente non e una riga in un database di analytics: e una persona che ha il diritto di scegliere cosa condividere.&lt;/p&gt;

&lt;h3&gt;
  
  
  L'implementazione tecnica del middleware
&lt;/h3&gt;

&lt;p&gt;Il middleware si inserisce nella pipeline delle richieste HTTP con una logica precisa. Prima viene eseguito il check sul cookie di consenso. Se il consenso non e presente, il middleware &lt;strong&gt;non fa nulla&lt;/strong&gt; — nessun dato viene raccolto, nessuna riga viene scritta nel database. Solo quando l'utente ha esplicitamente accettato, il middleware procede a registrare la visita con IP anonimizzato (ultimo ottetto sostituito con zero, in conformita con le raccomandazioni del Garante Privacy italiano), user agent, URL visitato e timestamp.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cookie banner conforme EDPB
&lt;/h2&gt;

&lt;p&gt;Il cookie banner e stato riscritto seguendo le linee guida EDPB (European Data Protection Board): categorie separate (essenziali sempre attivi, analytics opzionali), tre azioni distinte (accetta tutto, salva preferenze, rifiuta tutto), flag di sicurezza &lt;code&gt;Secure&lt;/code&gt; e &lt;code&gt;SameSite=Lax&lt;/code&gt;. Rifiutare deve essere facile quanto accettare — i dark pattern che rendono il "rifiuta" più difficile da trovare sono una violazione dello spirito del regolamento.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anatomia del banner: scelte di design
&lt;/h3&gt;

&lt;p&gt;Il banner presenta tre categorie di cookie chiaramente distinte:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cookie essenziali&lt;/strong&gt; — sessione PHP, token CSRF, preferenza cookie consent: sempre attivi, non disattivabili, necessari per il funzionamento base&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie analytics&lt;/strong&gt; — tracking visite, conteggio pagine viste: opzionali, disattivati per default, attivabili con consenso esplicito&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie di terze parti&lt;/strong&gt; — eliminati completamente: nessun Google Analytics, nessun Facebook Pixel, nessun tracker esterno&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;L'eliminazione totale dei cookie di terze parti e una scelta radicale ma coerente. Se il principio e il rispetto per l'utente, condividere i suoi dati con aziende il cui modello di business e la sorveglianza pubblicitaria contraddice quel principio. L'analytics interna, costruita nel framework stesso, fornisce i dati necessari senza cederne il controllo a nessuno.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data retention: il diritto all'oblio nel codice
&lt;/h2&gt;

&lt;p&gt;Il comando &lt;code&gt;php soft clear:gdpr&lt;/code&gt; implementa la pulizia periodica dei dati personali: visitatori dopo 90 giorni, rate limits dopo 24 ore, sessioni dopo 7 giorni, log trace dopo 180 giorni. Non e sufficiente chiedere il consenso — bisogna anche non conservare i dati oltre il necessario.&lt;/p&gt;

&lt;p&gt;La data retention e forse l'aspetto più trascurato della privacy nel software. Tendiamo ad accumulare dati "perché potrebbero servire" — un impulso comprensibile ma problematico. Ogni riga nel database e una responsabilità: può essere rubata, può essere esposta, può essere richiesta da un'autorità. Meno dati conservi, meno rischi corri.&lt;/p&gt;

&lt;h3&gt;
  
  
  Il principio di minimizzazione dei dati
&lt;/h3&gt;

&lt;p&gt;L'articolo 5(1)(c) del GDPR parla di &lt;strong&gt;minimizzazione dei dati&lt;/strong&gt;: raccogliere solo cio che e strettamente necessario per lo scopo dichiarato. Nel codice, questo si traduce in domande concrete. Serve davvero salvare l'IP completo? No — l'ultimo ottetto viene azzerato. Serve conservare la sessione dopo 7 giorni di inattivita? No — viene cancellata. Serve tenere i log di trace per sempre? No — 180 giorni sono sufficienti per il debugging, oltre diventa sorveglianza.&lt;/p&gt;

&lt;p&gt;Il comando &lt;code&gt;clear:gdpr&lt;/code&gt; può essere schedulato via cron per esecuzione automatica. Questo trasforma la data retention da "buona intenzione" a &lt;strong&gt;processo automatizzato&lt;/strong&gt; — una distinzione fondamentale in un contesto normativo dove "avevamo intenzione di cancellare" non e una difesa accettabile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-hosting: riprendere il controllo
&lt;/h2&gt;

&lt;p&gt;Bootstrap CSS, jQuery, Font Awesome — tutti serviti da CDN di terze parti. Ogni richiesta a un CDN e un dato condiviso: l'IP dell'utente, il referer, il timing. Spostare queste risorse in locale sotto &lt;code&gt;assets/vendor/&lt;/code&gt; non e solo una questione di performance (niente DNS resolution extra, niente connessioni cross-origin): e una scelta di sovranita digitale.&lt;/p&gt;

&lt;p&gt;Richard Stallman parlava di liberta del software in termini di controllo: se non controlli il software che usi, il software controlla te. Lo stesso principio si applica all'infrastruttura: se le risorse della tua applicazione dipendono da server di terze parti, la privacy dei tuoi utenti dipende dalle policy di quelle terze parti. Self-hosting e un atto di responsabilità.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vantaggi tecnici del self-hosting
&lt;/h3&gt;

&lt;p&gt;Oltre all'aspetto etico, il self-hosting delle dipendenze frontend offre vantaggi tecnici misurabili:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero DNS resolution aggiuntive&lt;/strong&gt; — ogni CDN esterno richiede una risoluzione DNS separata, aggiungendo latenza al caricamento iniziale&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nessun rischio di downtime esterno&lt;/strong&gt; — se il CDN di Bootstrap va offline, il tuo sito continua a funzionare&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache controllata&lt;/strong&gt; — puoi impostare header di cache aggressivi sapendo esattamente quando le risorse cambiano&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subresource Integrity nativa&lt;/strong&gt; — non serve calcolare hash SRI perché le risorse sono già sotto il tuo controllo&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Privacy by design, non privacy by afterthought
&lt;/h2&gt;

&lt;p&gt;Il form contatti ora include un campo &lt;code&gt;privacy_consent&lt;/code&gt; con validazione server-side, e il timestamp del consenso viene salvato nel database come prova ai sensi dell'Art. 7(1) del GDPR. Non e un dettaglio implementativo: e la differenza tra "abbiamo chiesto il consenso" e "possiamo dimostrare di aver chiesto il consenso".&lt;/p&gt;

&lt;p&gt;La validazione avviene a livello server tramite il sistema di validazione del framework: &lt;code&gt;required&lt;/code&gt;, &lt;code&gt;accepted&lt;/code&gt;. Anche se il JavaScript lato client impedisce l'invio del form senza la spunta, la validazione server-side e la vera barriera. Il client mente — il server verifica.&lt;/p&gt;

&lt;p&gt;Scrivere software che rispetta la privacy richiede un cambio di mentalita. Non e un layer che aggiungi alla fine: e una decisione architetturale che influenza ogni scelta, dalla struttura del database al flusso dei middleware. E, in ultima analisi, e una questione di rispetto — per le persone che useranno il tuo software e per i dati che ti affidano. Il GDPR, nel suo spirito migliore, non e un ostacolo burocratico: e un invito a costruire software che tratti le persone come persone, non come risorse da estrarre.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://iadicola.it/articoli/gdpr-quando-il-codice-incontra-etica?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Leggi l'articolo completo su iadicola.it&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>gdpr</category>
      <category>privacy</category>
      <category>etica</category>
    </item>
    <item>
      <title>Form avanzati con Filament 5: relazioni, repeater e wizard</title>
      <dc:creator>Dev-Iadicola</dc:creator>
      <pubDate>Wed, 16 Sep 2026 16:20:08 +0000</pubDate>
      <link>https://dev.to/dev_iadicola/form-avanzati-con-filament-5-relazioni-repeater-e-wizard-22pa</link>
      <guid>https://dev.to/dev_iadicola/form-avanzati-con-filament-5-relazioni-repeater-e-wizard-22pa</guid>
      <description>&lt;h2&gt;
  
  
  Perché i form reali non sono mai semplici
&lt;/h2&gt;

&lt;p&gt;I form delle applicazioni reali non sono mai una lista piatta di campi di testo. Un ordine ha righe prodotto con quantità e prezzi. Un progetto ha milestone con task e scadenze. Un paziente ha visite mediche con esami allegati e prescrizioni. La complessità dei dati si riflette nella complessità dei form, e gestirla bene e una delle sfide più comuni nello sviluppo di pannelli admin.&lt;/p&gt;

&lt;p&gt;Filament 5 affronta questa complessità con componenti dedicati che si dichiarano in PHP puro, senza JavaScript custom, senza gestione dello stato frontend e senza validazione duplicata tra client e server. Il form builder di Filament e probabilmente il componente più potente dell intero framework, e quello che giustifica da solo l adozione per molti progetti.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gli strumenti chiave per form complessi
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Repeater: campi dinamici che l utente aggiunge e rimuove
&lt;/h3&gt;

&lt;p&gt;Il Repeater e il componente per gestire liste di dati variabili all interno di un form. L utente può aggiungere nuove righe, rimuoverle, riordinarle con drag and drop e compilarle con qualsiasi tipo di campo supportato da Filament.&lt;/p&gt;

&lt;p&gt;Casi d uso tipici: righe di un ordine o preventivo, indirizzi multipli per un cliente, varianti di un prodotto (taglia, colore, prezzo), esperienze lavorative in un curriculum, allegati con metadati. Ogni riga del repeater può contenere qualsiasi combinazione di campi: text, select, date, file upload, toggle e anche altri repeater annidati per strutture dati ricorsive.&lt;/p&gt;

&lt;p&gt;Il Repeater gestisce automaticamente la persistenza dei dati. Se e associato a una relazione HasMany, Filament crea, aggiorna ed elimina i record figli in modo automatico quando il form viene salvato. Non serve scrivere logica custom nel controller.&lt;/p&gt;

&lt;h3&gt;
  
  
  Relationship manager: gestione relazioni inline
&lt;/h3&gt;

&lt;p&gt;Il Relationship Manager e un componente che aggiunge una tabella di record correlati direttamente nella pagina di dettaglio di una risorsa. A differenza del Repeater — che gestisce la relazione all interno del form — il Relationship Manager mostra una tabella separata con il proprio CRUD completo.&lt;/p&gt;

&lt;p&gt;Esempio: nella pagina di dettaglio di un cliente, un Relationship Manager per gli ordini mostra la lista degli ordini con tabella, filtri e azioni. L utente può creare un nuovo ordine, modificarne uno esistente o eliminarlo, tutto senza navigare via dalla pagina del cliente.&lt;/p&gt;

&lt;p&gt;Questo approccio e ideale quando i record correlati sono entita autonome con i propri campi e la propria logica, e non semplici righe di un form.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wizard: form multi-step con validazione per sezione
&lt;/h3&gt;

&lt;p&gt;Il Wizard suddivide un form lungo in passaggi logici, ognuno con i propri campi e la propria validazione. L utente naviga avanti e indietro tra i passaggi, e la validazione viene eseguita ad ogni transizione. Solo quando tutti i passaggi sono validi si può procedere al salvataggio.&lt;/p&gt;

&lt;p&gt;Il vantaggio non e solo estetico: un form di 30 campi spaventa l utente, mentre gli stessi 30 campi distribuiti in 4 step da 7-8 campi risultano gestibili. La percentuale di completamento dei form aumenta significativamente quando si usa un wizard rispetto a un form piatto.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dipendenze tra campi: logica condizionale nel form
&lt;/h3&gt;

&lt;p&gt;Filament supporta dipendenze tra campi con i metodi &lt;code&gt;-&amp;gt;visible()&lt;/code&gt;, &lt;code&gt;-&amp;gt;hidden()&lt;/code&gt;, &lt;code&gt;-&amp;gt;disabled()&lt;/code&gt; e &lt;code&gt;-&amp;gt;reactive()&lt;/code&gt;. Quando un campo cambia valore, altri campi possono apparire, scomparire o cambiare le proprie opzioni in tempo reale.&lt;/p&gt;

&lt;p&gt;Esempio: un select "tipo documento" con le opzioni Fattura, Nota di Credito e Preventivo. Selezionando Fattura, appaiono i campi per la ritenuta d acconto e il regime IVA. Selezionando Preventivo, appare un campo per la data di scadenza dell offerta. Tutto gestito in PHP con metodi dichiarativi, senza JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Esempio concreto: form di creazione preventivo
&lt;/h2&gt;

&lt;p&gt;Vediamo un caso reale implementato per un cliente. Un form di creazione preventivo con quattro step, ognuno con la propria logica e validazione.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1 — Dati cliente&lt;/strong&gt;: select con ricerca su anagrafica esistente, con possibilita di creare un nuovo cliente inline. Campi per ragione sociale, P.IVA, indirizzo e email di fatturazione&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2 — Righe preventivo&lt;/strong&gt;: repeater con descrizione, quantità, prezzo unitario e sconto percentuale. Calcolo automatico del totale per riga e del totale generale. Possibilita di riordinare le righe con drag and drop&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 3 — Condizioni&lt;/strong&gt;: textarea per note e condizioni, select per termini di pagamento, date picker per validita dell offerta, toggle per inclusione IVA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 4 — Riepilogo&lt;/strong&gt;: anteprima del preventivo con tutti i dati, totali calcolati e pulsante di conferma&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Senza Filament, questo form richiederebbe un framework JavaScript per la gestione dello stato, componenti custom per il repeater con calcoli, validazione duplicata client-server, chiamate AJAX per la ricerca clienti e un template Blade complesso per il layout. Con Filament, tutto vive in una classe PHP di circa 150 righe, testabile e manutenibile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validazione avanzata nei form Filament
&lt;/h2&gt;

&lt;p&gt;La validazione in Filament sfrutta il sistema di validazione di Laravel, il che significa accesso a tutte le regole built-in e la possibilita di creare regole custom. Ma ci sono alcune funzionalita specifiche di Filament che meritano attenzione:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Validazione real-time&lt;/strong&gt; — i campi marcati come &lt;code&gt;-&amp;gt;live()&lt;/code&gt; vengono validati mentre l utente digita, mostrando gli errori immediatamente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validazione per step del wizard&lt;/strong&gt; — ogni passaggio valida solo i propri campi, impedendo di procedere al passaggio successivo se ci sono errori&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validazione su repeater&lt;/strong&gt; — le regole si applicano a ogni riga del repeater indipendentemente, con messaggi di errore specifici per riga&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validazione cross-field&lt;/strong&gt; — regole come &lt;code&gt;required_if&lt;/code&gt;, &lt;code&gt;gt:field&lt;/code&gt; e &lt;code&gt;different:field&lt;/code&gt; funzionano anche tra campi di sezioni diverse del form&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance dei form complessi
&lt;/h2&gt;

&lt;p&gt;Un form con molti campi reattivi e repeater può diventare lento a causa delle richieste Livewire ad ogni interazione. Filament 5 mitiga questo problema con il debouncing automatico, il batching delle richieste e la possibilita di rendere reattivi solo i campi che lo necessitano davvero.&lt;/p&gt;

&lt;p&gt;La regola pratica e: usare &lt;code&gt;-&amp;gt;live()&lt;/code&gt; solo sui campi che influenzano altri campi, e usare &lt;code&gt;-&amp;gt;live(onBlur: true)&lt;/code&gt; quando la reattivita non serve in tempo reale ma solo quando l utente esce dal campo. Questo riduce il numero di richieste al server e mantiene il form scattante anche con 50+ campi.&lt;/p&gt;

&lt;h2&gt;
  
  
  Il vantaggio architetturale dei form dichiarativi
&lt;/h2&gt;

&lt;p&gt;Il beneficio più grande dei form Filament non e la velocità di sviluppo — che pure e notevole — ma la manutenibilità. Un form dichiarativo in PHP e intrinsecamente più leggibile di un equivalente mix di HTML, JavaScript e PHP. Le regole di validazione sono vicine ai campi, la logica condizionale e esplicita e la struttura del form e visibile in un colpo d occhio.&lt;/p&gt;

&lt;p&gt;Quando un nuovo sviluppatore apre la classe di una Resource Filament, capisce immediatamente quali campi ha il form, come sono validati, quali dipendenze esistono e come vengono salvati i dati. Questa leggibilità si traduce in meno bug, meno tempo per l onboarding e costi di manutenzione ridotti nel lungo termine.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://iadicola.it/articoli/form-avanzati-con-filament-5-relazioni-repeater-e-wizard?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Leggi l'articolo completo su iadicola.it&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>filament</category>
      <category>laravel</category>
      <category>ux</category>
    </item>
    <item>
      <title>Filament 5 vs Nova: quale scegliere nel 2026</title>
      <dc:creator>Dev-Iadicola</dc:creator>
      <pubDate>Wed, 16 Sep 2026 15:15:10 +0000</pubDate>
      <link>https://dev.to/dev_iadicola/filament-5-vs-nova-quale-scegliere-nel-2026-3kc7</link>
      <guid>https://dev.to/dev_iadicola/filament-5-vs-nova-quale-scegliere-nel-2026-3kc7</guid>
      <description>&lt;h2&gt;
  
  
  Due approcci diversi allo stesso problema
&lt;/h2&gt;

&lt;p&gt;Laravel Nova e il pannello admin ufficiale del framework, sviluppato e mantenuto dal team Laravel, disponibile con licenza a pagamento. Filament e un progetto open source, basato su Livewire, con una community in crescita esponenziale e un ecosistema di plugin che rivaleggia con quello di Nova per ampiezza e qualità.&lt;/p&gt;

&lt;p&gt;Entrambi generano pannelli admin completi a partire da codice PHP, con tabelle, form, filtri e dashboard. Ma le filosofie sottostanti sono diverse, e la scelta tra i due dipende dal contesto del progetto, dal budget e dalle competenze del team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dove Filament 5 vince rispetto a Nova
&lt;/h2&gt;

&lt;p&gt;Filament ha accumulato vantaggi significativi negli ultimi due anni, e la versione 5 consolida ulteriormente la sua posizione come strumento di riferimento per i pannelli admin Laravel.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gratuito e open source&lt;/strong&gt; — nessun costo di licenza per progetto. Per un freelance che sviluppa 10 pannelli admin all anno, il risparmio rispetto a Nova (99$ per progetto o 299$ per la licenza multi-sito) e sostanziale&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Basato su Livewire&lt;/strong&gt; — reattivita completa senza Vue.js nel frontend. Il team non ha bisogno di competenze JavaScript avanzate, tutto si gestisce in PHP. Questo riduce la complessità dello stack e i punti di failure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ecosistema plugin più ampio e attivo&lt;/strong&gt; — oltre 200 plugin community, molti dei quali gratuiti. Il marketplace di Filament include plugin per ogni esigenza comune: Shield per i permessi, Excel per l export, Media Library per i file, e decine di altri&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-tenancy integrata nel core&lt;/strong&gt; — Nova richiede pacchetti di terze parti per la multi-tenancy. Filament la offre nativamente, con supporto completo per tenant switching, scope automatico e branding per tenant&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form builder più flessibile&lt;/strong&gt; — wizard nativi, repeater con drag and drop, dipendenze tra campi e layout personalizzabili. Il form builder di Filament e più potente e più facile da estendere rispetto a quello di Nova&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Table builder superiore&lt;/strong&gt; — colonne personalizzabili, filtri avanzati, summarizer per totali, gruppi e azioni in bulk più granulari&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aggiornamenti più frequenti&lt;/strong&gt; — essendo open source con una community attiva, Filament rilascia aggiornamenti e bugfix con cadenza molto più frequente di Nova&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dove Nova resta forte nel 2026
&lt;/h2&gt;

&lt;p&gt;Nova non e un prodotto obsoleto. Ha ancora vantaggi specifici che lo rendono la scelta giusta in determinati contesti.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Supporto ufficiale Laravel&lt;/strong&gt; — aggiornamenti garantiti dal team core di Laravel. Quando esce una nuova versione del framework, Nova e aggiornata in parallelo. Per aziende che hanno bisogno di SLA e supporto formale, questo conta&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrazione più stretta con l ecosistema first-party&lt;/strong&gt; — Nova si integra nativamente con Cashier, Scout, Horizon e gli altri pacchetti ufficiali Laravel, spesso con meno configurazione rispetto a Filament&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interfaccia stabile e prevedibile&lt;/strong&gt; — Nova cambia poco tra una release e l altra. Per team grandi che hanno bisogno di stabilita e prevedibilita, questo e un vantaggio. Filament evolve più rapidamente, il che significa più funzionalita ma anche più cambiamenti da gestire&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentazione curata dal team Laravel&lt;/strong&gt; — la documentazione di Nova e scritta con lo stesso standard della documentazione di Laravel: completa, coerente e mantenuta professionalmente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend basato su Vue.js&lt;/strong&gt; — per team con competenze Vue, Nova offre possibilita di personalizzazione frontend più granulari rispetto a Filament, che limita volutamente l accesso al JavaScript&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Confronto tecnico diretto
&lt;/h2&gt;

&lt;p&gt;Mettiamo a confronto i due framework su aspetti tecnici specifici che influenzano la scelta quotidiana dello sviluppatore.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creazione di una Resource CRUD
&lt;/h3&gt;

&lt;p&gt;In entrambi i framework si genera una Resource con un comando Artisan. La struttura e simile: una classe PHP che definisce campi del form e colonne della tabella. La differenza principale e nel form builder: Filament offre più componenti built-in (wizard, repeater, builder blocks) mentre Nova richiede pacchetti aggiuntivi per le stesse funzionalita.&lt;/p&gt;

&lt;h3&gt;
  
  
  Personalizzazione dell interfaccia
&lt;/h3&gt;

&lt;p&gt;Filament usa Tailwind CSS con custom properties per il theming, personalizzabile senza ricompilare. Nova usa Tailwind ma con un sistema di theming meno flessibile. Per personalizzazioni profonde, Nova richiede la creazione di componenti Vue custom, mentre Filament permette di pubblicare e modificare view Blade specifiche.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance e scalabilità
&lt;/h3&gt;

&lt;p&gt;Filament basato su Livewire fa più richieste al server per le interazioni (ogni click e una richiesta HTTP). Nova basato su Vue.js gestisce più logica client-side. Su pannelli con molte interazioni simultanee, Nova può risultare più reattivo. Su pannelli standard con interazioni moderate, la differenza e impercettibile.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;Entrambi supportano il testing con PHPUnit. Filament offre helper specifici come &lt;code&gt;assertCanSeeTableRecords&lt;/code&gt; e &lt;code&gt;assertFormFieldExists&lt;/code&gt;. Nova ha un set di assertion simile. La testabilita e comparabile.&lt;/p&gt;

&lt;h2&gt;
  
  
  La scelta pratica nel 2026
&lt;/h2&gt;

&lt;p&gt;Dopo aver usato entrambi i framework in progetti reali, la mia raccomandazione per il 2026 e chiara:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Filament 5 per la maggior parte dei progetti nuovi.&lt;/strong&gt; Zero costi di licenza, community attiva, funzionalita che coprono il 95% dei casi d uso e una curva di apprendimento accessibile. Per freelance e piccoli team, il risparmio economico e di tempo e significativo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nova per progetti enterprise con requisiti specifici.&lt;/strong&gt; Team grandi che hanno bisogno di supporto ufficiale, SLA garantiti e stabilita a lungo termine. Aziende che sono già investite nell ecosistema Nova con plugin custom e workflow consolidati.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cosa considerare prima di scegliere
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Budget&lt;/strong&gt; — Filament e gratuito, Nova costa 99$/progetto o 299$ multi-sito. Su 10 progetti, sono 990$ di differenza&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competenze del team&lt;/strong&gt; — Filament richiede solo PHP e Livewire. Nova richiede anche Vue.js per personalizzazioni avanzate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complessità dei form&lt;/strong&gt; — se il progetto ha form complessi con wizard e repeater, Filament ha un vantaggio netto&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-tenancy&lt;/strong&gt; — se serve, Filament la offre nativamente. Con Nova serve un pacchetto esterno&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stabilita vs innovazione&lt;/strong&gt; — Nova cambia poco e lentamente. Filament evolve rapidamente. Entrambi sono validi, dipende da cosa serve al progetto&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In definitiva, la competizione tra Filament e Nova ha alzato la qualità di entrambi gli strumenti. Il vero vincitore e lo sviluppatore Laravel, che nel 2026 ha due opzioni eccellenti per costruire pannelli admin professionali in tempi rapidi.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://iadicola.it/articoli/filament-5-vs-nova-quale-scegliere-nel-2026?utm_source=devto&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Leggi l'articolo completo su iadicola.it&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>filament</category>
      <category>laravel</category>
      <category>confronto</category>
    </item>
  </channel>
</rss>
