PHP: un socket TCP per acquisire dati dal GPS Tracker GPS-102 compatibile OpenGTS (seconda parte)

Socket PHP
Socket PHP

Nella prima parte di questo articolo ho illustrato come creare le tabelle del DB dove registrare i dati provenienti dal tracker GPS, le principali funzionalità dello script e la possibilità di “agganciare” questo socket direttamente al software Open Source: OpenGTS.

Quest’ultima caratteristica, la ritengo particolarmente interessante in quanto permette di evitare di scriversi tutta la parte che riguarda la visualizzazione dei punti inviati dal tracker, sulle mappe.

Settaggi del socket
ChiaveValori possibiliDescrizione
VERBOSEtrue|falseSe impostato a true fornisce un output dettagliato degli errori
MOVING_THRESHOLD.05Soglia minima in Km per la registrazione del dato [.05 = 50 metri]
OPENGTStrue|falseSe impostato a true invia query per le tabelle OpenGTS
IP_ADDRxxx.xxx.xxx.xxxIndirizzo IP in ascolto [0 = tutti gli indirizzi]
TCP_PORT0..65535La porta TCP da utilizzare
DBHOSTlocalhostIndirizzo del DB MySQL
DBUSERdbuserutente del DB MySQL
DBPASSdbpasswordpassword dell’utente del DB MySQL
DBNAMEgpsdnome del DB MySQL
POLL_TIME20|30|60|300|600Tempo di polling del tracker in secondi
SPEED_CONV1.609344|1.852Conversione da Miglia (terrestri|marine) a Km
DFLT_MSG‘tracker’Messaggio di default del tracker
SOCK_RCV_TIMEOUT120Timeout in secondi per il socket in ricezione

Ed ecco il codice PHP del loop del socket (L’intero script è disponibile qui):

Leggi tutto

PHP: un socket TCP per acquisire dati dal GPS Tracker GPS-102 compatibile OpenGTS (prima parte)

Tracker GPS 102
Tracker GPS 102

Alcuni mesi fa mi è stato regalato questo questo tracker GPS per studiare come registrare su un database MySQL i dati che vengono trasmessi. L’apparecchio si chiama GPS-102 viene prodotto dalla Cobanch ed è disponibile anche in Italia ad un costo inferiore a 100€ su questo sito: www.nonsoloprevenzione.it

Poiché le informazioni della documetazione allegata sono, come spesso accade, piuttosto scarse, mi sono messo alla ricerca nel Web delle specifiche tecniche e del datagramma per la comunicazione dei dati forniti dal tracker (coordinate, velocità, ecc). Fortunatamente ho trovato questo foglio di calcolo, che si riferisce ai modelli TK102, TK103 ma il protocollo risulta identico e fornisce dunque le informazioni necessarie allo sviluppo del software.

Leggi tutto

P4A 3 Framework: helper per sincronizzare le tabelle sequence in MySQL

P4A 3 LogoChi utilizza l’RDBMS MySQL in P4A avrà certamente notato che il framework produce in certi casi, delle tabelle il cui nome termina in ‘_seq’. Queste tabelle servono ad avere una compatibilità nella gestione di tutti gli RDBMS supportati (MySQL, PostgreSQL, SQLite, Oracle). PostgreSQL e Oracle, non hanno lo stesso tipo di gestione delle chiavi primarie con l’attributo ‘AUTOINCREMENT‘, rispetto a MySQL e SQLite. La soluzione adottata è di costruire, per ogni tabella con chiave primaria di tipo ‘AUTOINCREMENT’, delle tabelle accessorie che hanno un campo ‘id’ di tipo ‘AUTOINCREMENT’ e di riferirsi a quest’ultime per ottenre il ‘LAST INSERT ID‘. In questo modo viene ricalcato il comportamento delle chiavi primarie di tipo ‘SERIAL’ in PostgreSQL, e anche quelle di Oracle (leggermente diverse).

Prima di tutto una precisazione: questo articolo è riferito esclusivamente agli utenti MySQL.
Se si pensa di utilizzare esclusivamente P4A Framework per la gestione dei dati del nostro database, sarebbe bene in fase di progettazione evitare di usare gli AUTOINCREMENT perché, come detto, non necessari. Nel caso in cui il framework venga utilizzato come ‘backoffice’ per la gestione di dati che vengono alimentati da un form di un sito web, oppure si abbia la necessità di utilizzare una struttura dati pre-esistente con tanto di chiavi primarie ‘AUTOINCREMENT’, potremmo prima o poi trovarci di fronte ad un problema di disallineamento dei valori fra la chiave primaria della tabella e l’id’ della tabella ‘_seq’ associata.

Immaginiamo di avere una tabella “test” con questi due campi:

+----+---------+
| id | name    |
+----+---------+

con ‘id’ chiave primaria, P4A creerà automaticamente una tabella “test_id_seq” con una campo ‘id’ chiave primaria e ‘AUTOINCREMENT’, ed userà i valori forniti da quest’ultima sia per l’inserimento di nuovi record nella tabella “test“, che per altre operazioni sulla chiave primaria. Dunque utilizzando un programma esterno al framework per fare degli inserimenti e volendo mantenere allineate le tabelle principali e le tabelle “_seq” sarà necessario, per ogni “INSERT” nella tabella principale, fare altrettanto nella “_seq”!
Anche utilizzando questo metodo, potrebbe verificarsi prima o poi il problema di un disallineamento, in questo caso ho pensato potesse utile scrivere un metodo della classe “P4A_DB_SOURCE” da utilizzare in extremis, per risistemare le cose.

Per maggiori informazioni sull’utilizzo degli ‘helper’ in P4A suggerisco questo link

Ecco il codice dell’helper, in pratica viene prelevato il valore massimo della chiave primaria ‘AUTOINCREMENT’ della tabella che funge da sorgente dati, quindi viene eliminata la tabella ‘_seq’ associata e successivamente ricostruita con il valore corretto.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 function p4a_db_source_resync_seq($source)
 
 { 
	$table = $source->getTable();
	$pKField = $source->getPk();
	$seqTable =  $table."_".$pKField."_seq";
	$lastId = P4A_DB::singleton()->fetchOne("SELECT MAX($pKField) FROM $table");
	$query = "DROP TABLE IF EXISTS `$seqTable`";
	$resQ1 = P4A_DB::singleton()->query($query);
	$query = "CREATE TABLE `$seqTable` (
	`id` int(11) NOT NULL auto_increment,
	PRIMARY KEY  (`id`)
	) TYPE=MyISAM AUTO_INCREMENT=$lastId";
 
	$resQ2 = P4A_DB::singleton()->query($query);
	$query = "INSERT INTO `$seqTable` VALUES ($lastId)";
	$resQ3 = P4A_DB::singleton()->query($query);
  return ($resQ1 && $resQ2 && $resQ3); 
 
 }

Questo codice deve essere inserito in un file con il nome: “p4a_db_source_resync_seq.php” che deve essere posizionato nella directory “libraries” della nostra applicazione P4A.

Ecco infine un po’ di codice di esempio da aggiungere alla nostra ipotetica maschera di manutenzione del db:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class test extends P4A_Base_Mask
{
	public function __construct()
 
	{
		parent::__construct();
 
		// DB Source
		$this->build("p4a_db_source", "source")
			->setTable("test")
			->setPk("id")
			->load();
		$this->setSource($this->source);
 
		// ....
 
	    $this->build("p4a_button", "btn_resync")
			->setLabel("resync")
			->implement("onclick", $this, "resync_seq_table");
 
		// ....
	}
 
	public function resync_seq_table()
	{
		$res = $this->source->resync_seq();	
	}
 
	// ....
}

Conclusioni

Questo metodo dovrebbe essere usato con una certa cautela, e solo come procedura di emergenza. Non consiglio l’utilizzo se c’è la possibilità di accesso in scrittura alla tabella coinvolta da parte di altri utenti.

Riferimenti ed approfondimenti:

PHP: Quando Tartaglia e Fibonacci si davano la mano

Tartaglia e FibonacciDi certo, in vita i due non si sarebbero mai potuti dare la mano, essendo vissuti in epoche distanti ben tre secoli. Fibonacci, al secolo Leonardo Pisano, visse infatti a cavallo del 1200 ed era di famiglia benestante essendo il padre (Bonaccio, da qui il nome FiBonacci) il segretario della Repubblica di Pisa e responsabile del commercio con l’Africa. Fu proprio in Africa che ebbe modo di studiare le avanzate tecniche matematiche, al tempo in possesso del mondo arabo.
Tartaglia, al secolo Niccolò Fontana visse a cavallo del 1500 fra Brescia e Verona. Era di famiglia tutt’altro che ricca, e rimase orfano di padre quando era ancora molto giovane. Ebbe anche la disgrazia di rimanere sfregiato durante il sacco di Brescia del 1512 ad opera dell’esercito francese. A leggere il suo stesso racconto c’è da stupirsi di come sia riuscito a sopravvivere a ferite così gravi. Rimase diversi giorni senza poter parlare e mangiare cibi solidi proprio a causa dei colpi di spada inferti sulla sua testa, e quando guarì non riuscì più a parlare senza balbettare, da questo il suo soprannome Tartaglia con il quale divenne famoso.

Il triangolo di Tartaglia

Tutti noi ricordiamo, dai tempi delle superiori, la piramide di numeri che compongono il famoso triangolo di Tartaglia, e lo ricordiamo soprattutto in relazione allo studio delle potenze di un binomio.

Triangolo di Tartaglia

Ogni riga, riporta i coefficienti dell’espansione del binomio con esponente uguale al numero di riga – 1 (iniziando a contare dal vertice della piramide) Così ad esempio, per esponente 3 avremo:
(a + b)3 = 1a3 + 3a2b + 3ab2 + 1b3

La successione di Fibonacci

La successione dei numeri di Fibonacci è nota soprattutto per la particolarità che il rapporto tra un numero e quello precedente, man mano che si procede nella successione, tende alla sezione aurea La successione fu trovata da Fibonacci, rispondendo al quesito: “Supponiamo di avere una coppia di conigli, che dopo un mese è in grado di generare una seconda coppia di conigli, quante coppie avremo in un anno?” (Ammesso che ogni coppia generi sempre e solo una coppia al mese e nessuno muoia…). Il procedimento è molto semplice: ogni numero, ad eccezione dei primi due (1, 1), è la somma dei due che lo precedono. Quindi:
F(12) = 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144

Dove si incontrano Tartaglia e Fibonacci?

Per capire il punto di contatto fra i due, è necessario modificare la forma del triangolo di Tartaglia, disponendo i numeri nelle celle che costituiscono un triangolo rettangolo piuttosto che isoscele, in questo modo:

Triangolo di Tartaglia

I numeri che costituiscono le diagonali ascendenti di questa matrice triangolare, sommati fra loro, generano la successione di Fibonacci.

Ecco dunque una classe PHP che calcola i valori del triangolo di Tartaglia e poi estrae dalle diagonali ascendenti i numeri della successione di Fibonacci.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class tartfibo
{
  var $tartaglia;
  var $fibonacci;
  var $max;
 
  function tartfibo($max=10)
  {
    $this->max = $max;
    $this->tartaglia = array();
    $this->fibonacci = array();    
    $this->makeTartaglia();
    $this->makeFibonacci();
  }
 
  function makeTartaglia ()
  {
    $this->tartaglia[1][1] = 1;
    $this->tartaglia[2][1] = 1;
    $this->tartaglia[2][2] = 1;
    for($row=3; $row< =$this->max; ++$row) {
      $this->tartaglia[$row][1] = 1;
      for ($col=2; $col< $row; ++$col) {
        $this->tartaglia[$row][$col] = $this->tartaglia[$row-1][$col-1]
                                + $this->tartaglia[$row-1][$col];
      }
      $this->tartaglia[$row][$row] = 1;
    }    
  }
 
  function makeFibonacci ()
  {
    for ($d=1; $d< =$this->max; ++$d) {
      $t = 0;
      for($el=1; $el< =($d+1)/2; ++$el) {
        $t += $this->tartaglia[$d+1-$el][$el];
      }
      $this->fibonacci[$d] = $t;
    }
  }  
}

Demo:

In questa pagina è visibile una demo della classe per n=15.

Download

Il download della classe è disponibile qui.

Conclusioni:

Il triangolo di Tartaglia racchiude nei suoi numeri, diversi piccoli segreti e non è solo un metodo per calcolare i coefficienti binomiali. Provate, per esempio a sommare i numeri di ciascuna riga, partendo dall’alto, danno le potenze di 2. Esistono persino dei frattali! Infine, due grandi matematici, Newton e Pascal hanno rielaborato il suo triangolo per lo studio del calcolo combinatorio. Anche i numeri di Fibonacci, oltre alla relazione con la sezione aurea, hanno implicazioni interessanti, sia con la disposizione geometrica di molte strutture naturali (piante soprattutto) che con l’informatica, per esempio: Fibonacci heap

Riferimenti ed approfondimenti:

PHP: una classe per il calcolo di matrici di distanze euclidee, cityblock e Minkowski

EuclideSono diversi gli ambiti nei quali può essere necessario raggruppare elementi di un certo insieme in base a differenze registrate attraverso misure sul campo. In questi casi per la determinazione dell’entità delle differenze, viene usata la distanza che può essere considerata al di là del suo significato metrico, una misura della diversità. I campi di applicazione possono essere i più disparati: dagli aspetti biologici come per esempio differenze genotipiche o fenotipiche di individui o popolazioni, agli aspetti socio-economici come redditi, produttività o consumo.
Non tutte le variabili, però, possono essere trattate allo stesso modo. Solo le variabili che vengono definite “ad intervallo”, possono essere utilizzate per calcolare distanze di tipo metrico come le distanze euclidee, city-block (o Manhattan) e di Minkowski. Parliamo quindi di variabili quantitative. Negli altri casi, a seconda del tipo di variabile utilizzato (dicotomiche, categoriali, ecc) le differenze possono essere comunque calcolate mediante l’utilizzo di distanze non metriche o ultra-metriche.
A questo punto è bene definire cosa sono le distanze metriche. Sono quelle che rispettano i seguenti enunciati:

  • la distanza tra due punti che non coincidono deve essere positiva;
  • la distanza tra due punti che coincidono è pari a 0;
  • la distanza tra due punti deve essere simmetrica (d AB = d BA),

e non contravvengono la proprietà della disuguaglianza triangolare, cioè dati tre punti A, B e C deve essere verificata la condizione che:
d AB < d AC + d BC
riassumendo, si può dire che sono quelle che seguono la metrica pitagorica.

Fatta questa doverosa premessa, passiamo ad analizzare le formule delle distanze metriche utilizzate
nella classe PHP.

Distanze Euclidee

E’ senza dubbio il tipo di distanza più diffuso. La formula per il calcolo deriva dalla formula della distanza fra 2 punti in un piano cartesiano e può essere espressa come:

Formula per il calcolo delle distanze euclidee

in cui xik e xjk sono le misure in posizione i e j rispettivamente della k-esima di n variabili.

Distanze city-block (Manhattan)

Viene anche detta distanza assoluta o della metrica del taxi. La sua formula è:

Formula per il calcolo delle distanze city-block

La particolarità di questa formula sta nel fatto che, considerando la distanza euclidea fra 2 punti A e C di un triangolo ABC, e che questa distanza può essere espressa come la radice quadrata della somma dei quadrati costruiti sui cateti del triangolo ABC, la distanza di city-block è la somma dei cateti di questo triangolo. Il concetto risulta forse più chiaro osservando la figura qui sotto.

Triangolo di esempio

Non a caso, il nome Manhattan deriva proprio dalla particolare disposizione delle strade del famoso quartiere di New York, che si incrociano ad angolo retto, formando una sorta di scacchiera. In effetti questo tipo di distanza, ben si presta a rappresentare il percorso reale fra due punti che si trovano in prossimità degli angoli opposti di un palazzo (…o grattacielo!)

Distanze di Minkowski

Rappresenta la forma più generalizzata di distanza metrica. La sua formula è:

Formula per il calcolo delle di minkowski

Si dice di ordine p, e in particolare quando p=1, coincide con la distanza city-block,
e quando p=2, coincide con la distanza euclidea, come si evince dalla formula. Per p -> infinito coincide con la distanza di Lagrange o di Chebychev.

La classe PHP che ho preparato permette di calcolare, scegliendo una delle distanze illustrate sopra, una matrice triangolare (nella quale la diagonale assume valori = 0) di confronto fra tutti i campioni passati in input. La matrice dati da passare come parametro al costruttore deve avere questo formato:

1
2
3
4
5
6
7
8
9
10
11
12
$dataTest = array (
                "sample01" => array(82.897,488,0.6381,8.576),
                "sample02" => array(37.04,512,0.7935,7.9293),
                "sample03" => array(86.571,617,0.1518,0.9705),
                "sample04" => array(76.038,876,0.0883,5.5867),
                "sample05" => array(67.726,687,0.9145,9.2478),
                "sample06" => array(34.407,979,0.8148,3.8348),
                "sample07" => array(52.258,462,0.7132,3.716),
                "sample08" => array(75.141,652,0.8453,8.3466),
                "sample09" => array(17.546,322,0.0483,1.5812),
                "sample10" => array(35.786,502,0.6899,3.1447)
                );

Ed ecco dunque il codice PHP della classe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
class DistanceMatrix
{
 var $dataArray = null;
 var $dataSize = 0;
 var $dataVectSize = 0;
 
 function DistanceMatrix($data)
 {
  $this->dataArray = array();
  $this->dataArray = $data;
  $this->checkData();
 }
 
 function checkData()
 {
  $this->dataSize = count($this->dataArray);
  if($this->dataSize < 2){
   die("Cannot proceed: only one sample, or missing data");
  }
  reset ($this->dataArray);
  $this->dataVectSize = count(current($this->dataArray));
  foreach ($this->dataArray as $key => $vectData){
   $vectSize = count($vectData);
   if ($vectSize != $this->dataVectSize){
    die("Cannot proceed: different size vectors!");
   }
  }
 }
 
 function euclidean ($vect1,$vect2)
 {
  $qdist = 0.0;
  for($i=0;$i< $this->dataVectSize;$i++){
   $qdist += pow($vect1[$i]-$vect2[$i],2);
  }
  return sqrt($qdist);
 }
 
 function manhattan ($vect1,$vect2)
 {
  $dist = 0.0;
  for($i=0;$i< $this->dataVectSize;$i++){
   $dist += abs($vect1[$i]-$vect2[$i]);
  }
  return $dist;
 }
 
 function minkowski($vect1,$vect2,$exp) {
  $edist = 0.0;
  for($i=0; $i< $this->dataVectSize; $i++){
   $edist += pow(abs($vect1[$i]-$vect2[$i]), $exp);
  }
  return pow($edist, 1/$exp);
 }
 
 function printData($distType,$exp=1)
 {
  if (!method_exists($this,$distType)) {
   die ("Sorry, can't find $distType method!");
  }
  echo ("<h1>Matrix of $distType distances </h1>\n");
  echo ("<table class='datatable' summary='Results'>\n");
  echo ("<thead><tr>");
  echo ("<th>&nbsp;</th>");
  foreach ($this->dataArray as $key=>$data){
   echo ("<th>".$key."</th>");
  }
  echo ("</tr></thead><tbody>\n");
  foreach ($this->dataArray as $keyA=>$dataA){
   echo ("<tr>");
   echo ("<td><strong>".$keyA."</strong></td>");
   foreach ($this->dataArray as $keyB=>$dataB){
    if ($distType=="minkowski"){
     printf("<td>%.4f</td>",$this->minkowski($dataA,$dataB,$exp));
    }
    else{
     printf("<td>%.4f</td>",$this->$distType($dataA,$dataB));
    }
   }
   echo ("</tr>\n");
  }
  echo ("</tbody></table>\n");
 }
}

Demo:

In questa pagina è visibile una demo della classe con dei campioni ipotetici e delle variabili di test.

Download

Il download della classe completa del file di esempio è disponibile qui.

Conclusioni:

La naturale conclusione della produzione di una matrice di distanze è l’elaborazione di una cluster analisys. Questo metodo permette di leggere visivamente i raggruppamenti dovuti alle similarità o diseguaglianze indicate dalle distanze calcolate. Tali raggruppamenti potranno essere espressi in forma gerarchica. Un software distribuito con licenza GNU che permette queste elaborazioni, e che suggerisco
è Cluster 3.0, disponibile per Linux, Windows e MacOSX.

Riferimenti ed approfondimenti:

P4A 3 framework: personalizzare il tema grafico con icone e colori

Le icone di P4ASulla personalizzazione dell’aspetto grafico delle maschere di P4A, esiste già questo interessante screencast di Fabrizio Balliano. Trovo interessante poter cambiare la grafica perché l’aspetto di default, sebbene gradevole e riposante, in alcuni casi, per esempio sugli schermi dei netbook appare un po’ troppo poco contrastato. Il tema alternativo proposto nello screencast è “Human” per Gnome, davvero molto bello!
Il set di impostazioni per i colori e il set di icone vengono generati a partire da script PHP. Entrambi gli script sono disponibili in P4A Wiki nella sezione: “Theme customizations”, il requisito è di farli girare su una macchina Linux, che sia dotata del necessario software di conversione da SVG a PNG. Ho pensato di scrivere questo post, anche se in gran parte è una ripetizione dello screencast di Fabrizio, perché qualcuno si potrebbe trovare in difficoltà scoprendo al primo approccio che lo script che genera il set di icone, per funzionare correttamente, necessita di una particolare libreria.

Dunque, la situazione migliore è che possediamo una distro “Ubuntu“, quindi con installato il Desktop Gnome. Per prima cosa, ci dobbiamo accertare che sia installato il programma rsvg che fa parte della libreria librsvg. Se non è presente (in genere non lo è…), l’installazione è davvero molto semplice utilizzando apt-get:

sudo apt-get install librsvg2-2

invece, se volete perdere tempo e avete già installate tutte le librerie per il supporto alle manipolazioni dei formati SVG, potete installare il pacchetto manualmente. Queste librerie sono comunque necessarie: libxml2 e libxml2-dev

Questo è il link per l’installazione del software rsvg:
http://ftp.gnome.org/pub/GNOME/sources/librsvg/2.22/librsvg-2.22.3.tar.bz2

scompattate il pacchetto con:

tar -xjvf librsvg-2.22.3.tar.gz.bz2

ed infine compilate:

  • sudo ./configure
  • sudo make
  • sudo make install

Ci siamo, ora possiamo lanciare lo script di Fabrizio che genera il set di icone, in questo caso il set Human per Gnome:

php build_icon_theme.php /home/directory/che/volete /usr/share/icons/Human /usr/share/icons/gnome

Adesso copiate le icone generate che saranno raggruppate nelle cartelle con il nome 16 e 32 nella directory human che si deve trovare all’interno di p4a/icons e aggiungete il seguente codice all’interno del file index.php della vostra applicazione P4A, prima della riga di codice: require_once dirname(__FILE__) . '/../../p4a.php'; e con le icone abbiamo finito.

define('P4A_ICONS_NAME', 'human');

In pratica lo script recupera le icone che servono a p4a e le copia, creando la struttura di directory necessaria, nella cartella /directory/che/volete. Se non sono disponibili nel formato richiesto, le genera dai modelli scalabili in SVG, oppure le cerca fra quelle del tema Gnome. Naturalmente, è sempre possibile aggiustare alcuni set a mano. Per esempio, ho notato che nella generazione del tema “Human”, l’icona “folder open”, risulta di colore grigio ed è piuttosto differente da “folder”, così l’ho sostituita con quella generata per il tema “Tangerine”.

Per quanto riguarda lo schema dei colori, dovete procurarvi lo script PHP: gtkrc2p4a.php per importare gli schemi Gnome gtkrc. Per generare il set di colori che armonizza le icone “Human”, digitate da linea di comando:

php gtkrc2p4a.php /usr/share/themes/Human/gtk-2.0/gtkrc

L’esecuzione genera il seguente set di impostazioni da copiare e incollare dentro index.php (sempre prima di: require_once dirname(__FILE__) . '/../../p4a.php';):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
define('P4A_THEME_FG', '#101010');
define('P4A_THEME_BG', '#EFEBE7');
define('P4A_THEME_BORDER', '#d7d3cf');
define('P4A_THEME_INPUT_FG', '#1A1A1A');
define('P4A_THEME_INPUT_BG', '#FFF');
define('P4A_THEME_INPUT_BORDER', '#e5e5e5');
define('P4A_THEME_SELECTED_FG', '#1A1A1A');
define('P4A_THEME_SELECTED_BG', '#FFA443');
define('P4A_THEME_SELECTED_BORDER', '#e5933c');
define('P4A_THEME_TOOLTIP_FG', '#000');
define('P4A_THEME_TOOLTIP_BG', '#F5F5B5');
define('P4A_THEME_TOOLTIP_BORDER', '#dcdca2');
define('P4A_THEME_EVEN_ROW', '#eee');
define('P4A_THEME_ODD_ROW', '#fff');

Sembra fatta, ma c’è ancora qualcosa di imperfetto. Se nella vostra applicazione è presente un “tab-panel” i bordi rimangono colorati dell’azzurro di default, e lo sfondo del bottoncino per il passaggio da un pannello all’altro, rimane azzurro chiaro. Così per essere pignoli rimane da modificare un poco il CSS in questo modo:

Create un file provacss.php con le seguenti istruzioni per il CSS (io l’ho messo nella directory libraries della mia applicazione):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
header('Content-type: text/css');
?>
.p4a_tab_pane ul.tabs {
	border-bottom: 1px solid <?php echo $_GET['input_border'] ?>;
}
.p4a_tab_pane ul.tabs li a {
	border: 1px solid <?php echo $_GET['input_border'] ?>;
}
.p4a_tab_pane ul.tabs a:hover {
	background: <?php echo $_GET['selected_bg'] ?>;
}
.p4a_tab_pane div.p4a_tab_pane_page {
	border: 1px solid <?php echo $_GET['input_border'] ?>;
}

Nel file principale della vostra applicazione, quello che estende la classe base p4a, inserite questo codice:

$this->addCss(P4A_APPLICATION_LIBRARIES_PATH."provacss.php?". $this->getCssConstants());

E il gioco è fatto! In pratica, è possibile aggiungere un CSS dinamico che carica, mediante querystring, le costanti determinate dal tema adottato.

Ecco uno screeshot della mia applicazione per la gestione delle fatture “vestita” con Human-gnome:

Screenshot di gestione fatture con tema Human
Screenshot di gestione fatture con tema Human

Download

Per chi non avesse a disposizione un ambiente Linux (ma cosa aspetta a farlo?) metto a disposizione il set di icone Human che ho generato qui

Conclusioni

Una volta compreso il meccanismo, personalizzare p4a è piuttosto semplice. Mi sono divertito anche a creare un tema “Vista like”, tanto per non spiazzare troppo i clienti “allineati” a M$…

Riferimenti ed approfondimenti:

  • Screencast di Fabrizio Balliano: “Theme customizations in RC5”
  • P4A Wiki

Fabrizio Balliano ha scritto:

ottimo articolo come sempre, vedo però di risolvere il problema del tab pane perché va fixato :)
23.02.09 09:41
Fabrizio Balliano ha scritto:

risolto e committato :)