Share |

domenica 29 agosto 2010

PHP: Validare numeri, date ed email

In questo articolo PHP voglio presentare il componente open source Validate.

Sostanzialmente si tratta di una libreria molto utile ed affidabile, da utilizzare ogni volta che si devono compiere operazioni di validazione su alcuni tipi di dati, quali:

  • Numeri: range di valori, min/max, decimali ed altro;
  • Stringhe: trasformazioni ad altri tipi predefiniti;
  • E-mail: sintassi, verifica di indirizzi e domini;
  • Date: operazioni su date e formattazione;
  • URI: secondo la direttiva RFC2396

Il componente solitamente non è distribuito insieme ai package predefiniti(Es: GDLib e CURL) e quindi probabilmente sarà necessario installarlo tramite PEAR (PHP Extension and Application Repository).

Che cos'è PEAR?

Traduzione della descrizione riportata sul sito:
"PEAR è un framework ed un sistema di distribuzione di componenti PHP riusabili."

In parole povere è un repository nel quale risiedono componenti PHP aggiuntivi pronti per essere installati, al pari di RubyGems per il mondo Ruby e Ruby on Rails.

Per installare la libreria Validate si posso seguire le istruzioni disponibili su siti sopra elencati ed anche questo articolo presente su HTML.it, nel caso tu debba installare anche PEAR.

Di seguito alcuni esempi per dimostrare la facilità d'utilizzo della libreria Validate.

Validare un indirizzo email.

La classe Validate per la validazione di indirizzi email mette a disposizione il metodo statico email(string, options[]).

Le opzioni offerte dalla libreria sono molte ed importanti, è consigliata una lettura sul sito di riferimento.

Il secondo parametro, ovvero un array di opzioni, è una caratteristica fondamentale per utilizzare a fondo la libreria e comune a tutti i metodi che saranno analizzati nelle successive sezioni dell'articolo.

<?php
require_once 'Validate.php';

if (!Validate::email('mickey@topolinia.car'))
    echo 'Indirizzo email non validato.';
else
    echo 'Indirizzo email validato.';

?>

Nell'esempio precedente, il metodo email(indirizzo) è utilizzato per eseguire un controllo solo dal punto di vista sintattico-formale, ossia che non esistano errori di forma e di punteggiatura.

Nel seguente, invece, al metodo viene passata anche una feature per verificare la stretta aderenza alla specifica RCF822.

<?php
$email = '"Mouse, Mickey" <mickey@topolinia.car>';
if (Validate::email($email, array('use_rfc822' => true))) {
    echo 'Indirizzo email corretto.';
} else {
    echo 'Indirizzo email non corretto.';
}
?>

Nell'esempio successivo è richiesta la verifica dell'esistenza del dominio.

<?php
require_once 'Validate.php';

if (Validate::email('mickey@topolinia.car'
        , array('check_domain' => 'true')))
    echo 'Il dominio è valido ed esiste.';
else
    echo 'Il dominio non è stato validato.';

?>

Validazione di date,

Per la validazione di date e formati, la classe Validate espone il metodo statico date(string, options[]).

Nell'esempio che segue per prima cosa verrà verificata la corretta formattazione della data 061275 rispetto al pattern passato in options[], dopodiché sarà controllato che la data sia compresa nell'arco di tempo che va dal 15 Novembre 1975 al 31 Dicembre dello stesso anno.

<?php
require_once 'Validate.php';

var_dump(
    Validate::date(
        '061275',
        array(
            'format' => '%d%m%y',
            'min' => array('15', '11', '1975'),
            'max' => array('31', '12', '1975')
        )
    )
);
?>

Validare valori numerici.

La validazione di numeri è molto importante, soprattutto in ambiti assicurativi e bancari, e per fare ciò la classe Validate fornisce il metodo statico number(num, options[]).

Nell'esempio che segue, si vuole validare un numero decimale di 3 cifre decimali e il cui carattere separatore è la virgola.

<?php
require_once 'Validate.php';

echo (Validate::number('1,234', array('decimal' => ',', 'dec_prec' => 3)))
    ? echo 'Il numero è valido'
    : echo 'Il numero non è valido';
}

?>

Il prossimo esempio mostra come validare un numero negativo decimale verificando che soddisfi le condizioni:

  • utilizzare come separatore per la virgola il carattere ',' o '.';
  • essere compreso tra i valori -9 e -7;
<?php
require_once 'Validate.php';

if (Validate::number('-7,987',
        array('decimal' => '.,', 'min' => -9, 'max' => -7 )))
    echo 'Il numero è valido';
else
    echo 'Il numero non è valido';

?gt;

Validare Stringhe

Per eseguir controlli sulle stringhe, si utilizza il metodo string(string, options[]).
Il metodo, riceve due valori: la stringa da controllare e un'array di opzioni.

Le opzioni sono veramente molte e coprono tutte le esigenze, è consigliato dare uno sguardo alla documentazione ufficiale.

Nel prossimo esempio si verifica che la stringa da controllare sia scritta solo con caratteri maiuscoli e che sia composta da soli numeri e spazi, oltre ai caratteri maiuscoli.

<?php
require_once 'Validate.php';

if (Validate::string("1975 MIRKO AGRATI", array(
        'format' => VALIDATE_NUM . VALIDATE_SPACE . VALIDATE_ALPHA_UPPER)))
    echo 'La stringa è stata validata.';
else
    echo 'La stringa non è stata validata.';

?>

Validate e l'internazionalizzazione.

La libreria prevede anche la verifica di codici postali, città ed altro nell'ambito di uno specifico continente, questa validazione è chiamata validate features e rimando alla documentazione ufficiale, dalla quale ho appreso che il modulo per l'Italia non è disponibile.

Questo articolo, sebbene non approfondisce le molteplici opzioni di ogni singolo componente di verifica, mostra in maniera chiara e semplice la facilità con cui è possibile compiere tutte le operazioni che altrimenti bisognerebbe scriversi da sé.

Io la utilizzo da un bel po' e la ritengo ormai indispensabile.

Alla prossima,
MA.

giovedì 26 agosto 2010

Introdotto il componente SourceCodeDecorator

A circa un mese dalla sua anticipazione, finalmente ho introdotto il componente javascript per decorare il codice sorgente presente sul blog.

E' stata un'operazione delicata che ha richiesto continue verifiche e cambiamenti al contenuto degli articoli più datati.

Penso di aver controllato tutto, ma qualcosa si sa scappa sempre! Quindi, se navigando tra i diversi contenuti qui presenti, tu dovessi trovare qualche cosa che non ti torna o che ti pare incompleto e migliorabile, ti chiedo cortesemente di avvisarmi. Scegli te il mezzo che preferisci per comunicarmelo: email(<mirko.agrati at gmail.com>) o anche semplicemente commentando l'articolo nel quale ti sei imbattuto.

Il componente è giovane e crescerà ancora, quindi sono cosciente che ha alcune lacune, ma era importante metterlo in produzione per poterlo testare sul campo, con tutti i benefici, e gatte da pelare, che questo comporta ........

Quando riterrò la classe javascript SourceCodeDecorator abbastanza matura e definitiva, ne mostrerò il codice sorgente in un bel articolo, come mia consuetudine.

Per ora, godetevi una visualizzazione più chiara e meno faticosa di tutto il codice sorgente che ho condiviso su questo blog.

Alla prossima,
MA.

martedì 3 agosto 2010

PHP: Creare grafici ed immagini on line

In questo articolo tecnico presenterò il prototipo funzionante di un mio piccolo framework PHP utile per la creazione di immagini e grafici da inserire nelle proprie applicazioni, web o client che siano.

Tale framework, allo stato attuale, è in grado di eseguire il rendering di grafici a torta(in inglese PieChart) ed istogrammi verticali ed orizzontali.

Per avere un'idea di ciò che questa classe può generare è possibile dare uno sguardo a questi grafici PHP di esempio.

Noterai per prima cosa che sono presenti sia grafici a torte sia istogrammi, poi che i valori espressi negli istogrammi si auto-ridimensionano automaticamente e che i possibili colori delle etichette, delle barre e delle fette di torta sono praticamente infiniti.

Introduzione alla classe Picasso

La suddetta classe, che è il cuore del framework in questione, è in grado di generare immagini in molti formati tra i quali GIF, PNG e JPG/JPEG. Questo è possibile perchè Picasso utilizza i metodi esposti dalle librerie grafiche GDLib.

Effettivamente, la classe incapsula alcuni metodi delle suddette librerie ed esegue una serie di calcoli per normalizzare le dimensioni delle barre, per distribuire i vari oggetti nello spazio, per calcolare l'ampiezza degli angoli delle fette di torta e le dimensioni dell'etichette.

I metodi delle GDLib che vengono incapsulati ed utilizzati all'interno dei membri della classe Picasso sono:

  • imagestring(image,font,x,y,text,lineColor): aggiunge del testo orizzontale all'immagine;
  • imagestringup(image,font,x,y,text,lineColor): aggiunge del testo verticale all'immagine;
  • imagerectangle(image,x,y,X,Y,lineColor): disegna un rettangolo nell'immagine;
  • imagefilledrectangle(image,x,y,X,Y,lineColor): disegna un rettangolo colorato nell'immagine;
  • imagefilledarc(image,x,y,width,height,start,end,lineColor,IMG_ARC_PIE): disegna una fetta di torta colorata nell'immagine;

Prima di esporre ed analizzare il codice sorgente della classe è necessario spiegare il funzionamento del framework.

Il framework e le classi accessorie

Per funzionare esso ha bisogno, oltre alla classe Picasso, di un'altra classe per rappresentare le barre degli istogrammi, o le fette di pie charts, e di una pagina per gestire i valori da rappresentare nei grafici, istanziare l'oggetto Picasso ed inviare al client le immagini generate.

Grazie a questo framework, per scatenare la creazione delle immagini e dei grafici in una pagina HTML basterà utilizzare un semplice tag IMG come il seguente:

<img src="imageViewer.php?
  width=150&height=150&red=255&green=255&blu=255&
  type=pie&
  items=2&
  label1=IndPres&value1=100&r1=0&g1=225&b1=0&
  label2=IndNonPres&value2=0&r2=255&g2=0&b2=0" />

I dati in querystring

Che significato hanno i parametri utilizzati in querystring per il trasporto dei dati?

  • width ed height indicano le dimensioni, in pixel, dell'immagine da creare;
  • red,green e blu sono le percentuali, in formato RGB, per determinarne il colore di sfondo dell'immagine;
  • type indica che tipo di grafico si vuole ottenere, in questo caso una torta;
  • items indica quanti valori si vogliono rappresentare, in questo caso 2;
  • label1,value1,r1,g1,b1 sono le proprietà del primo dato da rappresentare graficamente, e si incrementano per ogni dato successivo;

Il gestore delle richieste: imageViewer.php

Entriamo nel vivo del codice analizzando cosa fa lo script PHP presente in imageViewer.php. Come al solito spiattello il codice sorgente commentando abbondantemente i passaggi chiave nel codice stesso:

<?php

include_once 'CPicasso.php';
include_once 'CBar.php';

//Valori di default per l'immagine
$w = 500;
$h = 300;
$red = 200;
$green = 100;
$blu = 300;

//Ricezione dei parametri in querystring
if($_GET['width'])
  $w = $_GET['width'];

if($_GET['height'])
  $h = $_GET['height'];

if($_GET['red'])
  $red = $_GET['red'];

if($_GET['green'])
  $green = $_GET['green'];

if($_GET['blu'])
  $blu = $_GET['blu'];

/**
 * Creo una istanza della classe Picasso:
 * il costruttore della classe riceve in input:
 *   1)La larghezza che deve avere l'immagine;
 *   2)L'altezza che deve avere l'immagine;
 *   3)La percentuale di Rosso che deve avere lo sfondo;  
 *   4)La percentuale di Verde che deve avere lo sfondo;  
 *   5)La percentuale di Blue che deve avere lo sfondo;  
 */
$img = new Picasso($w,$h,$red,$green,$blu);

//Ricevo il numero di items da rappresentare graficamente
if($_GET['items']){
  $items = $_GET['items'];

  //Array di Bar che Picasso disegnerà nel grafico
  $barArr = array();
   
  for($i=0;$i<$items; $i++){
    $param = $i+1;
    $lbl = "label$param";
    $value = "value$param";
    $r = "r$param";
    $g = "g$param";
    $b = "b$param";
  
    /**
     * Istanzio un oggetto Bar per ogni items ricevuto in querystring
     * il costruttore della classe riceve in input:
     *   1)L'etichetta che deve indicare l'elemento;
     *   2)Il valore che deve esprimere l'elemento;
     *   3)La percentuale di Rosso che deve avere lo sfondo;  
     *   4)La percentuale di Verde che deve avere lo sfondo;  
     *   5)La percentuale di Blue che deve avere lo sfondo;
     */
    $barArr[] = 
      new Bar($_GET[$lbl],$_GET[$value],$_GET[$r],$_GET[$g],$_GET[$b]);
  }

  /**
   * Gestione della tipologia di grafico da creare:
   * type = "hbars" -> istogramma con barre orizzontali.
   */
  if($_GET['type'] && $_GET['type'] == 'hbars')
    $img->addHorizontalBars($barArr);

  //type = "vbars" -> istogramma con barre verticali
  else if($_GET['type'] && $_GET['type'] == 'vbars')
    $img->addVerticalBars($barArr);

  //type = "pie" -> PieChart
  else if($_GET['type'] && $_GET['type'] == 'pie')
    $img->addPieChart($barArr);
}

/**
 * Setto il content-type per quello che voglio 
 * inviare al browser cliente: in questo caso
 * si tratta di un'immagine PNG.
 */
header('Content-Type: image/png');

//Invio l'immagine al client
imagepng($img->getImage());

//Distruggo l'immagine
unset($img);

?>

Riassumendo: imageViewer.php crea un array di istanze della classe Bar che l'oggetto Picasso successivamente disegnerà nel grafico scelto.

Inoltre, analizzando il codice dello script PHP presente in imageViewer.php, si è potuto vedere con che facilità è possibile scegliere quali tipologie di grafici far disegnare dalla classe Picasso, in particolare:

  • Istogrammi con barre verticali;
  • Istogrammi con barre orizzontali;
  • PieChart, ovvero grafici a Torta;

In realtà sarà dimostrato, successivamente analizzandone il codice, che la classe Picasso espone altri metodi per disegnare rettangoli colorati e con bordo, testo e archi di circonferenze.

Passiamo ora all'analisi della classe Bar, ovvero il componente di model che rappresenta una barra, una fetta di torta oppure un semplice rettangolo:

La classe Bar, ovvero un item del grafico

<?php
/**
 * Rappresenta un oggetto, o item, rappresentabile 
 * all'interno di qualunque tipologia di grafico
 * generato dal componente Picasso.
 */
class Bar{
  //Proprietà Private
  private $label = 'label';
  private $value = 0;
  private $r = 0;
  private $g = 0;
  private $b = 0;

  /**
   * Costruttore:
   * Riceve: etichetta,valore,%rosso,%verde,%blue
   */
  public function __construct($lbl,$value,$r,$g,$b){
    $this->value = $value;
    $this->label = $lbl;
    $this->r = $r;
    $this->g = $g;
    $this->b = $b;
  }

  /**
   * Metodi Setter & Getter Pubblici
   */
  public function getLabel(){
    return $this->label;
  }

  public function getValue(){
    return $this->value;
  }

  public function getRed(){
    return $this->r;
  }

  public function getGreen(){
    return $this->g;
  }

  public function getBlu(){
    return $this->b;
  }
}
?>

Il componente è molto semplice e non ha bisogno di alcun commento supplementare a ciò che è già presente nel codice sorgente, in ambito Java definirei questa classe un semplice bean.

Ciò che è importante è che Bar rappresenta la tipologia utilizzata da Picasso per effettuare il rendering grafico di barre e fette di torta all'interno dei propri grafici.

Ora, manca solo l'esposizione e l'analisi del codice sorgente base del nocciolo che
caratterizza il mio framework: ovvero la classe Picasso.

<?php

class Picasso{
  /** Dimensione del Margine tra ogni Barra */
  const BARS_MARGIN = 4;

  /** Margine interno dell'immagine */
  const IMAGE_MARGIN = 4;

  /** Dimensione del font di default */
  const DEFAULT_FONT_SIZE = 6;

  /**
   * Coefficiente di default per ricavare
   * il colore del testo in base a quello del
   * proprio contenitore 
   */
  const DEFAULT_FONT_COLOR_COEFF = 4;

  /**  Immagine Padre di tutti i grafici */
  private $image = null;

  /** Larghezza dell'immagine Padre */
  private $width = 0; 

  /** Altezza dell'immagine Padre */
  private $height = 0;

  /** Colore di sfondo dell'immagine Padre */
  private $bgColor = '';

  /**
   * Costruttore:
   * Riceve: larghezza,altezza,%rosso,%verde,%blue
   */
  function __construct($w,$h,$red,$green,$blu){
    $this->width = $w;
    $this->height = $h;
    $this->image = imagecreate($w,$h);
    $this->bgColor = $this->setColor($red,$green,$blu);
  }

  /** Aggiunge del testo alle coordinate x,y */
  public function addText($font,$x,$y,$text
        ,$linered,$linegreen,$lineblu){
    $lineColor = $this->setColor($linered,$linegreen,$lineblu);
    imagestring($this->image,$font,$x,$y,$text,$lineColor);
   }

  /** Aggiunge del testo verticale alle coordinate x,y */
  public function addVerticalText($font,$x,$y,$text
        ,$linered,$linegreen,$lineblu){
    $lineColor = $this->setColor($linered,$linegreen,$lineblu);
    imagestringup($this->image,$font,$x,$y,$text,$lineColor);
  }

  /**
   * Crea un rettangolo colorato con l'angolo 
   * alto-sinistro alle coordinate x,y
   * e con l'angolo basso-destro alle coordinate X,Y
   */
  public function addFilledRectangle($x,$y,$X,$Y
        ,$linered,$linegreen,$lineblu){
    $lineColor = $this->setColor($linered,$linegreen,$lineblu);
    imagefilledrectangle($this->image,$x,$y,$X,$Y,$lineColor);
  }

  /**
   * Crea i bordi di un rettangolo con l'angolo 
   * alto-sinistro alle coordinate x,y
   * e con l'angolo basso-destro alle coordinate X,Y
   */
  public function addEmptyRectangle($x,$y,$X,$Y
        ,$linered,$linegreen,$lineblu){
    $lineColor = $this->setColor($linered,$linegreen,$lineblu);
    imagerectangle($this->image,$x,$y,$X,$Y,$lineColor);
  }

  /**
   * Crea una fetta di Torta colorata 
   * con centro alle coordinate x,y
   * con raggio di lunghezza width, 
   * con un angolo rappresentato da start e end
   */  
  public function addFilledPieceOfPie($x,$y,$width,$height
        ,$start,$end,$red,$green,$blu){
    $lineColor = $this->setColor($red,$green,$blu);
    imagefilledarc ($this->image,$x,$y,$width,$height
      ,$start,$end,$lineColor, IMG_ARC_PIE);
  }

  /**
   * Crea una grafico a barre orizzontali:
   * riceve un array di barre con cui 
   * riempire il grafico (class CBar)
   */
  public function addHorizontalBars($barArray){
    /**
     * Coefficiente per la rappresentazione delle barre:
     * Se le barre sono piu' lunghe della dimensione dell'immagine
     * $scala viene incrementato fino a che tutte le barre possano
     * essere disegnate nell'immagine.
     */
    $scala = $this->normalizeBarsLength($barArray,$this->width);

    $nBar = count($barArray);

    //Altezza delle barre
    $h = $this->calculateBarsDimension($this->height,$nBar);

    $tempHeight = Picasso::BARS_MARGIN;
    $newY = $h + $tempHeight;

    foreach($barArray as $bar){
      try{
        $this->addFilledRectangle(Picasso::IMAGE_MARGIN
            ,$tempHeight,($bar->getValue()/$scala),$newY
            ,$bar->getRed(),$bar->getGreen(),$bar->getBlu());

        $fontSize = $this->calculateHorizontalFontSize($h);
        $this->addText($fontSize
            ,(Picasso::IMAGE_MARGIN*2)
            , $this->centerHorizontalText($fontSize,$h,$newY)
            ,$bar->getLabel() . ": " . $bar->getValue()
            ,$bar->getRed()/Picasso::DEFAULT_FONT_COLOR_COEFF
            ,$bar->getGreen()/Picasso::DEFAULT_FONT_COLOR_COEFF
            ,$bar->getBlu()/Picasso::DEFAULT_FONT_COLOR_COEFF);

        $tempHeight = $tempHeight + Picasso::BARS_MARGIN + $h;
        $newY = $tempHeight + $h;
      }
      catch (Exception $e){
        die('<br />Eccezzione: ' 
            . $e->getMessage() . '<br />');
      }
    }
  }
  
  /**
   * Crea una grafico a barre verticali:
   * riceve un array di barre con cui riempire 
   * il grafico (class CBar).
   */
  public function addVerticalBars($barArray){
    /**
     * Coefficiente per la rappresentazione delle barre:
     * Se le barre sono piu' lunghe della dimensione dell'immagine
     * $scala viene incrementato fino a che tutte le barre possano
     * essere disegnate nell'immagine.
     */
    $scala = $this->normalizeBarsLength($barArray,$this->height);

    $nBar = count($barArray);

    //larghezza delle barre
    $h = $this->calculateBarsDimension($this->width,$nBar);

    $tempWidth = Picasso::BARS_MARGIN;
    $newX = $h + $tempWidth;

    foreach($barArray as $bar){
      try{
        $this->addFilledRectangle($tempWidth
            ,($this->height - Picasso::IMAGE_MARGIN 
                - $bar->getValue()/$scala)
            ,$newX
            ,($this->height - Picasso::IMAGE_MARGIN)
            ,$bar->getRed(),$bar->getGreen(),$bar->getBlu());

        $text = $bar->getLabel()."(".$bar->getValue().")";
        $fontSize = $this->calculateVBarFontSize($h,$text);

        if($fontSize < 1){
          /**
           * Dimensione dello Spazio che rimane vuoto 
           * tra l'immagine e la barra
           */
          $emptySpace = $this->height - Picasso::IMAGE_MARGIN 
              - $bar->getValue()/$scala;

          /**
           * Ricalcolo la dimensione del font 
           * in base all'altezza della barra
           */
          $fontSize = $this->calculateVBarFontSize(
              $this->height - $emptySpace,$text);
          $this->addVerticalText($fontSize
              ,$this->centerVerticalVBarText
                  ($fontSize,$h,$tempWidth,$text)
              ,($this->height - Picasso::IMAGE_MARGIN 
                  - imagefontwidth($fontSize))
              ,$text 
              ,$bar->getRed()/Picasso::DEFAULT_FONT_COLOR_COEFF
              ,$bar->getGreen()/Picasso::DEFAULT_FONT_COLOR_COEFF
              ,$bar->getBlu()/Picasso::DEFAULT_FONT_COLOR_COEFF);
        }
        else{
          $this->addText($fontSize
              ,$this->centerVBarText($fontSize,$h,$tempWidth,$text)
              ,($this->height - Picasso::IMAGE_MARGIN 
                  - imagefontheight($fontSize))
              ,$text 
              ,$bar->getRed()/Picasso::DEFAULT_FONT_COLOR_COEFF
              ,$bar->getGreen()/Picasso::DEFAULT_FONT_COLOR_COEFF
              ,$bar->getBlu()/Picasso::DEFAULT_FONT_COLOR_COEFF);
        }
        $tempWidth = $tempWidth + Picasso::BARS_MARGIN + $h;
        $newX = $tempWidth + $h; 
      }
      catch (Exception $e){
        die('<br />Eccezzione: '
            . $e->getMessage() . '<br />');
      }
    }
  }

  function addPieChart($barArray){
    $coeff = $this->getPieCoeff($barArray);
    $raggio = (imagesx($this->image) <= imagesy($this->image))
        ? imagesx($this->image) : imagesy($this->image);
    $raggio = $raggio - Picasso::IMAGE_MARGIN*2;

    $x = imagesx($this->image)/2;
    $y = imagesy($this->image)/2;
    $start = 0;
    $end = 0;

    foreach($barArray as $bar){
      $end += $coeff * $bar->getValue(); 
      $this->addFilledPieceOfPie($x,$y,$raggio,$raggio
          , $start, $end, $bar->getRed()
          , $bar->getGreen(),$bar->getBlu());

      $start = $end;
    }
  }

  /** Restituisce l'immagine Padre. */
  public function getImage(){
    return $this->image;
  }

  /**
   * Calcola lo spessore di ogni barra dividendo 
   * l'altezza o la larghezza dell'immagine
   * per il numero di barre considerando uno spazio 
   * di 4px per distanziarle.
   * 
   * Spessore: imgHeight = 4 + nBar(x + 4);
   *  ==> x = (imgHeight - 4 - 4*nBar)/nBar; 
   */ 
  private function calculateBarsDimension($dimensionSide,$barsNumber){
    return ($dimensionSide - Picasso::BARS_MARGIN - 
        (Picasso::BARS_MARGIN*$barsNumber))/$barsNumber;
  }

  /** 
   * Restituisce un Colore da usare per l'immagine 
   * o un oggetto creato nell'immagine 
   */
  private function setColor($red,$green,$blu){
    return imagecolorallocate($this->image,$red,$green,$blu);
  }

  /** Calcola il punto per centrare il testo nell'immagine */
  private function centerHorizontalText($font,$dimension,$position){
    $fHeight = imagefontheight($font);
    return $position - ($dimension/2 + $fHeight/2);
  }

  /** 
   * Calcola il punto per centrare un testo orizzontale 
   * in una Vertical Bar.
   */
  private function centerVBarText($font,$dimension,$position,$txt){
    $fWidth = imagefontwidth($font);
    return $position + ($dimension/2 - ($fWidth * strlen($txt))/2);
  }

  /**
   * Calcola il punto per centrare un testo verticale 
   * in una Vertical Bar 
   */
  private function centerVerticalVBarText
        ($font,$dimension,$position,$txt){
    $fWidth = imagefontheight($font);
    return $position + 
        ($dimension/2 - ($fWidth * strlen($txt[1]))/2);
  }

  /**
   * Calcola il font da utilizzare in base alla dimensione 
   * del lato da considerare nell'immagine
   */
  private function calculateHorizontalFontSize($dimension){
    $font = Picasso::DEFAULT_FONT_SIZE;

    while(imagefontheight($font) > 
          ($dimension - Picasso::BARS_MARGIN) 
          && $font >0){
      $font--;
    }
    return $font;
  }

  /**
   * Calcola la dimensione del font da utilizzare 
   * nelle barre verticali in base alla dimensione 
   * del lato da considerare nell'immagine e alla 
   * lunghezza del testo.
   */ 
  private function calculateVBarFontSize($dimension,$txt){
    $font = Picasso::DEFAULT_FONT_SIZE;

    while((imagefontwidth($font)*strlen($txt) > 
          $dimension - Picasso::BARS_MARGIN) 
          && $font >0){
      $font--;
    }
    return $font;
  }

  /**
   * Trova il coefficiente con cui ridurre in scala 
   * la lunghezza delle barre nei grafici 
   * a barre orizzontali e verticali.
   */
  private function normalizeBarsLength($arr,$dimension){
    $coeff = 1;

    //Rapresenta il valore piu' grande da rappresentare
    $maxLength = 0;
    $coeffIng = 1;

    foreach($arr as $bar){
      $temp = $bar->getValue();
      $maxLength = ($temp > $maxLength) 
          ? $temp : $maxLength; 

      while( ($temp/$coeff) >= 
          ($dimension - Picasso::IMAGE_MARGIN)){
        $coeff++;
      }
    }

    //Se $coeff == 1 allora provo ad ingrandire la scala
    if($coeff == 1){
      $temp = $coeffIng + 1;
      
      while( ($maxLength*$temp) < 
          ($dimension - Picasso::IMAGE_MARGIN)){
        $coeffIng++;
        $temp = $coeffIng + 1;
      }

      $coeff = 1/$coeffIng;
    }

    return $coeff;
  }

  /**
   * restituisce il coefficiente per trasformare il valore
   * di ogni oggetto Bar in una fetta di torta
   */
  function getPieCoeff($arr){
    $tot = 0;

    foreach($arr as $bar){
      $tot += $bar->getValue();
    }

    return 360/$tot;
  }
}

?>

La classe è un po' complessa, sopratutto nelle fasi di calcolo per determinare le dimensioni e le distanze degli oggetti, per il resto il modo in cui vengono create le immagini e come sono posizionate nell'immagine padre risulta essere molto semplice e trasparente.

Come premesso, questo framework è un prototipo funzionante dal quale poter facilmente creare grafici sempre più complessi e raffinati. Direi però che è una buona base da cui iniziare.

Alla prossima,
MA.