NamedActions è una tecnica di sviluppo di applicazioni il cui scopo è velocizzare la gestione delle azioni su form.
La maggior parte dei form che uno sviluppatore produce sono insiemi di campi cui si agganciano uno o più pulsanti di azione (bottoni di submit). Nella mia esperienza mi sono trovato a gestire praticamente sempre almeno due azioni:
Ho sempre voluto gestire questi “comportamenti” senza l'ausilio di Javascript. La mia filosofia è che, ove possibile, evito di usare Javascript.
La soluzione è stata l'introduzione dell'attributo “name” ai pulsanti di submit in modo da poter effettuare dei controlli lato server:
<input type="submit" name="save" value="Salva" /> <input type="submit" name="abort" value="Annulla" />
if ( isset($_POST['save']) ) echo "Procedo con il salvataggio..."; if ( isset($_POST['abort']) ) echo "Operazione annullata";
NamedAction consiste in una funzione erogata sia da PowHelper che da PowComponent e permette di gestire la creazione di pulsanti di interfaccia e di intercettare il loro utilizzo lato server in modo estremamente semplice.
Ma NamedAction fa molto di più! Infatti permette di utilizzare DAC per gestire l'appearance del controllo nella pagina ed anche il suo funzionamento lato server permettendo un'elevato grado di configurazione dell'applicazione.
Ogni azione è infatti corredata di callback sia durante la produzione del codice xHTML sia durante i controlli server side. Questo accorgimento permette un'elevatissimo grado di integrazione tra diversi software o forti verticalizzazioni di plugin.
All'interno di una vista (NamedAction è pensato per i form!) è possibile lanciare un'azione:
<?=$pow->action('save')?>
la quale verrà interpretata e tradotta in:
<input type="submit" name="pow-action-save" value="Salva" />
E' possibile configurare nel dettaglio il risultato mediante un array associativo che è possibile passare come secondo parametro al metodo oppure è possibile configurare l'azione mediante DAC alla path “app.namedActions.actionName”
CakePOWER definisce un set di NamedActions pronte all'uso:
E' comunque possibile estendere il numero di azioni disponibili nella DAC creando le proprie NamedActions:
JC::extend('app.namedActions',array( 'myaction' => array( 'type' => 'button', 'name' => 'my-action', 'show' => 'Testo visualizzato', ), ));
Ogni azione si concretizza nella produzione di un certo codice xHTML di interfaccia. E' possibile intervenire in modo estremamente dettagliato su questo processo definendo dei metodi di Callback.
Le callback possono essere definite, ad esempio, in AppHelper di applicazione in quanto PowHelper eredita l'applicazione.
E' possibile variare la configurazione di un'azione per far invocare una o più funzioni di callback:
JC::append('controller.apples.add.namedActions.save.beforeRender','>>foo'); // AppHelper::foo()
Il metodo di callback riceve un'unico parametro $data.
L'array associativo “data” è passato per riferimento e contiene 3 chiavi:
Modificando l'array “$data” è possibile influenzare il comportamento dell'azione stessa.
Nel controllers NamedActions è invocato per rispondere ad un'azione. L'utilizzo più frequente è il redirecting differito sulle azioni di salvataggio:
function save() { if ( !empty($this->data) ) { $this->Pow->action('abort'); // Redirect per richiesta annullata. if ( $this->Model->save($this->data) ) { $this->Pow->action('save'); // Redirect alla form con conferma salvataggio. $this->Pow->action('exit'); // Redirect alla vista elemento. } } }
Il codice qui proposto è un tipico esempio di gestione delle azioni demandata alla configurazione DAC. Nel sorgente infatti è specificato solamente quali azioni gestire e non come gestirle. Sarà la configurazione DAC di applicazione a definire cosa l'azione deve fare garantendo massima personalizzazione del software senza intervento sui sorgenti.
Come per le azioni di interfaccia è possibile utilizzare un array associativo come parametro aggiuntivo per configurare l'azione. In ogni caso l'azione cercherà di ereditare il comportamento dalla DAC.
| Parametro | Descrizione |
|---|---|
| redirectURL | Definisce l'url verso cui reindirizzare la pagina |
| flashMSG | Eventuale messaggio da visualizzare per conferma o segnalazioni |
| concat | Definisce un'azione da concatenare a quella in corso |
| listen | Definisce una o più azioni con cui “lavorare” |
E' possibile utilizzare NamedAction inibendo la gestione dell'azione in modo da ottenere semplicemente un valore booleano che indichi se l'azione è stata richiesta o meno:
if ( $this->Pow->action('abort',true) ) echo "Are you sure?";
Questo utilizzo inibisce i redirect e le eventuali callback associate all'azione mentre rimangono attive le funzionalità concat e listen.
E' possibile che il generarsi di un'azione debba scatenarne un'altra oppure è possibile che un'azione debba attivarsi in risposta ad un'altra azione.
Il seguente esempio gestisce un'ipotetica interfaccia di gestione utenti dove, oltre a salvare informazioni anagrafiche, abbiamo a disposizione un bottone dedicato all'attivazione dell'utente.
Cliccando sull'azione “Attiva utente” si perderebbe l'azione di salvataggio ma l'attributo concat ci viene in aiuto per collegare le due azioni.
// Utilizzo l'azione "Yes" per concatenarla a "save" nella configurazione DAC. // "Yes" verrà utilizzato per attivare l'utente. JC::extend('controller.users.save.namedActions.yes',array( 'type' => 'submit', 'show' => 'Attiva Utente e Salva', 'concat' => array('save') )); // Personalizzo i bottoni azione per il form di salvataggio. JC::extend('controller.users.save.formActions.actions','save,yes,abort'); // user_controller.php function save() { if ( !empty($this->data) ) { $this->Pow->action('abort'); // Utilizzo un bottone azione per gestire l'attivazione di un utente. if ( $this->Pow->action('yes',true) ) $this->data['User']['active'] = 1; if ( $this->User->save() ) { $this->Pow->action('save'); $this->Pow->action('exit'); } } }
Un'altro modo di configurare il seguente esempio è mettere l'azione “save” in ascolto di “yes”. In questo modo save verrebbe invocata sia al click esplicito sul relativo pulsante che al click sull'attivazione utente:
JC::extend('controller.users.save.namedActions.yes',array( 'type' => 'submit', 'show' => 'Attiva Utente e Salva' )); JC::extend('controller.users.save.namedActions.save',array( 'listen' => array('yes') ));
Sia concat che listen possono essere configurati con un array di nomi di azione.
E' possibile configurare un'azione per eseguire una o più funzioni di callback che vengono invocate prima di eseguire un determinato redirect. La chiave di configurazione è DAC “beforeRedirect”. (La chiave deve essere definita come array).
Questa callback riceve un array condizionale passato per riferimento in modo da poter influenzare i dati su cui si svolge l'azione.
| Parametro | Descrizione |
|---|---|
| action | Nome dell'azione. |
| name | Attributo “name” da ricercare nei dati $_POST. |
| config | Array di configurazione dell'azione. |
| output | Un qualunque tipo di output della funzione. |
E' possibile gestire vari tipi di richiesta di callback:
JC:write('app.namedActions.save.beforeRedirect',array( 'ctr::mia_callback', // AppController::mia_callback() '>>mia_callback', // AppComponent::mia_callback() ));