Tutorial: creare un componente per Joomla 1.5

Questo post è un tutorial scritto per introdurre allo sviluppo di componenti per Joomla 1.5.

Il componente creato per l'esempio si chiama com_allarmi, e permette agli utenti registrati al sito di inserire da frontend un allarme nel sistema, memorizzato in una apposita tabella del DB MySQL.

Un allarme è composto da un'ora e da un giorno. Ogni utente inserisce allarmi in modo indipendente dagli altri utenti del sito, e attraverso il componente può vedere tutti gli allarmi che ha impostato.

Il backend mostra tutti gli allarmi impostati, classificati per utente.

Notare che allo scoccare degli allarmi non succede niente, è solo un esempio di applicazione :)

Essendo un tutorial introduttivo non ho preso in considerazione l'architettura MVC.

Prima di partire, potete scaricare il codice del componente finito.

Iniziamo

Creare un'installazione di Joomla in locale e testare che funzioni correttamente.

Se non avete un editor di codice preferito, prendete in considerazione EasyEclipse, una versione di Eclipse preconfigurato per lo sviluppo di Web Application in PHP, quindi perfetto per Joomla.

Aprire EasyEclipse e creare due progetti PHP: uno chiamato com_allarmi con location Joomla/components/com_allarmi (frontend), l'altro com_allarmi_admin con location Joomla/administrator/components/com_allarmi (backend).

All'interno della cartella frontend creare un file allarmi.php e una cartella di nome 'views'. Al suo interno creare una cartella chiamata 'all'.
All'interno della cartella backend creare un file admin.allami.php

FRONTEND

Aprire il file allarmi.php ed inserire le seguenti linee di codice

< ?php
//no direct access
defined('_JEXEC') or die('Restricted access');
echo '
<div class="componentheading">Allarmi'
?>

La riga

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

indica che il codice deve essere eseguito all'interno di Joomla e non può essere richiamato dall'esterno.

echo '
<div class="componentheading">Allarmi</div>
 
'

inserisce il div nella pagina HTML.

Puntare ora il browser all'indirizzo joomla/index.php?option=com_allarmi.

Verrà visualizzata una pagina riportante il titolo del componente, così come lo abbiamo dichiarato usando la classe CSS componentheading.

/FRONTEND

BACKEND

In admin.allarmi.php inseriamo il codice

< ?php
//no direct access
defined('_JEXEC') or die('Restricted access');
echo 'Allarmi';
?>

Apriamo la pagina joomla/administrator/index.php?option=com_allarmi, dove vedremo la scritta 'Allarmi' che campeggia all'interno di una pagina vuota.

/BACKEND

Come abbiamo potuto notare Joomla divide nettamente il codice inerente la parte di amministrazione (backend) e la parte visualizzata all'interno del sito (frontend).

Per poter inserire il componente all'interno del workflow di Joomla è necessario registrarlo nel database, nella tabella jos_components.

Aprite il vostro tool preferito per accedere al database (CocoaMySQL o phpMyAdmin sono perfetti, oppure direttamente la console di MySQL) e create una nuova voce nella tabella usando il codice

INSERT INTO `jos_components` VALUES (42, 'Allarmi', 'option=com_allarmi', 0, 0, 'option=com_allarmi', 'Allarmi', 'com_allarmi', 0, '', 0, '', 1);

Se viene generato un errore, cambiare il primo valore per modificare il numero univoco che identifica il componente (l'ID).

A questo punto accedendo al backend selezionare il menu Components: dovrebbe essere visibile la voce 'Allarmi', e selezionandola dovrebbe aprirsi la pagina che abbiamo visto poco fa.

Possiamo anche aggiungere un collegamento al frontend inserendo una voce nel main menu: selezionare Menus, Main Menu, premere il pulsante New, selezionare la voce Internal Link -> Allarmi. Selezionare All e dare un titolo alla voce di menu: "Allarmi", quindi premere Save.

In frontend sarà visibile la voce "Allarmi" nel menu principale, e premendola verrà visualizzata la pagina vista in precedenza.

Bene! Lo scheletro base del componente è stato creato. Ma da bravo scheletro, questo componente non fa ancora nulla.

Costuiamo intorno allo scheletro

Creiamo una tabella nel DB per memorizzare gli allarmi che gli utenti inseriscono.

CREATE TABLE `jos_allarmi` (
`id` int(11) DEFAULT NULL auto_increment,
`user` int(11) DEFAULT NULL,
`orario` time DEFAULT NULL,
`giorno` date DEFAULT NULL,
primary key(id)
);

BACKEND

Creiamo la cartella tables ed un file chiamato allarme.php.

< ?php
//no direct access
defined('_JEXEC') or die('Restricted access');
 
class TableAllarme extends JTable {
	var $id = null;
	var $user = null;
	var $orario = null;
	var $giorno = null;
 
	function __construct(&$db) {
		parent::__construct( '#__allarmi', 'id', $db);
	}
}
?>

Questo file viene creato per gestire la tabella del database in modo che non dobbiamo scrivere il codice per interagire direttamente con l'SQL, ma astraiamo il concetto, usando la classe JTable - da cui tra l'altro ereditiamo i metodi bind(), store(), load() e delete(), che useremo più tardi.

/BACKEND

FRONTEND

Torniamo ad agire sul file allarmi.php, inserendo il codice

< ?php
//no direct access
defined('_JEXEC') or die('Restricted access');
 
echo '
<div class="componentheading">Allarmi';
 
jimport('joomla.application.helper');
require_once(JApplicationHelper::getPath('html'));
JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.$option.DS.'tables');
 
switch($task) {
  default:
  	showAllarmi($option);
	break;
}
 
function showAllarmi($option) {
	$user =& JFactory::getUser();
	$db =& JFactory::getDBO();
	$query = "SELECT * FROM #__allarmi WHERE user=".$user->id." ORDER BY giorno DESC";
	$db->setQuery($query);
	$rows = $db->loadObjectList();
	if ($db->getErrorNum()) {
		echo $db->stderr();
		return false;
	}
	HTML_allarmi::showAllarmi($rows, $option);
}
?>

Questo codice importa la classe helper che ci servirà per includere il file allarmi.html.php e la classe che abbiamo definito per usare la tabella jos_allarme.

Il codice è molto semplice e in ogni caso viene lanciata la funzione showAllarmi, che si collega al database e recupera tutte le voci presenti nella tabella jos_allarmi, quindi passa il comando ad allarmi.html.php.

Provando a ricaricare nel browser la pagina joomla/index.php?option=com_allarmi verrà mostrato un messaggio di errore: Joomla non trova il file che abbiamo indicato di includere. Lo creiamo ora, allarmi.html.php.

< ?php
//no direct access
defined('_JEXEC') or die('Restricted access');
 
class HTML_allarmi {
	function showAllarmi($rows, $option) {
		?>
<table>< ?php
		echo "
<tr>
<th>ID</th>
<th>Utente</th>
<th>Ora</th>
<th>Giorno</th>
 
";
		foreach ($rows as $row) {
			echo '
<tr>
<td>'.$row->id.'</td>
<td>'.$row->user.'</td>
<td>'.$row->orario.'</td>
<td>'.$row->giorno.'</td>
</tr>
 
';
		}
		?></table>
 
< ?php
	}
}
?>

Questo file organizza una semplice tabella mostrando i valori degli allarmi.

Inseriamo un valore di esempio nel database

INSERT INTO `jos_allarmi`
VALUES (
'1', '62', NOW( ) , '2008-08-21'
);

Dove 62 è l'id dell'utente amministratore.

Se apriamo la pagina di frontend come utente non registrato, non vedremo nessun allarme. Facendo il login come amministratore vedremo invece una riga con i valori appena inseriti nel database.

In effetti è più indicato aggiungere la voce che componente nel menu User, che compare soltanto quando un utente effettua il login.

/FRONTEND

BACKEND

Apriamo l'interfaccia di amministrazione ed eliminiamo la voce Allarmi nel Main Menu, ed inseriamola nello User Menu.

Il backend per ora non svolge alcuna operazione. Vediamo di elencare tutti gli allarmi impostati.

In admin.allarmi.php inseriamo

< ?php
//no direct access
defined('_JEXEC') or die('Restricted access');
 
jimport('joomla.application.helper');
require_once(JApplicationHelper::getPath('admin_html'));
JTable::addIncludePath(JPATH_COMPONENT.DS.'tables');
 
switch($task) {
  default:
  	showAllarmi($option);
	break;
}
 
function showAllarmi($option) {
	$db =& JFactory::getDBO();
	$query = "SELECT * FROM #__allarmi ORDER BY giorno DESC";
	$db->setQuery($query);
	$rows = $db->loadObjectList();
	if ($db->getErrorNum()) {
		echo $db->stderr();
		return false;
	}
	HTML_allarmi::showAllarmi($rows, $option);
}
?>

Ed in admin.allarmi.html.php

< ?php
//no direct access
defined('_JEXEC') or die('Restricted access');
 
class HTML_allarmi {
	function showAllarmi($rows, $option) {
		?>
<table>< ?php
		echo "
<tr>
<th>ID</th>
<th>Utente</th>
<th>Ora</th>
<th>Giorno</th>
 
";
		foreach ($rows as $row) {
			echo '
<tr>
<td>'.$row->id.'</td>
<td>'.$row->user.'</td>
<td>'.$row->orario.'</td>
<td>'.$row->giorno.'</td>
</tr>
 
';
		}
		?></table>
 
< ?php
	}
}
?>

Questo codice ricalca quasi fedelmente quello usato per il frontend, le differenze risiedono nel file admin.allarmi.php, dove il path per la cartella tables è diverso e non ci interessano le informazioni sull'utente, in quanto carichiamo tutti gli allarmi inseriti.

/BACKEND

Creiamo una form per inserire nuovi allarmi

Non vi è ancora modo di inserire un nuovo allarme, per cui ora modifichiamo il frontend.

FRONTEND

Prendiamo il file allarmi.html.php e modifichiamo la funzione showAllarmi, in modo che inserisca un link alla fine della tabella, che rimandi al componente, con task newAlarm. Inoltre aggiungiamo la funzione newAlarm, che ha il compito di mostrare la form per l'inserimento di un nuovo allarme.

	function showAllarmi($rows, $option) {
		?>
<table>< ?php
		echo "
<tr>
<th>ID</th>
<th>Utente</th>
<th>Ora</th>
<th>Giorno</th>
 
";
		foreach ($rows as $row) {
			echo '
<tr>
<td>'.$row->id.'</td>
<td>'.$row->user.'</td>
<td>'.$row->orario.'</td>
<td>'.$row->giorno.'</td>
</tr>
 
';
		}
		?></table>
 
< ?php
		echo '<a href="index.php?option=com_allarmi&task=newAlarm">Crea nuovo allarme';
	}
 
	function newAlarm($id, $option) {
		JHTML::_('behavior.calendar');
		?>
<form action="index.php?option=com_allarmi&task=salvaAllarme" method="post" name="formNuovoAllarme" id="formNuovoAllarme">
<table>
<tr>
<td>
			   Orario:
<input type="text" name="orario" id="orario" />
			  </td>
</tr>
<tr>
<td>
			   Giorno:
<input type="text" name="giorno" id="giorno" />
<input type="reset" class="button" value="..." onclick="return showCalendar('giorno', '%d-%m-%Y');" />
			  </td>
</tr>
<tr>
			 </tr>
</table>
<input type="hidden" name="user" value="<?php echo $id; ?/>" />
<input type="submit" class="button" value="crea" />
		</form>
 
 < ?
	}

Inseriamo il task newAlarm in allarmi.php

switch($task) {
  case newAlarm:
  	newAlarm($option);
  	break;
  default:
  	showAllarmi($option);
	break;
}

Quindi, sempre in allarmi.php, creiamo la funzione newAlarm.

function newAlarm($option) {
	$id = null;
	$user =& JFactory::getUser();
 
	if($user->id) {
		$id = $user->id;
	}
 
	$row =& JTable::getInstance('allarme', 'Table');
 
	if (!$row->bind(JRequest::get('post'))) {
		echo "<script> alert('".$row->getError()."'); window.history.go(-1); </script>\n";
		exit();
	}
 
	HTML_allarmi::newAlarm($id, $option);
}

Infine creiamo la funzione salvaAllarme, chiamata dalla form.

function salvaAllarme ($option) {
	global $mainframe;
	$row =& JTable::getInstance('allarme', 'Table');
	if (!$row->bind(JRequest::get('post'))) {
		echo "<script> alert('".$row->getError()."'); window.history.go(-1); </script>\n";
		exit();
	}
	if (!$row->store()) {
		echo "<script> alert('".$row->getError()."'); window.history.go(-1); </script>\n";
		exit();
	}
	$mainframe->redirect('index.php?option='.$option, 'Allarme salvato');
}

Dobbiamo ulteriormente modificare lo switch

switch($task) {
  case newAlarm:
  	newAlarm($option);
  	break;
  case salvaAllarme:
  	salvaAllarme($option);
  	break;
  default:
  	showAllarmi($option);
	break;
}

Facciamo una nuova modifica a showAllarmi, in modo che non sia visibile agli utenti non registrati.

function showAllarmi($option) {
	$user =& JFactory::getUser();
 
	if($user->id == 0) {
		echo "Occorre il login per visualizzare questa pagina";
	}
	else {
		$db =& JFactory::getDBO();
		$query = "SELECT * FROM #__allarmi WHERE user=".$user->id." ORDER BY giorno DESC";
		$db->setQuery($query);
		$rows = $db->loadObjectList();
		if ($db->getErrorNum()) {
			echo $db->stderr();
			return false;
		}
		HTML_allarmi::showAllarmi($rows, $option);
	}
}

Siamo a buon punto

A questo punto il componente funziona come dovrebbe: provate ad effettuare il login come utente e premete il pulsante "Crea nuovo allarme".

Inserite l'ora nel formato di MySQL, ovvero 17:34:37 e selezionate una data dal calendario premendo il pulsante "...".

Cliccando 'Crea' verrà inserito l'allarme nel database, e mostrato insieme agli altri che avete creato.

Effettuando il logout e collegandosi come un altro utente, non verranno visualizzati gli allarmi degli altri utenti, mentre da admin sarà possibile vedere tutto.

Conclusioni

Questo componente è un primo esempio di sviluppo per Joomla 1.5. Prima di poter usare un componente di questo tipo occorre come minimo introdurre una protezione contro SQL injection, andando a controllare bene i valori che vengono digitati nella form.

In caso contrario il componente potrebbe essere soggetto a problemi di sicurezza.

E' possibile scaricare il codice del componente.