venerdì 8 febbraio 2008

Joomla 1.5: Altre Funzioni per il Backend del Componente MyForm

Ho trascurato un po' lo sviluppo del componente di esempio per Joomla 1.5 (MyForm). Preferisco scrivere delle cose di cui mi occupo al momento e capita di affaccendarsi in diverse faccende.

Comunque con l'uscita di Joomla 1.5 stabile noto un crescente interesse riguardo allo sviluppo di componenti per la nuova versione per cui credo sia il caso di riprendere il filo ed aggiungere qualche (ultima) funzionalità al backend del componente.

Allo stadio attuale dello sviluppo, dal backend è possibile solamente consultare i dati inseriti dagli utenti tramite il modulo pubblicato nel frontend. Aggiungeremo le funzioni per modificare e cancellare questi dati con la possibilità di cancellazione di record multipli selezionati mediante caselle di selezione (checkboxes).

Come al solito il risultato finale è disponibile sul sito (myform5.zip).

Gestione della selezione dei record

La selezione multipla di record da un elenco è una funzionalità standard che viene implementata nei componenti con apposite funzioni del framework di Joomla.

Il file da modificare è default.php in .../administrator/components/com_myform/views/myform/tmpl

Aggiungiamo la casella per la selezione di tutti i record nell'intestazione dell'elenco

<th width="20">
 <input type="checkbox" name="toggle" value=""
   onclick="checkAll(' . count($this->items) . ');" />
</th>

Portiamo a 6 le colonne dell'elenco per fare spazio alla casella di selezione a fianco di ogni record.

$tr = '<tr>' . str_repeat('<td>%s</td>', 6) . '</tr>';

Il ciclo che genera le righe dell'elenco diventa

$i = 0;
foreach($this->items as $item) {
 $checked = JHTML::_('grid.id', $i, $item->id);
 $html .= sprintf($tr, $checked, $item->nome, $item->cognome,
 $item->telefono, $item->indirizzo, $item->note);
 $i++;
}

Da notare che il codice HTML per la casella di selezione è generato da una funzione del framework ( JHTML::_('grid.id', $i, $item->id) ) a cui si devono passare come argomenti il numero della riga dell'elenco ( $i ) e il valore del campo ID del record nel database ( $item->id ).

Infine va inserito al form adminForm un campo nascosto

<input type="hidden" name="boxchecked" value="0" />

che serve al passaggio dei valori dei campi selezionati.

Basta ricordarsi questi pochi passaggi e il resto sarà fatto da Joomla in modo standard. Maggiori dettagli (almeno a me, almeno per ora) non interessano.

Aggiunta pulsanti Cancella e Modifica

Aggiungiamo i pulsanti standard per la gestione delle operazioni di cancellazione e modifica.

Il file da modificare è view.html.php in .../administrator/components/com_myform/views/myform

JToolBarHelper::title('MyForm', 'generic.png');
JToolBarHelper::deleteList();
JToolBarHelper::editListX();

Anche in questo caso si utilizzano funzioni del framework. Non abbiamo passato alcun argomento a deleteList() e editListX() per cui tutte le impostazioni saranno quelle predefinite inclusi i valori dei task che vengono generati dalla pressione dei pulsanti, remove per la cancellazione, edit per la modifica.

Ricordo che perché il tutto possa funzionare il form adminForm che abbiamo visto sopra deve contenere un campo nascosto

<input type="hidden" name="task" value="" />

che serve alla trasmissione del task.

Controller di backend

Si è detto che ad ogni pulsante della barra degli strumenti corrisponde un task. Implementiamo nel Controller di backend i metodi per processare questi task.

File controller.php in .../administrator/components/com_myform/

function edit() {
 $this->addModelPath(JPATH_COMPONENT_SITE.DS.'models');
 $model = $this->getModel('myform');

Per la funzione di modifica abbiamo bisogno di visualizzare il modulo di immissione dati la cui struttura si trova nell'oggetto Model del frontend. Però stiamo scrivendo il backend del componente per cui con addModelPath indichiamo al Controller di creare l'oggetto Model utilizzando la classe definita nel frontend del componente (JPATH_COMPONENT_SITE).

 $array = JRequest::getVar('cid',  0, '', 'array');
 $id = (int)$array[0];

L'array contiene i valori del campo ID nel database di tutti i record selezionati nell'elenco. Sulla fiducia o, se non vi fidate, controllate il sorgente HTML della pagina che visualizza l'elenco. In una operazione di modifica anche in caso di selezione multipla ci interessa solo l'ID del primo record.

 $view =& $this->getView('form', 'html');
 $view->setModel($model);

Viene creato un nuovo oggetto View form. La classe relativa deve essere ancora creata, lo faremo tra poco.

 if($data = $model->getData($id)) {
   $view->assignRef('data', $data);
 }
 $view->display();
} // fine function edit()

I dati corrispondenti al record selezionato vengono letti dal database e passati all'oggetto View per la visualizzazione. Anche il metodo getData() di Model sarà creato in seguito.

Implementiamo il metodo per il task remove.

function remove() {
 $model = $this->getModel('myform');
 if(!$model->delete()) {
   $msg = JText::_('Errore: Uno o più record
   non sono stati cancellati');
 } else {
   $msg = JText::_('Record cancellato/i');
 }
 $this->setRedirect('index.php?option=com_myform', $msg);
}

Niente di particolare. Tutto il lavoro significativo viene fatto dal metodo delete() dell'oggetto Model (di backend) che dobbiamo ancora scrivere.

View per il modulo modifica dati nel backend

La classe utilizzata per crare l'oggetto View che si occupa della visualizzazione del modulo per la modifica dei dati nel backend è tutta da scrivere.

Creiamo un nuovo file view.html.php in .../administrator/components/com_myform/views/form
defined('_JEXEC') or die('Restricted access');

jimport('joomla.application.component.view');

class MyFormViewForm extends JView {
  
 function display($tpl = null) {
   JToolBarHelper::title(JText::_('MyForm Edit'), 'generic.png');
   JToolBarHelper::save('submit');
   JToolBarHelper::cancel();

Si crea un pulsante Salva, che genera un task submit, e un pulsante Annulla che genera il task predefinito cancel.

   
   $model =& $this->getModel('myform');
   $form = $model->getForm();
   //nel backend nome e id sono standard
   $form['name'] = 'adminForm';
   $form['id'] = 'adminForm';
   $this->assignRef('form', $form);
   parent::display($tpl);
 } // fine function display()
} //fine class MyFormViewForm

La definizione del form viene chiesta all'oggetto Model e passata al template per la visualizzazione. Tutte cose già viste negli articoli precedenti.

Anche il template associato alla View va creato da zero.

File default.php in .../administrator/components/com_myform/views/form/tmpl

defined('_JEXEC') or die('Restricted access');
require JPATH_COMPONENT_ADMINISTRATOR.DS.'helpers'
. DS . 'myform.php';
MyFormHelper::displayForm($this->form, $this->data);

Il codice per la visualizzazione del modulo lo abbiamo già scritto per il frontend del componente, sarebbe assurdo duplicarlo. Scriviamo quindi una classe MyFormHelper con un metodo displayForm() che sarà utilizzato nel frontend e nel backend.

La classe MyFormHelper è definita nel file myform.php in .../administrator/components/com_myform/helpers

Non commento il codice perché si tratta di cose già viste, potete controllare i sorgenti allegati.

Il file default.php del frontend in ...components/com_myform/views/myform/tmpl

è stato modificato per utilizzare lo stesso metodo displayForm() e anche in questo caso chi è interessato ai dettagli può esaminare il sorgente.

Controller di backend: task submit e cancel

Bisogna tornare al Controller di backend per l'implementazione dei metodi submit() e cancel() che processano i task generati dai pulsanti Salva e Annulla nella schermata di modifica record.

File controller.php in .../administrator/components/com_myform/

function submit() {
 $data = JRequest::getVar('myform', array(), 'post', 'array');
 $this->addModelPath(JPATH_COMPONENT_SITE.DS.'models');
 $model = $this->getModel('myform');
 if($model->store($data)) {
   $msg = JText::_('Record Salvato');
   $this->setRedirect('index.php?option=com_myform', $msg);
 } else {
   $view =& $this->getView('form', 'html');
   $view->setModel($model);
   $view->assignRef('data', $data);
   $view->display();
 }
}

Per salvare le modifiche si chiama il metodo store() dell'oggetto Model del frontend che già esiste perché è utilizzato per il salvataggio dei dati inseriti dai visitatori. Notate che solo in caso di successo si fa un setRedirect per reindirizzare alla pagina principale (quella con l'elenco dei record), in caso di errore i dati ricevuti da $_POST vengono restituiti alla View in modo che il modulo sia visualizzato di nuovo e l'utente possa fare le necessarie correzioni senza perdere i dati già inseriti.

Il codice è praticamente identico a quello già scritto negli articoli precedenti per il frontend.

Manca il metodo per il task cancel.

function cancel() {
 $msg = JText::_('Operazione annullata');
 $this->setRedirect('index.php?option=com_myform', $msg);
}

Più facile di così!

Model di backend

La cancellazione dei dati avviene solo dal backend per cui la relativa funzione va inserita nella classe Model del backend.

File myform.php in .../administrator/components/com_myform/models

function delete() {
 $cids = JRequest::getVar('cid', array(0), 'post', 'array');
 $row =& $this->getTable();

 foreach($cids as $cid) {
   if (!$row->delete($cid)) {
     $this->setError($row->getErrorMsg());
     return false;
   }
 }
 return true;
}

Ricordo che questo metodo viene invocato dal metodo remove() del Controller di backend.

$cids contiene un array dei valori del campo ID di tutti i record selezionati nell'elenco. Il resto è banale (o forse no?): scansione dell'array e uso del metodo delete() dell'oggetto Table (di cui già si è parlato negli articoli precedenti) per cancellare i record.

Come al solito niente istruzioni SQL nel nostro codice, tutto il lavoro lo fa il framework.

Model di frontend

Resta da implementare il metodo getData() (richiamato da edit() del Controller di backend) nella classe Model del frontend.

File myform.php in .../components/com_myform/models

function getData($id) {
 $sql = 'SELECT * FROM #__myform WHERE id = '. $id;
 $this->_db->setQuery($sql);
 return $this->_db->loadAssoc();
}

Si estrae dal database il record corrispondente ad un determinato ID e si ritorna come array associativo ( loadAssoc() ).

Per concludere

Abbiamo finito. Il sorgente aggiornato è scaricabile dal sito (myform5.zip).

Sviluppare ulteriormente MyForm non avrebbe molto senso. Si tratta di un componente di esempio anche se nato con l'ambizione di essere (anche solo appena un po') più 'reale' del tradizionale componente dimostrativo.

Lo sviluppo di componenti (nonché di moduli e plugin) per Joomla è comunque un argomento di cui si avrà modo di parlare ancora.

Se c'è qualcosa che non funziona, qualche dettaglio che non capite o semplicemente se vi va di farlo lasciate un commento.

7 commenti:

Anonimo ha detto...

Sei stato iLLLLLuminante !!!!!

Grandissimo Grazie.

Simon

Massimo ha detto...

Grazie a te, sono contento di esserti stato utile.

Marco ha detto...

Spiegazione chiarissima!
Mi cimenterò nel passaggio dalla teoria alla pratica, casomai avessi qualche dubbio ti chiederò sicuramente lumi :-)

Anonimo ha detto...

Mi sto istruendo sui componenti di Joomla, ritengo sia un ottimo strumento. Si vede che siete preparati, avete fatto un bel lavoro. Ringrazio per il manuale che avete messo a disposizione. Saluti. Dr.Luca

Massimo ha detto...

Grazie dei complimenti, mi fa piacere che la guida sia stata utile. Ad avere tempo mi sarebbe anche piaciuto ampliarla, ma non è stato possibile per ora.

Marco ha detto...

Caro Massimo, ho seguito il tuo tutorial ed è favoloso. Solo che sto impazzando per capire come fare ad integrarlo con check box, radio box, ma sopratutto upload file. Mi sapresti dare una mano?

Grazie 1000, mi saresti davvero di aiuto!
Marco

Massimo ha detto...

Questo è un esempio semplice che spero sia utile per iniziare. Poi bisogna proseguire da soli :) Purtroppo non ho il tempo per fornire assistenza personale.

Posta un commento

Nota. Solo i membri di questo blog possono postare un commento.