Creare dei report in PDF con PHP

La creazione di report è un’attività molto comune per tutti i programmatori, non solo per coloro che si occupano a tempo pieno di applicazioni gestionali e simili. La gestione di siti web o e-commerce, cataloghi on-line, community e qualsiasi attività che coinvolga dei dati prima o poi avrà bisogno di analizzarli, ecco dunque che la necessità di creare dei report si manifesta.

In questo articolo vedremo come creare dei semplici report utilizzando PHP e la libreria FPDF, che ha diversi pregi: è molto leggera, è completamente free anche per usi commerciali e modifiche, è ben documentata.

Un semplice report tabulare

Per familiarizzare con la libreria consigliamo di installare lo stack XAMPP adatto al proprio sistema (Win o Linux), perché di base ha già installato FPDF come modulo PEAR.

In questo primo script vediamo come sia possibile creare un report in forma tabulare:

<?php
include ('fpdf/fpdf.php');

define('EURO', chr(128));

// dati di test

$data = array(
  array(
    'product_code' => 'S284056',
    'product_name' => 'Ferrary F1234',
    'customer_code' => 'CUST1234',
    'customer_name' => 'Gino Ginetti',
    'amount' => 250000),
  array('product_code' => 'S284056',
    'product_name' => 'Ferrary F1234',
    'customer_code' => 'CUST1100',
    'customer_name' => 'Gongolo Nannolo',
    'amount' => 270000 ),
  array('product_code' => 'S292383',
    'product_name' => 'Lardonghini Mucila',
    'customer_code' => 'CUST0120',
    'customer_name' => 'Pasquale Pasqualini',
    'amount' => 352000 ),
  array('product_code' => 'S292383',
    'product_name' => 'Lardonghini Mucila',
    'customer_code' => 'CUST1234',
    'customer_name' => 'Gino Ginetti',
    'amount' => 352000 ),
  array('product_code' => 'S898964',
    'product_name' => 'Porsck Paprika',
    'customer_code' => 'CUST0120',
    'customer_name' => 'Pasquale Pasqualini',
    'amount' => 352000 ),
  array('product_code' => 'S898964',
    'product_name' => 'Porsck Paprika',
    'customer_code' => 'CUST0054',
    'customer_name' => 'Pino Pinerati',
    'amount' => 175000 )
);

// crea PDF

$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial', 'B', 16);
$pdf->Cell(40, 10, 'Report vendite');
$pdf->Ln();

$pdf->Ln(5);

$pdf->SetFont('Helvetica', 'B', 10);
$pdf->Cell(30, 7, 'Cod. prodotto', 1);
$pdf->Cell(40, 7, 'Nome prodotto', 1);
$pdf->Cell(30, 7, 'Cod. cliente', 1);
$pdf->Cell(40, 7, 'Nome cliente', 1);
$pdf->Cell(40, 7, 'Prezzo pagato', 1);
$pdf->Ln();

$pdf->SetFont('Helvetica', '', 10);

foreach($data as $row) {
  $pdf->Cell(30, 7, $row['product_code'], 1);
  $pdf->Cell(40, 7, $row['product_name'], 1);
  $pdf->Cell(30, 7, $row['customer_code'], 1);
  $pdf->Cell(40, 7, $row['customer_name'], 1);
  // formattazione italiana
  $pdf->Cell(40, 7, EURO . ' ' . number_format($row['amount'], 2, ',', '.'), 1, 0, 'R');
  $pdf->Ln();
}

$pdf->Output();

 

In questo breve script ci sono molti elementi da notare:

  • l’istruzione include (‘fpdf/fpdf.php’); funziona con XAMPP, in un’applicazione reale potrebbe essere necessario utilizzare un path differente. Verificare la documentazione o l’amministratore di sistema per chiarire eventuali dubbi;
  • L’istruzione define(‘EURO’, chr(128)); definisce il carattere “euro”, in modo da non doversi ricordare il codice carattere (128);
  • l’array $data contiene i dati prelevati dal (ipotetico) database;
  • per creare il PDF viene istanziato un oggetto di tipo FPDF;
  • per creare i vari elementi del report abbiamo fatto uso praticamente di soli tre metodi: SetFont(), Cell() e Ln();
  • l’istruzione $pdf->Output(), infine, invia al browser i byte del PDF prodotto.

Il risultato è un semplice file PDF, aperto direttamente nella finestra del browser:

 

Da notare come la colonna degli importi sia stata allineata a destra grazie al parametro ‘R’ nel metodo Cell(). Sul sito ufficiale c’è la documentazione completa della libreria (anche in italiano!) alla quale vi rimandiamo per scoprire i dettagli di utilizzo dei vari metodi.

Raggruppamenti

Una delle funzionalità più utili dei report sono sicuramente i raggruppamenti, perché consentono di estrarre degli indicatori sintetici da una lunga fila di dati. Affinché si possano raggruppare i dati, è necessario che questi siano ordinati per la caratteristica che si vuole raggruppare. Nell’esempio sopra possiamo notare che i rapporti di vendita sono già ordinati per prodotto: non ci resta che creare un report che sfrutti questo raggruppamento:

<?php
include ('fpdf/fpdf.php');

define('EURO', chr(128));

function report_table_header($pdf) {
  $pdf->SetFont('Helvetica', 'B', 10);
  $pdf->Cell(30, 7, 'Cod. prodotto', 1);
  $pdf->Cell(40, 7, 'Nome prodotto', 1);
  $pdf->Cell(30, 7, 'Cod. cliente', 1);
  $pdf->Cell(40, 7, 'Nome cliente', 1);
  $pdf->Cell(40, 7, 'Prezzo pagato', 1);
  $pdf->Ln();
}

function report_product_total($pdf, $productTotal) {
  if (isset($productTotal)) {
    $pdf->SetFont('Helvetica', 'B', 10);
    $pdf->Cell(100, 7, '', 3);
    $pdf->Cell(40, 7, 'Totale', 0, 0, 'R');
    $pdf->Cell(40, 7, EURO . ' ' . number_format($productTotal, 2, ',', '.'), 1, 0, 'R');
    $pdf->Ln();
  }
}

// dati di test

NB: COPIARE LA SEZIONE DI DATI DALL'ESEMPIO N. 1

// crea PDF

$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial', 'B', 16);
$pdf->Cell(40, 10, 'Report vendite - per modello');
$pdf->Ln();

$pdf->Ln(5);

$pdf->SetFont('Helvetica', '', 10);

$lastProductCode = null;
$breakProduct = true;
$productTotal = null;

foreach($data as $row) {
  $breakProduct = $row['product_code'] != $lastProductCode;

  if ($breakProduct) {
    // mostra totali del prodotto precedente (se c'è)
    report_product_total($pdf, $productTotal);

    // mostra titolo prodotto
    $pdf->SetFont('Helvetica', 'B', 10);
    $pdf->Cell(40, 10, $row['product_code'] . ' - ' . $row['product_name']);
    $pdf->Ln();
    // mostra header tabella
    report_table_header($pdf);
  }

  $pdf->SetFont('Helvetica', '', 10);
  $pdf->Cell(30, 7, $row['product_code'], 1);
  $pdf->Cell(40, 7, $row['product_name'], 1);
  $pdf->Cell(30, 7, $row['customer_code'], 1);
  $pdf->Cell(40, 7, $row['customer_name'], 1);
  // formattazione italiana
  $pdf->Cell(40, 7, EURO . ' ' . number_format($row['amount'], 2, ',', '.'), 1, 0, 'R');
  $pdf->Ln();

  $lastProductCode = $row['product_code'];
  $productTotal += $row['amount'];
}

// totale dell'ultimo prodotto
report_product_total($pdf, $productTotal);

$pdf->Output();

 

NB: Per limitare la lunghezza del sorgente abbiamo omesso la dichiarazione dell’array $data, che può essere copiata dall’esempio n. 1. Da notare:

  • abbiamo spostato il codice che crea l’intestazione della tabella nella funzione report_table_header(), poiché questa intestazione andrà ripetuta per ogni prodotto;
  • la funzione report_product_total() mostra l’ammontare totale; da notare in questo caso l’uso di una cella che occupa tre spazi (l’quivalente del colspan in HTML);
  • le variabili $lastProductCode , $breakProduct e $productTotal sono utilizzate per capire se mostrare una nuova tabella e il riassunto della precedente, oppure no.

L’output di questo report è il seguente:

 

Links