In questa pillola voglio trattare un problema molto comune (circa una volta alla settimana almeno qualcuno chiede come fare), ovvero la creazione di menù option (a tendina per intenderci) in modo dinamico. Ad esempio:
Ho un primo menù option dove posso scegliere il genere musicale. A dipendenza del genere che scelgo, nel secondo option avrò la lista di musicisti che suonano quel genere, una volta scelto il musicista, nel terzo option, troverò l'elenco degli album.
Solitamente chi risponde, me compreso, consiglia di implementare una soluzione ajax. Molto elegante non c'è dubbio, ed anche funzionale. Mi rendo conto che purtroppo in diversi vengono però scoraggiati da questa tecnologia.
Ho provato dunque a realizzare una cosa del genere senza utilizzare ajax, ma solo con un po' di javascript.
Il risultato è forse un po' laborioso ma è efficace.
Per il nostro esempio prenderò in considerazione la realizzazione di tre option menù che listano le regioni, le province, i comuni.
Dunque una volta selezionata la regione, nell'option delle province troverò le province di quella regione. Ed una volta selezionata la provincia, nell'option comuni troverò i comuni di quella provincia.
Ovviamente tutti questi dati dovrò averli in un database. Cominciamo dunque a vedere come strutturarlo.
Immagino che tutti sappiate cosa si intende per database relazionale, ma visto che non ne sono sicuro, faccio una brevissima premessa.
Nel realizzare il database, sarebbe assurdo che facessi una tabella per le regioni, per ogni provincia di ogni regione una tabella e per ogni comune di ogni provincia una tabella. Mi ritroverei un database di migliaia di tabelle e praticamente ingestibile.
Farò invece 3 tabelle. Una per le regioni, una per le province, e una per i comuni. Sfruttando le chiavi primarie di ogni tabella, le metterò poi in relazione.
In questo modo:
Tabella regioni:
ID – regione
Tabella province:
ID – id_regione – provincia
Tabella comuni:
ID – id_provincia – comune
In questo modo se l'id della regione Lombardia è 6, nella tabella delle province la provincia di Como avrà in id_regione il numero 6, come pure ad esempio la provincia di Varese.
Creiamo allora la struttura del database:
CREATE TABLE `regioni` (
`id` int(10) unsigned NOT NULL auto_increment,
`regione` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE `province` (
`id` int(3) unsigned NOT NULL auto_increment,
`id_regione` int(3) unsigned NOT NULL,
`provincia` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE `comuni` (
`id` int(4) unsigned NOT NULL auto_increment,
`id_provincia` int(3) unsigned NOT NULL,
`comune` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
E mettiamoci anche qualche dato (non tutti ovviamente, ma almeno per fare qualche prova).
Adesso, la prima cosa che dovremo fare, è inserire nell'header della pagina una funzione javascript da richiamare nei menù a tendina. Scopo di questa funzione è di ricaricare la pagina al momento della selezione. Chiaramente ricaricheremo la pagina passando dei parametri, ma questo lo vedremo dopo.
Codice PHP:
<SCRIPT language=JavaScript>
<!--
function goSelect(daform)
{
with(daform)
{
top.window.location=options[selectedIndex].value;
}
}
//-->
</SCRIPT>
Siccome andremo a creare una classe, questo script lo metteremo in un metodo della nostra classe; metodo che richiameremo poi nell'header della pagina. Lo vedremo in seguito.
Creiamo il file db_config.php (è sempre preferibile inserire i dati di connessione del db in un file esterno).
Codice PHP:
<?php
$db = "option";
$host = "localhost";
$username = "root";
$password = "password";
?>
Ed ora la classe completa (option.class.php)
Codice PHP:
session_start();
class OptionMenu
{
protected $conn;
protected $page;
public function __construct()
{
$this->page = basename($_SERVER['PHP_SELF']);
$this->DbConnectAndSelect();
$this->ParsingAction();
}
protected function DbConnectAndSelect()
{
include "db_config.php";
$this->conn = @mysql_connect($host,$username,$password) OR
die("Impossibile connettersi al server");
@mysql_select_db($db, $this->conn) OR
die("Impossibile selezionare il database");
}
public function JsHeader()
{
echo '<SCRIPT language=JavaScript>
<!--
function goSelect(daform)
{
with(daform)
{
top.window.location=options[selectedIndex].value;
}
}
//-->
</SCRIPT>
';
}
public function ShowRegioni()
{
if(isset($_SESSION['regione']))
{
$regione = $_SESSION['regione'];
}
else
{
$regione = "Seleziona una regione";
}
$sql = "SELECT id,regione FROM regioni";
$res = mysql_query($sql, $this->conn);
echo '<form>
<select onchange="goSelect(this)" size="1">
<option>' . $regione . '</option>
';
while($row = mysql_fetch_array($res))
{
if($row['regione'] != $regione)
{
echo '<option value="' . $this->page . '?id_regione=' . $row['id'] . '&action=provincia®ione=' . $row['regione'] . '">' . $row['regione'] . '</option>
';
}
}
echo '</select>
</form>
';
}
public function ShowProvince()
{
if(isset($_SESSION['provincia']))
{
$provincia = $_SESSION['provincia'];
}
else
{
$provincia = 'Seleziona una provincia';
}
echo '<form>
<select onchange="goSelect(this)" size="1">
<option>' . $provincia . '</option>
';
if($regione = $this->SelectProvincia())
{
$sql = "SELECT id,provincia FROM province WHERE id_regione='$regione'";
$res = mysql_query($sql, $this->conn);
while($row = mysql_fetch_array($res))
{
if($row['provincia'] != $provincia)
{
echo '<option value="' . $this->page . '?id_provincia=' . $row['id'] . '&action=comune&provincia=' . $row['provincia'] . '">' . $row['provincia'] . '</option>
';
}
}
}
echo '</select>
</form>
';
}
public function ShowComuni()
{
if(isset($_SESSION['comune']))
{
$comune = $_SESSION['comune'];
}
else
{
$comune = 'Seleziona un comune';
}
echo '<form>
<select onchange="goSelect(this)" size="1">
<option>' . $comune . '</option>
';
if($_GET['id_provincia'])
{
$sql = "SELECT id,comune FROM comuni WHERE id_provincia='$_GET[id_provincia]'";
$res = mysql_query($sql, $this->conn);
while($row = mysql_fetch_array($res))
{
echo '<option value="' . $this->page . '?id_comune=' . $row['id'] . '&action=end&comune=' . $row['comune'] . '">' . $row['comune'] . '</option>
';
}
}
echo '</select>
</form>
';
}
protected function SelectProvincia()
{
if(!$_GET['id_regione'] AND !$_SESSION['regione'])
{
return FALSE;
}
else
{
if($_GET['id_regione'])
{
return $_GET['id_regione'];
}
else
{
$sql = "SELECT id FROM regioni WHERE regione='$_SESSION[regione]'";
$res = mysql_query($sql, $this->conn);
$row = mysql_fetch_array($res);
return $row['id'];
}
}
}
protected function ParsingAction()
{
if(isset($_GET['action']))
{
if($_GET['action'] == 'provincia')
{
$_SESSION['regione'] = $_GET['regione'];
unset($_SESSION['provincia']);
unset($_SESSION['comune']);
}
if($_GET['action'] == 'comune')
{
$_SESSION['provincia'] = $_GET['provincia'];
unset($_SESSION['comune']);
}
if($_GET['action'] == 'end')
{
$_SESSION['comune'] = $_GET['comune'];
header("Location: result.php");
die;
}
}
}
}
Che utilizzeremo in questo modo:
Codice PHP:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>Titolo</title>
<?php
include "option.class.php";
$OpMenu = new OptionMenu();
$OpMenu->JsHeader();
// Abbiamo incluso la classe, istanziato la classe, e stampato la funzione Javascript
?>
</head>
<body>
<?php
$OpMenu->ShowRegioni();
$OpMenu->ShowProvince();
$OpMenu->ShowComuni();
// Naturalmente possono essere impaginati a piacere
?>
</body>
</html>
Una volta scelto il comune si verrà reindirizzati alla pagina result.php, a titolo di prova l'ho fatta così:
Codice PHP:
<?php
session_start();
echo 'Regione: ' . $_SESSION['regione'] . '
Provincia: ' . $_SESSION['provincia'] . '
Comune: ' . $_SESSION['comune'];
?>
Alcune considerazioni:
Utilizzo le sessioni per comodità; nel senso che mi permettono di memorizzare lo stato delle scelte ed eventualmente anche operare dei ripensamenti. Infatti, finchè non si è scelto il comune, è possibile modificare nuovamente la regione o la provincia.
E' chiaro che se dovessi scegliere un'altra regione quando ho già scelto la provincia, dovrò resettare i parametri di sessione associati alla regione e alla provincia, questo lo faccio con il metodo ParsingAction() che invoco nel costruttore. In questo modo, ogni volta che viene modificata una selezione, il metodo si occupa di assegnare il giusto stato alla sessione.