##file: lib-doc.php
<?php
class Document{
private $code;
private $date;
private $costumer;
private $total;
private $vat;
private $imp;
private $i;
public $items;
public $template;


public function __construct($code, $date, $costumer){
$this->i = 0;
$this->template = 'document.tpl.php';
$this->code = $code;
$this->date = $date;
$this->costumer = $costumer;
$this->items = array();
}

public function addItem($title, $code, $qnt, $price, $nVat){
$this->i++;
$item = new Item($code, $title, $qnt, $price, $nVat, $this->i, $this);
$this->items[$this->i] = $item;

$this->totaliDocumento();
return $item;
}

public function removeItem($item){
if(isset($this->items[$item->getKey()])){
unset($this->items[$item->getKey()]);
$this->totaliDocumento();
}
}

public function changeQnt($item, $newQnt){
if(isset($this->items[$item->getKey()])){
$item->changeQnt($newQnt);
$this->totaliDocumento();
}
}

public function totaliDocumento(){
$this->total = 0;
$this->vat = 0;
$this->imp = 0;
foreach($this->items AS $item){
$this->total += $item->getImporto('totale');
$this->imp += $item->getImporto('imponibile');
$this->vat += $item->getImporto('iva');
}
}

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

public function output(){
$document = $this;
include($this->template);
}
public function outputItem($item){
include($item->template);
}
}
class Item Document{
private $qnt;
private $prezzo;
private $cIva;
public $titolo;
public $codice;
public $template;
/*
* rayKey e' la chiave dell'array items
* dell'istanza di ogni Item.
* Serve per tenerne la tracciabilita'
* (per rimuovere gli oggetti o modificarli)
*/
private $rayKey;

private $documento;
private $totale;
private $imponibile;
private $iva;

public function __construct($codice, $titolo, $qnt, $prezzo, $cIva, $key, $documento){
$this->template = 'item.tpl.php';
$this->documento = $documento;
$this->rayKey = $key;
$this->codice = $codice;
$this->titolo = $titolo;
$this->qnt = $qnt;
$this->prezzo = $prezzo;
$this->cIva = $cIva;
//calcolo i totali
$this->calcolaTotali();
}
public function getKey(){
return $this->rayKey;
}
/*
*Diciamo che voglio avere la certezza che
*aggiornando la quantita' o il prezzo
*dell'oggetto, i totali sono sempre aggiornati.
*Quindi qnt e prezzo sono privati, per aggiornarli
*bisogna utilizzare la relativa funzione che
*aggiorna anche i totali dell'oggetto.
*/
public function aggiornaQnt($qnt){
$this->qnt = $qnt;
$this->calcolaTotali();
}

public function aggiornaPrezzo($prezzo){
$this->prezzo = $prezzo;
$this->calcolaTotali();
}

private function calcolaTotali(){
$this->imponibile = $this->qnt * $this->prezzo;
$this->iva = ($this->imponibile * $this->cIva) / 100;
$this->totale = $this->imponibile + $this->iva;
$this->documento->totaliDocumento();
}
/*
* Anche i totali non sono modificabili
* direttamente ma dipendono da altre
* proprieta' dell'oggetto.
* L'unico modo per ottenerli al di fuori
* della classe, e' quindi questa funzione
*/
public function getImporto($importo = 'totale'){
switch($importo){
case 'totale':
return $this->totale;
break;
case 'imponibile':
return $this->imponibile;
break;
case 'iva':
return $this->iva;
break;
}
}
/*
* questo metodo serve solo per recuperare dall'esterno
* le variabli protette
*/
public function attr($attr){
return $this->$attr;
}

public function output(){
$item = $this;
include($this->template);
}
}
?>

##file: index.php
<?php
require_once('lib-doc.php');

$fattura = new Document('00001', '11 November 2009', 'Jhon Doe');

$beer = $fattura->addItem('Beer Bottle', 'F6ASJK8', 6, 3.43, 20);
$chips = $fattura->addItem('Cheesy Chips', 'KBLN32', 2, 1.12, 20);
$popcorn = $fattura->addItem('Pop Corn', 'BCHREUD6', 2, 0.69, 20);
$fattura->removeItem($beer);
$beer_cans = $fattura->addItem('Beer Cans, x6', 'YHEF6DTT', 1, 5.99, 20);
//$fattura->changeQnt($chips, 4);

$fattura->output();
?>

##file: document.tpl.php
<div class="document document-<?php echo $document->attr('code'); ?>">
<h1>Document <?php echo $document->attr('code'); ?> of <?php echo $document->attr('date'); ?></h1>
<p>Costumer: <b><?php echo $document->attr('costumer'); ?></b></p>
<h2>Items Details</h2>
<p class="item-list">
<?php
foreach($document->items AS $item){
$document->outputItem($item);
}
?>
</p>
<h2>Document Totals:</h2>
<ul class="totals">
<li><b>Imponibile:</b> <?php echo $document->attr('imp'); ?>&euro;</li>
<li><b>VAT:</b> <?php echo $document->attr('vat'); ?>&euro;</li>
<li><b>Total:</b> <?php echo $document->attr('total'); ?>&euro;</li>
</ul>
</div>

##file: item.tpl.php
<?php
//questo DEVE dare ERRORE!
$item->aggiornaPrezzo(10.54);
?>
<div class="item item-<?php echo $item->codice; ?>">
<h3><?php echo $item->titolo; ?></h3>
<ul>
<li><b>Quantity:</b> <?php echo $item->attr('qnt'); ?></li>
<li><b>Cost per Unit:</b> <?php echo $item->attr('prezzo'); ?></li>
<li><b>VAT Appliable:</b> <?php echo $item->attr('cIva'); ?>%</li>
<li><b>Imponibile:</b> <?php echo $item->getImporto('imponibile'); ?>&euro;</li>
<li><b>VAT:</b> <?php echo $item->getImporto('iva'); ?>&euro;</li>
<li><b>Total:</b> <?php echo $item->getImporto('totale'); ?>&euro;</li>
</ul>
</div>