giovedì 30 agosto 2007

Joomla 1.5: Sviluppo Componenti (Amministrazione)

Il componente di esempio MyForm è ora in grado di ricevere dati inviati da un modulo, compiere un controllo di validità degli stessi e salvarli nel database.

Resta da scrivere la funzione di visualizzazione dei dati che sarà inserita nella parte di amministrazione del componente (backend).

La parte di amministrazione di un componente per Joomla 1.5 è strutturata in modo del tutto analogo a quello della parte pubblica che abbiamo visto fino ad ora. Avremo quindi un file principale (entry point) e oggetti Controller, Model, View con relativo Template.

File principale (entry point). admin.myform.php

in .../administrator/components/com_myform/
defined('_JEXEC') or die('Restricted access');

require_once(JPATH_COMPONENT.DS.'controller.php');

$controller = new MyFormController();
$controller->execute(JRequest::getVar('task'));
$controller->redirect();

Stesse funzioni del corrispondente file della parte pubblica.

Controller. File controller.php

in .../administrator/components/com_myform/
defined('_JEXEC') or die('Restricted access');

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

class MyFormController extends JController {}

Per ora definiamo solo la classe, non ci serve implementare alcun metodo.

Model. File myform.php

in .../administrator/components/com_myform/models/
defined('_JEXEC') or die();
jimport('joomla.application.component.model');

class MyFormModelMyForm extends JModel {

  function _buildQuery() {
    $query = 'SELECT * FROM #__myform';
    return $query;
  }
 
  function getData(){
    $data = $this->_getList($this->_buildQuery());
    return $data;
  }
}

Implementiamo due metodi. Conviene, se possibile, centralizzare la creazione delle istruzioni sql utilizzate da un oggetto Model in un unico metodo (_buildQuery()). In questo caso abbiamo solo una semplicissima query per recuperare tutti i dati salvati nella tabella del componente.

Il metodo getData() utilizza questa query per ritornare un array contenente tutti i record della tabella.

Il metodo _getList(), ereditato da JModel, esegue la query che gli viene passata come argomento e ritorna il risultato sotto forma di array di oggetti.

View. File view.html.php

in .../administrator/components/com_myform/views/myform/

Come abbiamo visto in precedenza per ogni altro oggetto View dobbiamo implementare il metodo display()

defined('_JEXEC') or die('Restricted access');

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

class MyFormViewMyForm extends JView {
    
  function display($tpl = null) {
    $items =& $this->get('Data');
    $this->assignRef('items', $items);
    parent::display($tpl);
  }
}

Quasi tutto già visto, ma la riga

$items =& $this->get('Data');

merita una spiegazione a parte. Quando in un oggetto Model è implementato un metodo il cui nome inizia con get, la View a cui l'oggetto Model è stato assegnato può accedere al valore di ritorno del metodo come se si trattasse di una sua proprietà il cui nome è dato dal nome del metodo meno il get iniziale.

Quella singola riga di codice è quindi l'equivalente, molto più leggibile e compatto, di

$model =& $this->getModel();
$items = $model->getData();

$items contiene l'array di record risultato della query impostata nel metodo _buildQuery() dell'oggetto Model.

Template. File default.php

in .../administrator/components/com_myform/views/myform/tmpl/

Non commento tutto il codice perché si tratta di semplici istruzioni per la visualizzazione dei dati.

Faccio solo notare che, poiché abbiamo nell'oggetto View

$this->assignRef('items', $items);

nel Template per leggere l'array che contiene i dati da visualizzare si usa

foreach($this->items as $item) {
  ...
}

File myform.xml

in .../administrator/components/com_myform/

La sezione tra <administrator> e </administrator> del file xml di installazione deve essere aggiornata per includere tutti i file che abbiamo appena aggiunto

<administration>
  <menu>My Form</menu>
  <files folder="admin">
    <filename>admin.myform.php</filename>
    <filename>controller.php</filename>
    <filename>tables/myform.php</filename>
    <filename>views/myform/view.html.php</filename>
    <filename>views/myform/tmpl/default.php</filename>
    <filename>models/myform.php</filename>
    <filename>install.sql</filename>
    <filename>uninstall.sql</filename>
  </files>  
</administration>

Il file del componente con le modifiche fatte in questo articolo è scaricabile dal sito (myform3.zip)

Per quanto sia solo un semplice esempio (oddio, magari sulla semplicità non tutti saranno d'accordo), il componente può essere già utilizzato. Volendo modificare o aggiungere campi al modulo si deve intervenire sulla struttura definita nell'oggetto Model della parte pubblica (.../components/com_myform/models/myform.php) di cui abbiamo parlato nel primo articolo di questa serie.

E' chiaro che dovranno essere modificati anche lo script per la creazione della tabella nel database (.../administrator/components/com_myform/install.sql) e la classe TableMyForm del componente (.../administrator/components/com_myform/tables/myform.php).

Un esempio così semplice non può certo esaurire tutto quello che ci sarebbe da dire sullo sviluppo di componenti per Joomla 1.5.

Però penso possa essere un buon punto di partenza per chi è interessato a questo argomento. Io lo sono parecchio per cui aspettatevi integrazioni e futuri sviluppi. Se necessarie anche correzioni perché, come detto fin dall'inizio, qui nessuno fa lezione e qualche errore è sempre possibile. Se siete interessati restate in zona.

Tutto il codice presentato è stato testato in locale sotto Windows XP + wamp5 (Apache/2.2.4, PHP 5.21, MySql 5.0.27)

Se riscontrate problemi nell'installazione o nell'uso del componente lasciate un commento.

Per il momento chiudiamo questa lunga chiaccherata su Joomla. Anche se è un cms che mi piace molto non è l'unica cosa di cui voglio parlare nel blog.

mercoledì 29 agosto 2007

Joomla 1.5: Sviluppo Componenti (2)

Arrivati a questo punto si è visto come utilizzare l'oggetto View ed il Template ad esso associato per far visualizzare al componente di esempio (MyForm) un modulo di immissione dati la cui struttura abbiamo definito nell'oggetto Model.

Il passo successivo sarà scrivere il codice necessario per acquisire i dati inseriti dall'utente e salvarli in una tabella del database.

Il risultato finale di tutto quanto diremo è nel file myform2.zip. Consiglierei di scaricarlo subito e scompattarlo in una cartella del vostro hard disk perché durante la spiegazione salteremo da un file all'altro ed averli tutti subito a portata di mano incrementerà le probabilità di capirci qualcosa!

Creazione Tabella nel database

La tabella dove salvare i dati dovrà essere creata quando il componente viene installato e rimossa quando viene disinstallato. Si devono quindi scrivere due distinti script sql.

install.sql

DROP TABLE IF EXISTS `#__myform`;

CREATE TABLE `#__myform` (
  `id` int(11) NOT NULL auto_increment,
  `nome` varchar(25) NULL,
  `cognome` varchar(25) NULL,
  `telefono` varchar(15) NULL,
  `indirizzo` varchar(120) NULL,
  `note` text NULL,
  `data` datetime NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

uninstall.sql

  DROP TABLE IF EXISTS `#__myform`;

Prima di eseguire la query i caratteri #__ vengono automaticamente sostituiti con il prefisso tabelle specificato in fase di installazione di Joomla. Se non sono state modificate le impostazioni predefinite il nome della tabella nel database sarà jos_myform.

Classe Table del componente

Oltre a creare la tabella nel database bisogna aggiungere al componente una classe specifica che fornisca al framework di Joomla le informazioni necessarie a compiere le operazioni sui dati nella tabella.

Per fare questo bisogna aggiungere un altro file al componente

File myform.php

in .../administrator/components/com_myform/tables/
class TableMyForm extends JTable {
  var $id = null;
  var $nome = null;
  var $cognome = null;
  var $telefono = null;
  var $indirizzo = null;
  var $note = null;
  var $data = null;

Una variabile di classe per ogni campo della tabella sul database con lo stesso nome del campo. Niente di più semplice!

  function __construct(& $db) {
    parent::__construct('#__myform', 'id', $db);
  }
} //Fine class TableMyForm

Il nome della tabella e del campo chiave primaria (id) sono necessari alle funzioni del framework per gestire le operazioni sui dati della tabella (inserimento, modifica, cancellazione).

File myform.xml

in .../administrator/components/com_myform/

Il file xml del componente dovrà essere aggiornato per riflettere le modifiche che abbiamo appena apportato.

1)
...
</files>
<install>
  <sql>
    <file charset="utf8" driver="mysql">install.sql</file>
  </sql>
</install>
<uninstall>
  <sql>
    <file charset="utf8" driver="mysql">uninstall.sql</file>
  </sql>
</uninstall>
...

I tag <install> e <uninstall>, com'è facile intuire, servono ad indicare quale dei due script deve essere eseguito in fase di installazione e quale in fase di disinstallazione del componente.

Gli attributi del tag <file> charset e driver in questa versione di Joomla vanno sempre impostati rispettivamente come utf-8 e mysql.

2)
 
...
<administration>
  <menu>My Form</menu>
  <files folder="admin">
    <filename>admin.myform.php</filename>
    <filename>tables/myform.php</filename>
    <filename>install.sql</filename>
    <filename>uninstall.sql</filename>
  </files>  
</administration>
...

Poiché i tag <filename> sono collocati tra <administration> e </administration> i due script e il file contenente la definizione della classe TableMyForm saranno installati in .../administrator/components/com_myform/

L'attributo folder del tag <files> indica che tutti questi files si trovano nella cartella admin del pacchetto di installazione.

Processare i dati ricevuti dal modulo

Facciamo un passo indietro. Se avete installato la versione preliminare del componente e creato un link ad esso secondo le istruzioni contenute nel post precedente, fate click sul link per visualizzare la pagina con il modulo di immissione dati. Con l'opzione Visualizza Sorgente Pagina del vostro browser controllate il codice html generato per il modulo.

Troverete

<form name="myform" method="post" action="index.php">
...
<input type="hidden" name="option" value="com_myform" />
<input type="hidden" name="task" value="submit" />

Vale la pena ricordare che questo codice è generato dal Template (in .../components/com_myform/views/myform/tmpl/default.php)

Le variabili passate attraverso i due campi hidden sono essenziali.

  • option comunica al framework di passare il controllo al file principale del componente com_myform
  • task indica l'azione che deve essere eseguita.

Il file principale del nostro componente è .../components/com_myform/myform.php e contiene, come abbiamo già visto, le due istruzioni seguenti

$controller = new MyFormController();
$controller->execute(JRequest::getVar('task'));

Il metodo execute() del Controller (implementato nella classe base JController) riceve come parametro il valore di task letto in questo caso da $_POST (method="post" nel tag di apertura <form>)

Il Controller esegue il metodo corrispondente al valore di task, nel nostro caso submit.

Non resta che implementarlo in .../components/com_myform/controller.php

class MyFormController extends JController {
 
  function submit() {
    $data = JRequest::getVar('myform', array(), 'post', 'array');
    $model =& $this->getModel('myform');
  
    if ($model->store($data)) {
      $this->setRedirect(
        JRoute::_('index.php?option=com_myform', false), 
        JText::_('Modulo Inviato con Successo')
      );
    } else {
      $view =& $this->getView('myform', 'html');
      $view->setModel($model);
      $view->assignRef('data', $data);
      $view->display();    
    }
  }
}

Per prima cosa la funzione JRequest::getVar legge da $_POST l'array myform. Tornando al sorgente html del modulo, poiché abbiamo

<input type="text" name="myform[nome]" id="nome" size="25" />

$data['nome'] conterrà il valore immesso nel campo nome. Stessa cosa per tutti gli altri campi.

Poi, ottenuto un riferimento all'oggetto Model se ne invoca il metodo store() passando come parametro l'array di dati da memorizzare nella tabella del database.

Se l'operazione ha avuto successo si imposta un reindirizzamento alla pagina principale del componente (setRedirect()).

In caso di errore il controllo torna a View perché il modulo deve essere mostrato nuovamente. Si utilizza setModel() per passare all'oggetto View un riferimento all'oggetto Model. La struttura dati che definisce la struttura del modulo è in Model quindi View deve poter accedere a Model.

Per consentire all'utente di correggere l'errore senza perdere tutti i dati già inseriti, si passa a View (con assignRef()) un riferimento all'array $data che verrà utilizzato per reimpostare il valore dei campi del modulo.

Il codice che fa questo è in .../components/com_myform/views/myform/tmpl/default.php

Infine si esegue la visualizzazione invocando il metodo display() di View.

Scriviamo il codice per il metodo store() di Model in .../components/com_myform/models/myform.php

class MyFormModelMyForm extends JModel {
  ...
  function store($data) {
    $row =& $this->getTable();
    if (!$row->bind($data)) {
      JError::raiseWarning(500, $row->getError());
      return false;
    }
    if (!$row->check()) {
      JError::raiseWarning(500, $row->getError());
      return false;
    }
    if (!$row->store()) {
      JError::raiseWarning(500, $row->getError());
      return false;
    }
    return true
  } 
}

Si ottiene per prima cosa un riferimento all'oggetto Table del nostro componente(classe TableMyForm)

Il metodo bind() della classe JTable (la classe base da cui abbiamo derivato TableMyForm) fa una cosa semplicissima. Legge campo per campo l'array $data e quando trova una corrispondenza tra una chiave dell'array e il nome di una variabile di classe di TableMyForm, assegna alla variabile di classe il valore corrispondente nell'array.

Quindi se abbiamo

$data['nome'] = 'Pippo'

Dopo l'esecuzione del metodo bind avremo

$row->nome = 'Pippo'

Il metodo bind() ritorna false in caso di errore. In questo caso si esce dalla funzione impostando una condizione di errore. Di JError e la gestione degli errori in Joomla si parlerà un'altra volta.

Il metodo check() di JTable è il metodo standard utilizzato per i controlli di validità sui dati prima di procedere al salvataggio degli stessi sul database. Lo implementeremo in seguito nella nostra classe TableMyForm.

Il metodo store() di JTable salva i dati nel database. Non dobbiamo scrivere nessuna istruzione sql. Una volta creata una istanza della nostra classe TableMyForm, e valorizzatene opportunamente i campi con il metodo bind(), le funzioni del framework hanno tutte le informazioni necessarie per creare ed eseguire la query sql.

Nota a margine. Le operazioni sul database eseguite dal componente di esempio sono solo quelle di inserimento: ogni volta che il modulo è inviato con successo un nuovo record è creato nel database. Non ci sono funzioni di modifica di un record esistente. Ma se ci fossero (e su questo per ora vi tocca fidarvi sulla parola), potremmo gestirle senza modifiche al codice del metodo store() dell'oggetto Model (MyFormModelMyForm).

Questo perché il metodo store() di JTable (occhio! Stesso nome del metodo, ma classi diverse) gestisce sia le operazioni di inserimento che quelle di modifica di un record.

E come fa a sapere quando eseguire l'una e quando l'altra?

Quando abbiamo creato la classe TableMyForm abbiamo indicato un campo (id) come chiave primaria.

function __construct(& $db) {
  parent::__construct('#__myform', 'id', $db);
}

Il metodo store() inserisce un nuovo record se la variabile di classe id in TableMyForm è null (o zero), altrimenti modifica il record con chiave corrispondente al valore di tale variabile.

Poiché non abbiamo un campo di nome id nel modulo di immissione dati, quando viene eseguito il metodo $row->bind() il valore di $row->id resta null, di conseguenza $row->store() crea sempre un nuovo record.

Validazione dati immessi nel modulo

Se lasciassimo il tutto così, cosa che sarei tentato di fare visto che mi sono dilungato in maniera mostruosa, il componente non effettuerebbe nessun controllo di validità sui dati immessi dall'utente. Quello che si inserisce nel modulo viene salvato nel database.

Il bello è che se si preme Invia lasciando il modulo vuoto, nel database viene creato un record nuovo con tutti i campi vuoti.

Direi che sia il caso di ovviare almeno a quest'ultimo inconveniente, lasciando come esercizio al lettore (la solita scusa quando uno non ha più voglia di scrivere!) l'implementazione di controlli più sofisticati.

Stabiliamo che il campo Nome e Cognome debbano essere obbligatoriamente inseriti. Si è già accennato che i controlli di validità sui dati si effettuano con il metodo check() dell'oggetto Table.

Abbiamo già inserito la chiamata al metodo nel codice dell'oggetto Model (in store()), però se non lo implementiamo in TableMyForm sarà utilizzato il metodo corrispondente della classe base JTable che si limita a ritornare sempre true, in pratica il controllo di validità darebbe sempre esito positivo.

Quindi inseriamo in TableMyForm in .../administrator/components/com_myform/tables/myform.php

class TableMyForm extends JTable {
...
  function check() {
    if (trim($this->nome) == '') {
      $this->setError (JText::_('Inserire il Nome.'));
      return false;
    }
    if (trim($this->cognome) == '') {
      $this->setError(JText::_('Inserire il Cognome.'));
      return false;
    }
    return true;
  }
} //Fine class TableMyForm

Non c'è molto da dire. Per effetto del metodo bind(), $this->nome e $this->cognome contengono i valori immessi dall'utente nei campi corrispondenti del modulo. Se anche uno solo è vuoto si imposta un messaggio di errore e si esce con false.

E' tutto per ora. Il componente può essere scaricato dal sito (myform2.zip) e installato. Se avete installato la versione precedente disinstallatela.

Potete provare a inserire dati nel modulo e inviarlo, ma ancora mancano le funzioni di visualizzazione dei dati per cui dovrete usare phpMyAdmin (o un altro strumento per l'amministrazione di MySql) per verificare che quanto inserito nel modulo sia salvato nella tabella.

La prossima volta completeremo il componente aggiungendo le funzioni di amministrazione.

martedì 28 agosto 2007

Joomla 1.5: Sviluppo Componenti

La versione 1.5 di Joomla, attualmente allo stadio di RC1 (scaricabile dal sito ufficiale www.joomla.org), ha introdotto parecchi cambiamenti all'insieme di classi e funzioni di base dedicate allo sviluppo di moduli, componenti e plugins.

In particolare il nuovo framework renderà più semplice agli sviluppatori di componenti organizzare il proprio codice secondo il modello MVC (Model-View-Controller).

Una spiegazione sul modello MVC ed i sui benefici è presente, in inglese, sul wiki per sviluppatori nel sito ufficiale di Joomla per cui possiamo lasciare da parte ogni disquisizione teorica e passare direttamente a vedere con un esempio pratico come sviluppare un componente per Joomla 1.5.

Ho pensato che un componente per l'acquisizione di dati possa essere un buon componente di esempio. E' abbastanza facile da realizzare, ma nello stesso tempo non è troppo banale.

Il nome del componente è MyForm e queste sono le sue funzioni base.

  • Visualizzazione di un modulo di immissione dati
  • Salvataggio nel database dei dati immessi dall'utente
  • Visualizzazione dei dati immessi in un semplice formato tabellare.

Struttura di un componente Joomla 1.5

Paragonati ai componenti per le versioni 1.0.xx, i componenti della nuova versione hanno una struttura molto più modulare, ed interamente orientata agli oggetti. Il framework mette a disposizione classi base (JModel, JView, JController), da cui lo sviluppatore deriva le classi necessarie al proprio componente.

La struttura di base di un componente è questa:

  • Un file principale (entry point)
  • Uno o più oggetti Controller.
  • Uno o più oggetti Model.
  • Uno o più oggetti View. Ad ogni View viene associato uno o più Template.

Consiglio di tenere a portata di mano il codice del componente (myform1.zip scaricabile dal sito) per seguire meglio il discorso.

Entry point. File myform.php

in .../components/com_myform/
Dove i puntini rappresentano il percorso completo alla cartella dove è stato installato Joomla

defined('_JEXEC') or die('Restricted access');

Serve ad assicurarsi che si possa accedere al componente solo da Joomla. Un qualsiasi tentativo di eseguirne il codice dall'esterno di Joomla (per es. invocando direttamente la url www.miosito.ext/components/myform.php) viene bloccato da questa istruzione. Si tratta di un'importante misura di sicurezza e questa riga deve sempre essere inserita all'inizio di ogni file che fa parte del componente.

require_once(JPATH_COMPONENT.DS.'controller.php');

Include il file contenente la definizione della classe controller. JPATH_COMPONENT è una costante che contiene il percorso assoluto sul server della cartella del componente. DS (directory separator) è un'altra costante che contiene '/' o '\' a seconda del sistema operativo su cui si è installato Joomla. E' consigliabile utilizzare questa costante nei percorsi passati alle istruzioni require ed include per garantirsi che il codice sia indipendente dal sistema operativo.

$controller = new MyFormController();

Crea l'oggetto controller.

$controller->execute(JRequest::getVar('task'));

JRequest::getVar legge una variabile dalla URL. Il controller riceve il valore di tale variabile tramite il metodo execute() ed esegue la relativa funzione.

$controller->redirect();

Serve ad eseguire una eventuale redirezione di pagina decisa dal controller. Maggiori dettagli in seguito.

Il codice del file principale (o punto di ingresso) del componente è tutto qui. La sua funzione è di creare un'istanza dell'oggetto controller e indicargli la funzione da eseguire.

Controller. File controller.php

in .../components/com_myform/
defined('_JEXEC') or die('Restricted access');

jimport('joomla.application.component.controller');
Della funzione della prima riga si è già detto. jimport è una funzione di servizio utilizzata per includere librerie di base in alternativa alle funzioni include e require del PHP. In questo caso viene inclusa la definizione della classe base del Controller (JController) che si trova in .../libraries/joomla/application/component/controller.php
class MyFormController extends JController {

}

Definisce l'oggetto Controller principale del componente. Ci limitiamo a definire la classe senza implementare alcun metodo. In questa versione preliminare del componente tutto il lavoro viene svolto dalla classe base JController.

Se avrete la pazienza di arrivare fino alla fine di questa serie di articoli vedrete che arriverà il momento di scrivere qualcosa in questa classe.

Model. File myform.php

in .../components/com_myform/models/
defined('_JEXEC') or die();
jimport('joomla.application.component.model');

Niente di nuovo.

class MyFormModelMyForm extends JModel {
  var $form = array(
    'name'=>'myform',
    'fields' => array (
      array('label'=>'Nome',
      'name'=>'myform[nome]',
      'id'=>'nome'),
      array('label'=>'Cognome',
      'name'=>'myform[cognome]',
      'id'=>'cognome'),
      array('label'=>'Telefono',
      'name'=>'myform[telefono]',
      'id'=>'telefono',
      'size'=>15),
      array('label'=>'Indirizzo',
      'name'=>'myform[indirizzo]',
      'id'=>'indirizzo',
      'size'=>40),
      array('label'=>'Note',
      'name'=>'myform[note]',
      'id'=>'note',
      'rows'=>10,
      'cols'=>40,
      'type'=>'textarea'),
      array('name'=>'Invia',
      'type'=>'submit'),
      array('name'=>'option',
      'value'=>'com_myform',
      'type'=>'hidden'),
      array('name'=>'task',
      'value'=>'submit',
      'type'=>'hidden')
    )
  );
  function getForm() {
   return $this->form;
 }
}

L'oggetto Model contiene la logica applicativa del componente, definisce le entità che il componente deve gestire e i metodi che interagiscono con esse.

Nel nostro esempio definiamo una struttura che rappresenta un modulo di immissione dati: un array associativo di cui il campo fields è a sua volta un array di array associativi attributo/valore. E' una di quelle cose che si capiscono meglio guardando il codice piuttosto che con una spiegazione a parole!

Definiamo poi un metodo getForm() che semplicemente ritorna questa struttura dati

View. File view.html.php

in .../components/com_myform/views/myform/
defined('_JEXEC') or die('Restricted access');
jimport('joomla.application.component.view');

class MyFormViewMyForm extends JView {
  function display($tpl = null) {
    $model =& $this->getModel();
    $form = $model->getForm();
    $this->assignRef('form', $form);
    parent::display($tpl);
  }
}

Definisce l'oggetto View principale a cui è demandata la visualizzazione dei dati.

Per ogni oggetto View sono definiti uno più Template che determinano l'aspetto e l'organizzazione della visualizzazione.

I compiti del metodo display() sono

  • Recuperare un riferimento all'oggetto Model tramite il metodo JView::getModel()
  • Ricevere dall'oggetto Model la struttura da visualizzare tramite il metodo getForm() che abbiamo definito nella classe MyFormModelMyForm
  • Tramite il metodo assignRef() associare una etichetta a questa struttura dati in modo da poterla recuperare all'interno del template.
  • Invocare il metodo display() della classe base JView che passa il controllo al template per la visualizzazione.

Template. File default.php

in .../components/com_myform/views/myform/tmpl/

Non riporto tutto il codice trattandosi di semplici istruzioni di visualizzazione. La struttura che definisce il modulo di immissione dati è letta campo per campo, vengono impostati valori predefiniti per gli attributi che fossero stati lasciati vuoti, quindi il codice HTML viene visualizzato.

File di installazione myform.xml

Per ogni componente deve essere creato un file XML con le informazioni utilizzate dalla procedura di installazione per copiare al posto giusto tutti file necessari.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE install SYSTEM 
"http://dev.joomla.org/xml/1.5/component-install.dtd">
<install type="component" version="1.5.0">
 <name>Myform</name>
 <version>1.0</version>
 <description>
   Esempio di componente per l'immissione di dati.
 </description>
 <files folder="site">
  <filename>myform.php</filename>
  <filename>controller.php</filename>
  <filename>views/myform/view.html.php</filename>
  <filename>views/myform/tmpl/default.php</filename>
  <filename>models/myform.php</filename>
 </files>
 
 <administration>
  <menu>My Form</menu>
  <files folder="admin">
   <filename>admin.myform.php</filename>
  </files>  
 </administration>
</install>

Il file admin.myform.php deve essere inserito altrimenti avremo un errore al momento dell'installazione del componente, ma al momento è vuoto perchè non sono ancora presenti le funzioni di amministrazione.

La versione preliminare del componente è pronta e può essere scaricata dal sito (myform1.zip) Per installare il componente in Joomla

  • Accedere all'area di amministrazione sito.
  • Selezionare il menu Extensions -> Install/Unistall
  • Premere il pulsante Sfoglia a fianco del campo Package File. Selezionare il file zip appena scaricato e confermare.
  • Premere Upload File & Install

Se tutto è andato bene dovreste vedere un breve testo descrittivo del componente.

Inoltre una voce My Form sarà presente sotto il menu Components anche se l'unica cosa che vedrete se la selezionate è una pagina vuota visto che non abbiamo ancora scritto le funzioni di amministrazione.

E' necessario a questo punto includere un link al componente per poterlo testare.

  • Selezionare il menu Menus -> Menu Manager
  • Fare click sotto la colonna Menu Items in corrispondenza del menu mainmenu o othermenu (o un altro menu dove volete inserire il link al componente)
  • Nella pagina seguente selezionare l'icona New
  • Selezionare sotto Internal Link, My Form -> MyForm -> Default Layout
  • Impostare un titolo per la voce di menu e salvare.

Ritornati sulla pagina principale del sito selezionare la voce del menu appena inserita. Comparirà il modulo di immissione dati.

Questo è tutto. Per il momento il componente non svolge nessun altra funzione. Aggiungeremo il resto in un prossimo articolo.

martedì 14 agosto 2007

Menu a tendina in Javascript

Creare un menu a tendina (drop down menu per gli anglofoni) in Javascript non è niente di trascendentale, tanto che di applicazioni di questo tipo se ne trovano parecchie sui molti siti che offrono collezioni di script.

Quello presentato qui è uno script semplice, ma che può essere utile per imparare (o ripassare) qualche tecnica di programmazione a oggetti in Javascript e altre cose interessanti (credo) come, ad esempio, utilizzare Javascript per aggiungere dinamicamente elementi alle pagine html.

Lo script si chiama QMenu ed è scaricabile dal sito, l'archivio compresso contiene anche alcune pagine dimostrative.

Dovrebbe essere abbastanza facile da utilizzare anche per chi fosse semplicemente interessato al risultato finale, un menu a tendina per il proprio sito, senza preoccuparsi più di tanto dei dettagli di funzionamento.

Installazione

Contenuto di qmenu.zip

  • qmenu.js
  • qmenu.css
  • license.txt
  • cartella esempi

Solo qmenu.js e qmenu.css devono essere installati sul vostro sito e richiamati nel blocco di intestazione (tra i tag <head> e </head>) della pagina dove si vuole far apparire il menu. I super-principianti possono far riferimento al sorgente delle pagine dimostrative (cartelle esempi del pacchetto)

Creare la struttura del menu a tendina

Si inseriscono le seguenti istruzioni tra i tag <body> e </body> della pagina dove si vuole fare apparire il menu a tendina.

<div class="qmenu-main" id="qmenu-main" style="position:relative"></div>

Questo è il contenitore del menu e va inserito nella posizione esatta della pagina dove si vuole visualizzare il menu. E' l'unico tag html che dovrete scrivere, il resto del menu a tendina verrà generato dinamicamente dallo script.

Sempre nel corpo della pagina (anche immediatamente prima di </body> va bene) si inseriscono le istruzioni per creare la struttura del menu. Per esempio

<script type="text/javascript">
var myMenu=new qmenu('qmenu-main');

Si crea l'oggetto principale del menu. Il costruttore riceve come parametro il valore dell'attributo ID del tag div contenitore creato in precedenza.

myMenu.setStyle({
   'width':135,
   'height':25,
   'orientation':0,
   'textColor':'#0000ff',
   'bgColor':'#f3f3f3',
   'mouseOverBgColor':'#00ff00',
   'borderColor':'#a0a0a0'
});

Si impostano le proprietà base degli elementi del menu.

  • width: Larghezza (in pixel)
  • height: Altezza (in pixel)
  • orientation: 0=menu in orizzontale, 1=menu in verticale.
  • textColor: Colore del testo
  • bgColor: Colore di sfondo
  • mouseOverBgColor: Colore di sfondo quando il puntatore del mouse passa sopra l'elemento.
  • borderColor: Colore del bordo.

I valori impostati da setStyle possono essere modificati per ogni singolo elemento del menu. Vediamo prima come aggiungere i singoli elementi, le voci del menu.

myMenu.add('Home','','/','m1');

Parametri del metodo add (nell'ordine)

  • Testo della voce del menu
  • ID dell'elemento padre. In questo caso è vuoto perché stiamo aggiungendo un elemento al primo livello.
  • URL da usare per il link
  • ID dell'elemento del menu. Tutti gli elementi del menu hanno un ID univoco.
Proseguendo
myMenu.add('Prodotti','','prodotti.html','prod');
myMenu.add('Categoria1','prod','categoria1.html','cat1');
mnu=myMenu.add('Categoria2','prod','categoria2.html','cat2');

Si aggiunge un'altra voce (Prodotti) al primo livello del menu, poi si aggiungono due altri elementi passando come secondo parametro l'ID dell'elemento Prodotti (prod). In questo modo Categoria1 e Categoria2 verranno 'appesi' sotto Prodotti.

Il metodo add ritorna sempre un riferimento all'elemento aggiunto. Questo valore di ritorno può essere ignorato oppure memorizzato in una variabile per poter successivamente accedere all'elemento e modificarne le proprietà.

In questo caso il riferimento all'elemento relativo alla voce Categoria2 è salvato nella variabile mnu. Si può quindi scrivere ad esempio

mnu.bgColor='#c0c0c0';

La voce Categoria2 avrà un colore di sfondo diverso da quello impostato con il metodo setStyle all'inizio. Quando si crea la struttura del menu capiterà di dover creare un gruppo di elementi con lo stesso stile. In questo caso sarebbe scomodo modificare le proprietà per ogni singolo elemento.

Basterà usare di nuovo il metodo setStyle in questo modo

myMenu.setStyle({'bgColor':'#99ffff','width':120});
myMenu.add('Prodotto1','cat1','prodotto1.html','prod1');
myMenu.add('Prodotto2','cat2','prodotto2.html','prod2');

Il colore di sfondo e la larghezza impostati da setStyle divengono i valori predefiniti per tutti gli elementi del menu aggiunti successivamente (in questo caso Prodotto1 e Prodotto2).

Una volta finito di creare la struttura, non resta che mostrare il menu con

myMenu.display();
</script>

qmenu.css

Lo stile e la posizione del testo all'interno delle voci del menu sono controllati tramite foglio di stile css.

Quello utilizzato nell'esempio visto finora è il seguente

#qmenu-main div {
   font-family: arial;
   font-size:15px;
   cursor: pointer;
}
.qmenu-inside {
   margin-top:3px;
   text-align: center;
}
.qmenu-inside a{
   text-decoration: none;
}

Chiaramente si può modificare come si vuole. Ad esempio per avere le voci del menu a tendina allineate a sinistra invece che centrate all'interno del proprio elemento, basta rimuovere text-align: center; da .qmenu-inside.

In particolare l'attributo margin-top (sempre in .qmenu-inside) dovrà essere modificato se si cambia l'altezza degli elementi del menu.

Futuri sviluppi

Ci sono diverse possibilità di migliorare la funzionalità dello script

  • Consentire di impostare un'immagine di sfondo variabile al passaggio del mouse sopra l'elemento.
  • Consentire di affiancare un'icona al testo di ogni voce del menu.

Come funziona

Il codice non dovrebbe essere troppo difficile da capire, a meno che non si sia proprio alle primissime armi con Javascript. Spiegarlo tutto riga per riga sarebbe troppo lungo, darò qualche indicazione generale, i commenti ci sono apposta per chi voglia approfondire il discorso.

L'applicazione si compone di due oggetti.

qmenu - Contiene alcune proprietà globali e i metodi per la creazione della struttura del menu a tendina e per il suo funzionamento.

qmenu-item - Contiene le proprietà che determinano lo stile di ciascun elemento (voce) del menu e il metodo per la visualizzazione (expand) degli elementi figli, quelli cioè che appartengono al livello immediatamente sottostante del menu.

Un'oggetto qmenu-item non è mai creato direttamente, viene creato dal metodo add di qmenu ed aggiunto alla proprietà items di qmenu stesso con il proprio ID come chiave.

Ogni oggetto qmenu-item mantiene un riferimento al proprio contenitore (qmenu) nella proprietà menu. La proprietà children è un array che contiene le chiavi (ID) degli elementi figli.

Tutto il codice html è generato dinamicamente. Ogni oggetto qmenu-item si occupa (metodo expand) della visualizzazione degli elementi figli.

Licenza

QMenu è uno script open source distribuito con licenza GNU GPL. E' liberamente utilizzabile e modificabile secondo i termini della licenza.

sabato 11 agosto 2007

Introduzione

Perché un blog sullo sviluppo di applicazioni per la Rete. Mi è venuta voglia di iniziare un blog (sembra lo facciano tutti ormai!) e questo è un argomento che mi interessa ed appassiona.

Sono un programmatore con esperienza nella realizzazione di applicazioni gestionali e per il commercio elettronico nonché strumenti ed applicativi per la gestione dei contenuti e l'amministrazione di siti web.

Ma l'informatica e lo sviluppo software in particolare sono stati per molto tempo una passione prima di diventare un lavoro.

Gli argomenti trattati più frequentemente saranno la programmazione in linguaggio PHP, Javascript e AJAX, la realizzazione di componenti e moduli per prodotti cms, personali impressioni d'uso su strumenti di sviluppo, librerie e framework. Il tutto nel modo più rilassato possibile, senza fare 'lezioni' (ci mancherebbe altro), ma piuttosto quattro chiacchiere tra amici.

L'intenzione è comunque quella di fare poca teoria e scrivere molto codice realizzando mini applicazioni che servano realmente a qualcosa e non siano solo esempi di programmazione.

Non resta che iniziare.

mercoledì 1 agosto 2007

Le vostre Domande e Suggerimenti

Controllando su Google Analytics le statistiche sulle parole chiave utilizzate per trovare questo blog sui motori di ricerca, mi capita molto spesso di trovare frasi di ricerca estremamente specifiche.

Una cosa che mi fa impazzire è capire dalle parole chiave utilizzate che sarebbe stato facile dare una risposta, ma allo stesso tempo sapere che quel particolare argomento non è mai stato trattato sul blog e quindi chi ha fatto la ricerca questa risposta non può averla trovata.

Per questo ho pensato di dare la possibilità ai visitatori del blog di inviare le loro domande o suggerire un argomento da trattare.

Ovviamente le domande non possono essere sul senso profondo della vita, la Filosofia o l'allevamento dei criceti, ma solo su argomenti attinenti al tema del blog: sviluppo applicazioni web, php, javascript, cms e simili.

Credo comprenderete che non posso promettere di rispondere a tutti, ma cercherò di fare del mio meglio. Le risposte saranno sempre pubbliche, qui sul blog, quindi tanto più la domanda è di interesse generale tanto maggiori saranno le possibilità di ricevere una risposta.

Per inviare una domanda o suggerimento basta lasciare un commento a questo post o utilizzare il modulo che trovate qui sotto. Se usate il modulo, dopo l'invio sarete reindirizzati su una pagina dove dovrete inserire un codice numerico anti-spam. Fatelo o non vedrò mai il vostro messaggio!