Copy of materials from Matt Zandstra book "PHP 5 Objects, Patterns, and Practice"


File:listing03.01.php


<?php
class ShopProduct {
    
// class body
}
$product1 = new ShopProduct();
$product2 = new ShopProduct();

$product1->title="My Antonia";
$product2->title="Catch 22";

print  
$product1->title."\n"; // My Antonia
print "{$product1->title}\n"; // Catch 22
?>

File:listing03.02.php


<?php
    
class ShopProduct {
        public
$title               = "default product";
        public
$producerMainName    = "main name";
        public
$producerFirstName   = "first name";
        public
$price               = 0;
    }

$product1 = new ShopProduct();

print
"{$product1->title}\n";             // default product
print "{$product1->producerMainName}\n";  // main name

?>

File:listing03.03.php


<?php
    
class ShopProduct {
        public
$title               = "default product";
        public
$producerMainName    = "main name";
        public
$producerFirstName   = "first name";
        public
$price               = 0;
    }

$product1 = new ShopProduct();
$product1->title = "My Antonia";
$product1->producerMainName  = "Cather";
$product1->producerFirstName = "Willa";
$product1->price = 5.99;

print
"author: {$product1->producerFirstName} "
             
."{$product1->producerMainName}\n";
// author: Willa Cather
?>

File:listing03.04.php


<?php
    
class ShopProduct {
        public
$title               = "default product";
        public
$producerMainName    = "main name";
        public
$producerFirstName   = "first name";
        public
$price               = 0;
        
        function
getProducer() {
            return
"{$this->producerFirstName}".
                   
" {$this->producerMainName}";
        }
    }

$product1 = new ShopProduct();
$product1->title = "My Antonia";
$product1->producerMainName  = "Cather";
$product1->producerFirstName = "Willa";
$product1->price = 5.99;

print
"author: ".$product1->getProducer()."\n";
// author: Willa Cather
?>

File:listing03.05.php


<?php
    
class ShopProduct {
        public
$title;
        public
$producerMainName;
        public
$producerFirstName;
        public
$price;
        
        function
__construct( $title, $firstName, $mainName, $price ) {
            
$this->title             = $title;
            
$this->producerFirstName = $firstName;
            
$this->producerMainName  = $mainName;
            
$this->price             = $price;
        }

        function
getProducer() {
            return
"{$this->producerFirstName}".
                   
" {$this->producerMainName}";
        }
    }

$product1 = new ShopProduct( "My Antonia", "Willa", "Cather", 5.99 );
print
"author: ".$product1->getProducer()."\n";
// author: Willa Cather
?>

File:listing03.06.php


<?php
require_once( "listing03.05.php" );

class
ShopProductWriter {
    public function
write( $shopProduct ) {
        
$str  = "{$shopProduct->title}: ";   
        
$str .= $shopProduct->getProducer();
        
$str .= " ({$shopProduct->price})\n";
        print
$str;
    }
}
$product1 = new ShopProduct( "My Antonia", "Willa", "Cather", 5.99 );
$writer = new ShopProductWriter();
$writer->write( $product1 );

?>

File:listing03.07.php


<?php
require_once( "listing03.10.php" );

class
ShopProductWriter {
    public function
write( ShopProduct $shopProduct ) {
        
$str  = "{$shopProduct->title}: ";   
        
$str .= $shopProduct->getProducer();
        
$str .= " ({$shopProduct->price})\n";
        print
$str;
    }
}
class
Wrong { }
$product1 = new ShopProduct( "My Antonia", "Willa", "Cather", 5.99 );
$writer = new ShopProductWriter();
$wrong  = new Wrong();
// $writer->write( $product1 );
$writer->write( $wrong );

?>

File:listing03.08.php


<?php
class ShopProduct {
    public
$title;
    public
$producerMainName;
    public
$producerFirstName;
    public
$price;
    
    function
__construct( $title, $firstName, $mainName, $price ) {
        
$this->title             = $title;
        
$this->producerFirstName = $firstName;
        
$this->producerMainName  = $mainName;
        
$this->price             = $price;
    }

    function
getProducer() {
        return
"{$this->producerFirstName}".
               
" {$this->producerMainName}";
    }
}

$product1 = new ShopProduct(    "My Antonia", "Willa", "Cather", 5.99 );
$product2 = new ShopProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99 );
print
"author: ".$product1->getProducer()."\n";
print
"artist: ".$product2->getProducer()."\n";
// author: Willa Cather
// artist: The Alabama 3
?>

File:listing03.09.php


<?php
class ShopProduct {
    public
$numPages;
    public
$playLength;
    public
$title;
    public
$producerMainName;
    public
$producerFirstName;
    public
$price;
    
    function
__construct(   $title, $firstName,
                            
$mainName, $price,
                            
$numPages=0, $playLength=0 ) {
        
$this->title             = $title;
        
$this->producerFirstName = $firstName;
        
$this->producerMainName  = $mainName;
        
$this->price             = $price;
        
$this->numPages          = $numPages;
        
$this->playLength        = $playLength;
    }
    
    function
getNumberOfPages() {
        return
$this->numPages;
    }

    function
getPlayLength() {
        return
$this->playLength;
    }

    function
getProducer() {
        return
"{$this->producerFirstName}".
               
" {$this->producerMainName}";
    }
}

$product1 = new ShopProduct(    "My Antonia", "Willa", "Cather", 5.99, 300 );
$product2 = new ShopProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, null, 60.33 );

print
"author:          ".$product1->getProducer()."\n";
print
"number of pages: ".$product1->getNumberOfPages()."\n";
print
"artist:          ".$product2->getProducer()."\n";
print
"play length:     ".$product2->getPlayLength()."\n";

// author:          Willa Cather
// number of pages: 300
// artist:          The Alabama 3
// play length:     60.33
?>

File:listing03.10.php


<?php
class CdProduct {
    public
$playLength;
    public
$title;
    public
$producerMainName;
    public
$producerFirstName;
    public
$price;

    function
__construct(   $title, $firstName,
                            
$mainName, $price,
                            
$playLength ) {
        
$this->title             = $title;
        
$this->producerFirstName = $firstName;
        
$this->producerMainName  = $mainName;
        
$this->price             = $price;
        
$this->playLength        = $playLength;

    }

    function
getPlayLength() {
        return
$this->playLength;
    }

    function
getSummaryLine() {
        
$base  = "$this->title ( $this->producerMainName, ";
        
$base .= "$this->producerFirstName )";
        
$base .= ": playing time - $this->playLength";
        return
$base;
    }

    function
getProducer() {
        return
"{$this->producerFirstName}".
               
" {$this->producerMainName}";
    }
}

class
BookProduct {
    public
$numPages;
    public
$title;
    public
$producerMainName;
    public
$producerFirstName;
    public
$price;

    function
__construct(   $title, $firstName,
                            
$mainName, $price,
                            
$numPages ) {
        
$this->title             = $title;
        
$this->producerFirstName = $firstName;
        
$this->producerMainName  = $mainName;
        
$this->price             = $price;
        
$this->numPages          = $numPages;
    }

    function
getNumberOfPages() {
        return
$this->numPages;
    }

    function
getSummaryLine() {
        
$base  = "$this->title ( $this->producerMainName, ";
        
$base .= "$this->producerFirstName )";
        
$base .= ": page count - $this->numPages";
        return
$base;
    }

    function
getProducer() {
        return
"{$this->producerFirstName}".
               
" {$this->producerMainName}";
    }

}

$product1 = new BookProduct(    "My Antonia", "Willa", "Cather", 5.99, 300 );
$product2 =   new CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );

print
"author:          ".$product1->getProducer()."\n";
print
"number of pages: ".$product1->getNumberOfPages()."\n";
print
"summary:         ".$product1->getSummaryLine()."\n";
print
"artist:          ".$product2->getProducer()."\n";
print
"play length:     ".$product2->getPlayLength()."\n";
print
"summary:         ".$product2->getSummaryLine()."\n";
?>

File:listing03.11.php


<?php
require_once( "listing03.10.php" );

class
ShopProductWriter {
    public function
write( $shopProduct ) {
        if ( ! (
$shopProduct instanceof CdWriter )  &&
             ! (
$shopProduct instanceof BookProduct ) ) {
            die(
"wrong type supplied" );
        }

        
$str  = "{$shopProduct->title}: ";   
        
$str .= $shopProduct->getProducer();
        
$str .= " ({$shopProduct->price})\n";
        print
$str;
    }
}
// class Wrong { }
$product1 = new CdProduct( "My Antonia", "Willa", "Cather", 5.99, 300 );
$writer = new ShopProductWriter();
$writer->write( $product1 );
// $wrong  = new Wrong();
// $writer->write( $wrong );

?>

File:listing03.12.php


<?php
class ShopProduct {
    public
$numPages;
    public
$playLength;
    public
$title;
    public
$producerMainName;
    public
$producerFirstName;
    public
$price;
    
    function
__construct(   $title, $firstName,
                            
$mainName, $price,
                            
$numPages=0, $playLength=0 ) {
        
$this->title             = $title;
        
$this->producerFirstName = $firstName;
        
$this->producerMainName  = $mainName;
        
$this->price             = $price;
        
$this->numPages          = $numPages;
        
$this->playLength        = $playLength;
    }

    function
getProducer() {
        return
"{$this->producerFirstName}".
               
" {$this->producerMainName}";
    }

    function
getSummaryLine() {
        
$base  = "$this->title ( $this->producerMainName, ";
        
$base .= "$this->producerFirstName )";
        return
$base;
    }

    function
getProductXml() {
        
// empty implementation
    
}
}

class
CdProduct extends ShopProduct {
    function
getPlayLength() {
        return
$this->playLength;
    }
    
    function
getSummaryLine() {
        
$base  = "$this->title ( $this->producerMainName, ";
        
$base .= "$this->producerFirstName )";
        
$base .= ": playing time - $this->playLength";
        return
$base;
    }
}

class
BookProduct extends ShopProduct {
    function
getNumberOfPages() {
        return
$this->numPages;
    }

    function
getSummaryLine() {
        
$base  = "$this->title ( $this->producerMainName, ";
        
$base .= "$this->producerFirstName )";
        
$base .= ": page count - $this->numPages";
        return
$base;
    }
}

$product1 = new BookProduct(    "My Antonia", "Willa", "Cather", 5.99, 300 );
$product2 =   new CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, null, 60.33 );

print
"author:          ".$product1->getProducer()."\n";
print
"number of pages: ".$product1->getNumberOfPages()."\n";
print
"artist:          ".$product2->getProducer()."\n";
print
"play length:     ".$product2->getPlayLength()."\n";

// author:          Willa Cather
// number of pages: 300
// artist:          The Alabama 3
// play length:     60.33
?>

File:listing03.13.php


<?php
class ShopProduct {
    public
$title;
    public
$producerMainName;
    private
$producerFirstName;
    public
$price;
    
    function
__construct(   $title, $firstName,
                            
$mainName, $price,
                            
$numPages=0, $playLength=0 ) {
        
$this->title             = $title;
        
$this->producerFirstName = $firstName;
        
$this->producerMainName  = $mainName;
        
$this->price             = $price;
    }

    function
getProducer() {
        return
"{$this->producerFirstName}".
               
" {$this->producerMainName}";
    }

    function
getProductXml() {
        
// empty implementation
    
}
}

class
CdProduct extends ShopProduct {
    public
$playLength = 0;

    function
__construct(   $title, $firstName,
                            
$mainName, $price, $playLength ) {
        
parent::__construct(    $title, $firstName,
                                
$mainName, $price );
        
$this->playLength = $playLength;
    }

    function
getPlayLength() {
        return
$this->playLength;
    }
    
    function
getProductXml() {
        return
'<product type="cd" />';
    }
}

class
BookProduct extends ShopProduct {
    public
$numPages = 0;

    function
__construct(   $title, $firstName,
                            
$mainName, $price, $numPages ) {
        
parent::__construct(    $title, $firstName,
                                
$mainName, $price );
        
$this->numPages = $numPages;
    }

    function
getNumberOfPages() {
        return
$this->numPages;
    }
    
    function
getProductXml() {
        return
'<product type="book" />';
    }
}

$product1 = new BookProduct(    "My Antonia", "Willa", "Cather", 5.99, 300 );
$product2 =   new CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );

print
"author:          ".$product1->getProducer()."\n";
print
"number of pages: ".$product1->getNumberOfPages()."\n";
print
"artist:          ".$product2->getProducer()."\n";
print
"play length:     ".$product2->getPlayLength()."\n";

// author:          Willa Cather
// number of pages: 300
// artist:          The Alabama 3
// play length:     60.33
?>

File:listing03.14.php


<?php
class ShopProduct {
    public
$title;
    public
$producerMainName;
    public
$producerFirstName;
    private
$price;
    public
$discount = 0;
    
    function
__construct(   $title, $firstName,
                            
$mainName, $price,
                            
$numPages=0, $playLength=0 ) {
        
$this->title             = $title;
        
$this->producerFirstName = $firstName;
        
$this->producerMainName  = $mainName;
        
$this->price             = $price;
    }

    function
setDiscount( $num ) {
        
$this->discount=$num;
    }

    function
getPrice() {
        return (
$this->price - $this->discount);
    }

    function
getProducer() {
        return
"{$this->producerFirstName}".
               
" {$this->producerMainName}";
    }

    function
getProductXml() {
        
// empty implementation
    
}
}

class
CdProduct extends ShopProduct {
    public
$playLength = 0;

    function
__construct(   $title, $firstName,
                            
$mainName, $price, $playLength ) {
        
parent::__construct(    $title, $firstName,
                                
$mainName, $price );
        
$this->playLength = $playLength;
    }

    function
getPlayLength() {
        return
$this->playLength;
    }
    
    function
getProductXml() {
        return
'<product type="cd" />';
    }
}

class
BookProduct extends ShopProduct {
    public
$numPages = 0;

    function
__construct(   $title, $firstName,
                            
$mainName, $price, $numPages ) {
        
parent::__construct(    $title, $firstName,
                                
$mainName, $price );
        
$this->numPages = $numPages;
    }

    function
getProducer() {
        return
strToUpper( parent::getProducer() );
    }

    function
getNumberOfPages() {
        return
$this->numPages;
    }
    
    function
getProductXml() {
        return
'<product type="book" />';
    }
}

$product1 = new BookProduct(    "My Antonia", "Willa", "Cather", 5.99, 300 );
$product2 =   new CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
$product1->setDiscount( 1 );
print
$product1->getPrice();
print
"\n";
$product1->price;
print
"The price is $product1->price\n";
print
"\n";
print
"author:          ".$product1->getProducer()."\n";
print
"number of pages: ".$product1->getNumberOfPages()."\n";
print
"artist:          ".$product2->getProducer()."\n";
print
"play length:     ".$product2->getPlayLength()."\n";

/*
// author:          Willa Cather
// number of pages: 300
// artist:          The Alabama 3
// play length:     60.33
*/
?>

File:listing03.15.php


<?php
class ShopProduct {
    public
$title;
    public
$producerMainName;
    public
$producerFirstName;
    protected
$price;
    public
$discount = 0;
    
    function
__construct(   $title, $firstName,
                            
$mainName, $price,
                            
$numPages=0, $playLength=0 ) {
        
$this->title             = $title;
        
$this->producerFirstName = $firstName;
        
$this->producerMainName  = $mainName;
        
$this->price             = $price;
    }

    function
setDiscount( $num ) {
        
$this->discount=$num;
    }

    function
getPrice() {
        return (
$this->price - $this->discount);
    }

    function
getProducer() {
        return
"{$this->producerFirstName}".
               
" {$this->producerMainName}";
    }

    function
getProductXml() {
        
// empty implementation
    
}
}

class
CdProduct extends ShopProduct {
    public
$playLength = 0;

    function
__construct(   $title, $firstName,
                            
$mainName, $price, $playLength ) {
        
parent::__construct(    $title, $firstName,
                                
$mainName, $price );
        
$this->playLength = $playLength;
    }

    function
getPlayLength() {
        return
$this->playLength;
    }
    
    function
getProductXml() {
        return
'<product type="cd" />';
    }
}

class
BookProduct extends ShopProduct {
    public
$numPages = 0;

    function
__construct(   $title, $firstName,
                            
$mainName, $price, $numPages ) {
        
parent::__construct(    $title, $firstName,
                                
$mainName, $price );
        
$this->numPages = $numPages;
    }

    function
getNumberOfPages() {
        return
$this->numPages;
    }
    
    function
getProductXml() {
        return
'<product type="book" />';
    }

    function
getPrice() {
        return
$this->price;
    }
}

/*
$product1 = new BookProduct(    "My Antonia", "Willa", "Cather", 5.99, 300 );
$product2 =   new CdProduct(    "Exile on Coldharbour Lane",
                                "The", "Alabama 3", 10.99, 60.33 );
$product1->setDiscount( 1 );
print $product1->getPrice();
print "\n";
$product2->setDiscount( 1 );
print $product2->getPrice();
print "\n";
*/
/*
print "author:          ".$product1->getProducer()."\n";
print "number of pages: ".$product1->getNumberOfPages()."\n";
print "artist:          ".$product2->getProducer()."\n";
print "play length:     ".$product2->getPlayLength()."\n";

// author:          Willa Cather
// number of pages: 300
// artist:          The Alabama 3
// play length:     60.33
*/
?>

File:listing03.16.php


<?php
require_once( "listing03.15.php" );

class
ShopProductWriter {
    private
$products = array();

    public function
addProduct( ShopProduct $shopProduct ) {
        
$this->products[]=$shopProduct;
    }

    public function
write() {
        
$str = "";
        foreach (
$this->products as $shopProduct ) {
            
$str .= "{$shopProduct->title}: ";   
            
$str .= $shopProduct->getProducer();
            
$str .= " ({$shopProduct->getPrice()})\n";
        }
        print
$str;
    }
}
$product1 = new BookProduct(    "My Antonia", "Willa", "Cather", 5.99, 300 );
$product2 =   new CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
$writer = new ShopProductWriter();
$writer->addProduct( $product1 );
$writer->addProduct( $product2 );
$writer->write();

?>

File:listing03.17.php


<?php
class ShopProduct {
    private
$title;
    private
$producerMainName;
    private
$producerFirstName;
    protected
$price;
    private
$discount = 0;
    
    public function
__construct(   $title, $firstName,
                            
$mainName, $price ) {
        
$this->title             = $title;
        
$this->producerFirstName = $firstName;
        
$this->producerMainName  = $mainName;
        
$this->price             = $price;
    }

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

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

    public function
setDiscount( $num ) {
        
$this->discount=$num;
    }

    public function
getDiscount() {
        return
$this->discount;
    }
    
    public function
getTitle() {
        return
$this->title;
    }

    public function
getPrice() {
        return (
$this->price - $this->discount);
    }

    public function
getProducer() {
        return
"{$this->producerFirstName}".
               
" {$this->producerMainName}";
    }

    function
getSummaryLine() {
        
$base  = "$this->title ( $this->producerMainName, ";
        
$base .= "$this->producerFirstName )";
        return
$base;
    }
}

class
CdProduct extends ShopProduct {
    private
$playLength = 0;

    public function
__construct(   $title, $firstName,
                            
$mainName, $price, $playLength ) {
        
parent::__construct(    $title, $firstName,
                                
$mainName, $price );
        
$this->playLength = $playLength;
    }

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

    function
getSummaryLine() {
        
$base = parent::getSummaryLine();
        
$base .= ": playing time - $this->playLength";
        return
$base;
    }

}

class
BookProduct extends ShopProduct {
    private
$numPages = 0;

    public function
__construct(   $title, $firstName,
                            
$mainName, $price, $numPages ) {
        
parent::__construct(    $title, $firstName,
                                
$mainName, $price );
        
$this->numPages = $numPages;
    }

    public function
getNumberOfPages() {
        return
$this->numPages;
    }
   
    function
getSummaryLine() {
        
$base = parent::getSummaryLine();
        
$base .= ": page count - $this->numPages";
        return
$base;
    }

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

$product1 = new BookProduct(    "My Antonia", "Willa", "Cather", 5.99, 300 );
$product2 =   new CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
$product1->setDiscount( 1 );
print
$product1->getPrice();
print
"\n";
$product2->setDiscount( 1 );
print
$product2->getPrice();
print
"\n";
print
"title:           ".$product1->getTitle()."\n";
print
"producer first:  ".$product1->getProducerFirstName()."\n";
print
"producer main:   ".$product1->getProducerMainName()."\n";
print
"author:          ".$product1->getProducer()."\n";
print
"number of pages: ".$product1->getNumberOfPages()."\n";
print
"summary:         ".$product1->getSummaryLine()."\n";

print
"title:           ".$product2->getTitle()."\n";
print
"producer first:  ".$product2->getProducerFirstName()."\n";
print
"producer main:   ".$product2->getProducerMainName()."\n";
print
"artist:          ".$product2->getProducer()."\n";
print
"play length:     ".$product2->getPlayLength()."\n";
print
"summary:         ".$product2->getSummaryLine()."\n";

/*
// author:          Willa Cather
// number of pages: 300
// artist:          The Alabama 3
// play length:     60.33
*/
?>

File:settings.xml


<settings>
    <resolvedomains>true</resolvedomains>
</settings>

File:listing04.01.php


<?php
require_once( "../03/listing03.05.php" );

abstract class
ShopProductWriter {
    abstract static function
write( ShopProduct $shopProduct );
}

class
TextProductWriter extends ShopProductWriter {
    static function
write( ShopProduct $shopProduct ) {
        
$str  = "{$shopProduct->title}: ";   
        
$str .= $shopProduct->getProducer();
        
$str .= " ({$shopProduct->price})\n";
        print
$str;
    }
}

$product1 = new ShopProduct( "My Antonia", "Willa", "Cather", 5.99 );
//$writer = new ShopProductWriter();
TextProductWriter::write( $product1 );

?>

File:listing04.02.php


<?php

class StaticExample {
    static public
$aNum = 0;
    static public function
sayHello() {
        
self::$aNum++;
        print
"hello (".self::$aNum.")\n";
    }
}

StaticExample::sayHello();
StaticExample::sayHello();
StaticExample::sayHello();

?>

File:listing04.03.php


<?php
class ShopProduct {
    private
$title;
    private
$producerMainName;
    private
$producerFirstName;
    protected
$price;
    private
$discount = 0;
    private
$id = 0;
    
    public function
__construct(   $title, $firstName,
                            
$mainName, $price ) {
        
$this->title             = $title;
        
$this->producerFirstName = $firstName;
        
$this->producerMainName  = $mainName;
        
$this->price             = $price;
    }

    public function
setID( $id ) {
        
$this->id = $id;
    }

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

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

    public function
setDiscount( $num ) {
        
$this->discount=$num;
    }

    public function
getDiscount() {
        return
$this->discount;
    }
    
    public function
getTitle() {
        return
$this->title;
    }

    public function
getPrice() {
        return (
$this->price - $this->discount);
    }

    public function
getProducer() {
        return
"{$this->producerFirstName}".
               
" {$this->producerMainName}";
    }

    function
getSummaryLine() {
        
$base  = "$this->title ( $this->producerMainName, ";
        
$base .= "$this->producerFirstName )";
        return
$base;
    }

    public static function
getInstance( $id, DB_common $db ) {
        
$query = "select * from products where id='$id'";
        
$query_result = $db->query( $query );

        if (
DB::isError( $query_result ) ) {    
            die(
$query_result->getMessage());
        }

        
$row = $query_result->fetchRow( DB_FETCHMODE_ASSOC );
        if ( empty(
$row ) ) { return null; }

        if (
$row['type'] == "book" ) {
            
$product = new BookProduct(
                                    
$row['title'],
                                    
$row['firstname'], $row['mainname'],
                                    
$row['price'], $row['numpages'] );
        } else if (
$row['type'] == "cd" ) {
            
$product = new CdProduct(
                                    
$row['title'],
                                    
$row['firstname'], $row['mainname'],
                                    
$row['price'], $row['playlength'] );
        } else {
            
$product = new ShopProduct(     
                                    
$row['title'],
                                    
$row['firstname'], $row['mainname'],
                                    
$row['price'] );
        }
        
$product->setId(            $row['id'] );
        
$product->setDiscount(      $row['discount'] );
        return
$product;
    }
}

class
CdProduct extends ShopProduct {
    private
$playLength = 0;

    public function
__construct(   $title, $firstName,
                            
$mainName, $price, $playLength ) {
        
parent::__construct(    $title, $firstName,
                                
$mainName, $price );
        
$this->playLength = $playLength;
    }

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

    function
getSummaryLine() {
        
$base = parent::getSummaryLine();
        
$base .= ": playing time - $this->playLength";
        return
$base;
    }

}

class
BookProduct extends ShopProduct {
    private
$numPages = 0;

    public function
__construct(   $title, $firstName,
                            
$mainName, $price, $numPages ) {
        
parent::__construct(    $title, $firstName,
                                
$mainName, $price );
        
$this->numPages = $numPages;
    }

    public function
getNumberOfPages() {
        return
$this->numPages;
    }
   
    function
getSummaryLine() {
        
$base = parent::getSummaryLine();
        
$base .= ": page count - $this->numPages";
        return
$base;
    }

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

/*
require_once("DB.php");
$dsn = "sqlite://./products.db";    
$db = DB::connect($dsn);
if ( DB::isError( $db ) ) {    
    die ( $db->getMessage() );
}
$obj = ShopProduct::getInstance( 53, $db );
print_r( $obj );
*/
?>

File:listing04.04.php


<?php
class ShopProduct {
    const
AVAILABLE      = 0;
    const
OUT_OF_STOCK   = 1;
    public
$status;
}
print
ShopProduct::AVAILABLE;
?>

File:listing04.05.php


<?php
require_once( "listing04.03.php" );

abstract class
ShopProductWriter {
    protected
$products = array();

    public function
addProduct( ShopProduct $shopProduct ) {
        
$this->products[]=$shopProduct;
    }

    abstract public function
write( );
}

class
XmlProductWriter extends ShopProductWriter{
    public function
write() {
        
$str = "<products>\n";
         foreach (
$this->products as $shopProduct ) {
            
$str .= "\t<product title=\"{$shopProduct->getTitle()}\">\n";
            
$str .= "\t\t<summary>\n";
            
$str .= "\t\t{$shopProduct->getSummaryLine()}\n";
            
$str .= "\t\t</summary>\n";
            
$str .= "\t</product>\n";
        }
        
$str .= "</products>\n";   
        print
$str;
    }
}

class
TextProductWriter extends ShopProductWriter{
    public function
write() {
        
$str = "PRODUCTS:\n";
        foreach (
$this->products as $shopProduct ) {
            
$str .= $shopProduct->getSummaryLine()."\n";
        }
        print
$str;
    }
}

$product1 = new BookProduct(    "My Antonia", "Willa", "Cather", 5.99, 300 );
$product2 =   new CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );

$textwriter = new TextProductWriter();
$textwriter->addProduct( $product1 );
$textwriter->addProduct( $product2 );
$textwriter->write();

$xmlwriter = new XmlProductWriter();
$xmlwriter->addProduct( $product1 );
$xmlwriter->addProduct( $product2 );
$xmlwriter->write();
?>

File:listing04.06.php


<?php
require_once( "listing04.03.php" );

abstract class
ShopProductWriter {
    protected
$products = array();

    public function
addProduct( ShopProduct $shopProduct ) {
        
$this->products[]=$shopProduct;
    }

    abstract public function
write( );
    abstract static function
pibble();
}

class
ErroredWriter extends ShopProductWriter{
    protected function
write() {}
    public static function
pibble() {}
}

$writer = new ErroredWriter();
?>

File:listing04.07.php


<?php

class AbstractClass {
    function
abstractFunction() {
        die(
"AbstractClass::abstractFunction() is abstract\n" );
    }
}

class
ConcreteClass extends AbstractClass {}

$test = new ConcreteClass();
$test->abstractFunction();

File:listing04.08.05.php


<?php
require_once("DB.php");

class
Person {
    private
$name;
    private
$age;
    private
$id = 0;
    function
__construct( $name, $age ) {
        
$this->name = $name;
        
$this->age  = $age;
    }

    function
setID( $id ) {
        
$this->id = $id;
    }

    function
getName() {
        return
$this->name;
    }
    function
getAge() {
        return
$this->age;
    }
}

class
PersonPersist {
    private
$dsn;
    private
$db_obj;
    private
$fields = array( "name", "age" );

    function
__construct( $dsn ) {
        
$this->dsn = $dsn;
    }

    public function
connect( ) {
        
$this->db_obj = DB::connect($this->dsn);
    }

    public function
insert( Person $person ) {
        if ( empty(
$this->db_obj) ) {
            
$this->connect();
        }
        
$row = array();
        foreach(
$this->fields as $fieldname ) {
            
$method = "get{$fieldname}";
            
$row[$fieldname] = $person->$method();
        }
        
$row['id'] = $this->db_obj->nextId('persons_sequence');
        
$insert_result =
            
$this->db_obj->autoExecute(
            
'persons', $row, DB_AUTOQUERY_INSERT );
        
$person->setId( $row['id'] );
        return
$row['id'];
    }
}

$person = new Person( 'bob', 44 );
$saver = new PersonPersist( "sqlite://./persons.db" );
$saver->insert( $person );

?>

File:listing04.08.php


<?php
interface Chargeable {
    public function
getPrice();
}

class
ShopProduct implements Chargeable {
    
// ...
    
protected $price;
    
// ...

    
public function getPrice() {
        return
$this->price;
    }
    
// ...

}

$product = new ShopProduct();

?>

File:listing04.09.php


<?php
require_once("DB.php");

class
Person {
    private
$name;
    private
$age;
    private
$id = 0;

    function
__construct( $name, $age ) {
        
$this->name = $name;
        
$this->age  = $age;
    }

    function
setID( $id ) {
        
$this->id = $id;
    }

    function
getName() {
        return
$this->name;
    }

    function
getAge() {
        return
$this->age;
    }
}

class
PersonPersist {
    private
$dsn;
    private
$db_obj;
    private
$fields = array( "name", "age" );

    function
__construct( $dsn ) {
        
$this->dsn = $dsn;
    }

    public function
connect( ) {
        
$this->db_obj = DB::connect($this->dsn);
        if (
DB::isError( $this->db_obj )) {
            throw new
Exception("A connection error occured");
        }
    }

    public function
insert( Person $person ) {
        if ( empty(
$this->db_obj) ) {
            
$this->connect();
        }
        
$row = array();
        foreach(
$this->fields as $fieldname ) {
            
$method = "get{$fieldname}";
            
$row[$fieldname] = $person->$method();
        }
        
$row['id'] = $this->db_obj->nextId('persons_sequence');
        
$insert_result =
            
$this->db_obj->autoExecute(
            
'persons', $row, DB_AUTOQUERY_INSERT );
        
$person->setId( $row['id'] );
        return
$row['id'];
    }
}

$person = new Person( 'bob', 44 );
try {
    
$saver = new PersonPersist( "sqlite://./persons.db" );
    
$saver->insert( $person );
} catch (
Exception $e ) {
    print
$e->__toString();
}

?>

File:listing04.10.php


<?php
require_once("DB.php");

abstract class
DbException extends Exception {
    protected
$pearError;
    function
__construct( PEAR_Error $error ) {
        
parent::__construct( $error->getMessage(), $error->getCode() );
        
$this->pearError = $error;
    }
    
    function
getPearError() {
        return
$this->pearError;
    }
}

class
DbConnectionException extends DbException{ }
class
SqlException extends DbException{ }

class
Person {
    private
$name;
    private
$age;
    private
$id = 0;
    function
__construct( $name, $age ) {
        
$this->name = $name;
        
$this->age  = $age;
    }

    function
setID( $id ) {
        
$this->id = $id;
    }

    function
getName() {
        return
$this->name;
    }
    function
getAge() {
        return
$this->age;
    }
}

class
PersonPersist {
    private
$dsn;
    private
$db_obj;
    private
$fields = array( "name", "age" );

    function
__construct( $dsn ) {
        
$this->dsn = $dsn;
    }

    public function
connect( ) {
        
$this->db_obj = DB::connect($this->dsn);
        if (
DB::isError( $db_obj )) {
            throw new
DbConnectionException( $db_obj );
        }
    }

    public function
insert( Person $person ) {
        if ( empty(
$this->db_obj) ) {
            
$this->connect();
        }
        
$row = array();
        foreach(
$this->fields as $fieldname ) {
            
$method = "get{$fieldname}";
            
$row[$fieldname] = $person->$method();
        }
        
$row['id'] = $this->db_obj->nextId('persons_sequence');
        
$insert_result =
            
$this->db_obj->autoExecute(
            
'persons', $row, DB_AUTOQUERY_INSERT );

        if (
DB::isError( $insert_result )) {
            throw new
SqlException( $insert_result );
        }
        
$person->setId( $row['id'] );

        return
$row['id'];
    }
}

$person = new Person( 'bob', 44 );
try {
    
$saver = new PersonPersist( "sqlite://./persons.db" );
    
$saver->insert( $person );

} catch (
DbConnectionException $e ) {
    print
$e->__toString();

} catch (
SqlException $e ) {
    print
$e->__toString();

} catch (
Exception $e ) {
    print
$e->__toString();

}
?>

File:listing04.11.php


<?php
final class Checkout {
    
// ...
}

class
IllegalCheckout extends Checkout {
    
// ...
}

$checkout = new Checkout();

?>

File:listing04.12.php


<?php
class Checkout {
    final function
totalize() {
        
// calculate bill
    
}
}

class
IllegalCheckout extends Checkout {
    final function
totalize() {
        
// change bill calculation
    
}
}

$checkout = new Checkout();

?>

File:listing04.13.php


<?php
class Person {
    function
__get( $property ) {
        
$method = "get{$property}";
        if (
method_exists( $this, $method ) ) {
            return
$this->$method();
        }
    }
                                                                                
    function
getName() {
        return
"Bob";
    }
                                                                                
    function
getAge() {
        return
44;
    }
}

$p = new Person();
print
$p->name;
// output:
// Bob
?>

File:listing04.14.php


<?php
class Person {
    private
$_name;
    private
$_age;

    function
__set( $property, $value ) {
        
$method = "set{$property}";
        if (
method_exists( $this, $method ) ) {
            return
$this->$method( $value );
        }
    }

    function
setName( $name ) {
        
$this->_name = strtoupper($name);
    }

    function
setAge( $age ) {
        
$this->_age = $age;
    }
}

$p = new Person();
$p->name = "bob";
$p->age  = 44;
print_r( $p );
?>

File:listing04.15.php


<?php
class PersonWriter {

    function
writeName( Person $p ) {
        print
$p->getName()."\n";
    }

    function
writeAge( Person $p ) {
        print
$p->getAge()."\n";
    }
}

class
Person {
    private
$writer;

    function
__construct( PersonWriter $writer ) {
        
$this->writer = $writer;
    }

    function
__call( $method, $args ) {
        if (
method_exists( $this->writer, $method ) ) {
            return
$this->writer->$method( $this );
        }
    }

    function
getName()  { return "Bob"; }
    function
getAge() { return 44; }
}

$person= new Person( new PersonWriter() );
$person->writeName();
$person->writeAge();
?>

File:listing04.16.php


<?php
class Person {
    protected
$name;    
    private
$age;    
    private
$id;    

    function
__construct( $name, $age ) {
        
$this->name = $name;
        
$this->age  = $age;
    }

    function
setId( $id ) {
        
$this->id = $id;
    }
    
    function
__destruct() {
        if ( ! empty(
$this->id ) ) {
            
// save Person data
            
print "saving person\n";
        }
    }
}

$person = new Person( "bob", 44 );
$person->setId( 343 );
unset(
$person );

?>

File:listing04.17.1.php


<?php

class Account {
    public
$balance;
    function
__construct( $balance ) {
        
$this->balance = $balance;
    }
}

class
Person {
    private
$name;    
    private
$age;    
    private
$id;    
    public
$account;

    function
__construct( $name, $age, Account $account ) {
        
$this->name = $name;
        
$this->age  = $age;
        
$this->account = $account;
    }

    function
setId( $id ) {
        
$this->id = $id;
    }
   
    function
__clone() {
        
$this->id   = 0;
    }
}

$person = new Person( "bob", 44, new Account( 200 ) );
$person->setId( 343 );
$person2 = clone $person;

// give $person some money
$person->account->balance += 10;
// $person2 sees the credit too
print $person2->account->balance;

// output:
// 210

?>

File:listing04.17.2.php


<?php

class Account {
    public
$balance;
    function
__construct( $balance ) {
        
$this->balance = $balance;
    }
}

class
Person {
    private
$name;    
    private
$age;    
    private
$id;    
    public
$account;

    function
__construct( $name, $age, Account $account ) {
        
$this->name = $name;
        
$this->age  = $age;
        
$this->account = $account;
    }

    function
setId( $id ) {
        
$this->id = $id;
    }
   
    function
__clone() {
        
$this->id   = 0;
        
$this->account = clone $this->account;
    }
}

$person = new Person( "bob", 44, new Account( 200 ) );
$person->setId( 343 );
$person2 = clone $person;

// give $person some money
$person->account->balance += 10;
// $person2 sees the credit too
print $person2->account->balance;

// output:
// 200

?>

File:listing04.17.php


<?php
class Person {
    private
$name;    
    private
$age;    
    private
$id;    

    function
__construct( $name, $age ) {
        
$this->name = $name;
        
$this->age = $age;
    }

    function
setId( $id ) {
        
$this->id = $id;
    }
    
    function
__clone() {
        
$this->id = 0;
    }
}

$person = new Person( "bob", 44 );
$person->setId( 343 );
$person2 = clone $person;
print(
$person );
print_r( $person );
print(
$person2 );
print_r( $person2 );

?>

File:listing04.18.php


<?php

class StringThing {}
$st = new StringThing();
print
$st;
?>

File:listing04.19.php


<?php

class Person {
    function
getName()  { return "Bob"; }
    function
getAge() { return 44; }
    function
__toString() {
        
$desc  = $this->getName()." (age ".
        
$desc .= $this->getAge().")";
        return
$desc;
    }
}

$person = new Person();
print
$person;
// Bob (age 44)
?>

File:personmake.php


<?php

require_once("DB.php");
$dsn = "mysql://$user:$pass@$host/$database";

$dsn = "sqlite://./persons.db";    

$db = DB::connect($dsn);
if (
DB::isError($db) ) {    
    die (
$db->getMessage() );
}

@
$db->query( "DROP TABLE persons" );
$create =   "CREATE TABLE persons (  
                                    id INT PRIMARY KEY,
                                    name varchar(255),
                                    age int
                                    )"
;
$create_result = $db->query( $create );
if (
DB::isError( $create_result ) ) {    
    die (
$create_result->getMessage());
}
die;
$products = array(  
                array(  
"id"=>1,
                        
"type"=>"book",
                        
"firstname"=>"willa",
                        
"mainname"=>"cather",
                        
"title"=>"My Antonia",
                        
"price"=>10.99,
                        
"numpages"=>300
                
),
                array(  
"id"=>2,
                        
"type"=>"cd",
                        
"firstname"=>"The",
                        
"mainname"=>"Alabama 3",
                        
"title"=>"Exile on Coldharbour Lane",
                        
"price"=>10.99,
                        
"playlength"=>180
                
)
            );

foreach (
$products as $row ) {                    
    
$id = $db->nextId('products_sequence');
    
$row['id'] = $id;
    print
"Inserting {$row['firstname']} {$row['mainname']}: $id<br />\n";
    
$db->autoExecute( 'products', $row, DB_AUTOQUERY_INSERT );
}

$query = "SELECT * FROM products";
$query_result = $db->query( $query );

if (
DB::isError( $query_result ) ) {    
    die (
$query_result->getMessage());
}

while (
$row = $query_result->fetchRow( DB_FETCHMODE_ASSOC ) ) {
    
print_r( $row );
}

$query_result->free();
$db->disconnect();

?>

File:getCD.php


<?php

require_once( "ShopProduct.php" );

function
getProduct() {
    return new
CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
}

?>

File:listing05.01.php


<?php
require_once('business/BusinessClass.php');
require_once(
'util/UsefulClass.php');

?>

File:listing05.02.php


<?php
require_once('business/User.php');
require_once(
'forum/User.php');
// Fatal error: Cannot redeclare class user in...
?>

File:listing05.03.php


<?php

set_include_path
( get_include_path().":/home/john/phplib/");
print
get_include_path();
?>

File:listing05.04.php


<?php

function __autoload( $classname ) {
    include_once(
"$classname.php" );
}

$product = new ShopProduct( 'The Darkening', 'Harry', 'Hunter', 12.99 );
?>

File:listing05.05.php


<?php

function __autoload( $classname ) {
    
$path = str_replace('_', DIRECTORY_SEPARATOR, $classname );
    include_once(
"$path.php" );
}

$y = new business_ShopProduct();
?>

File:listing05.06.php


<?php
// listing05.06.php
$classname = "Task";

require_once(
"tasks/$classname.php" );
$myObj = new $classname();
$myObj->doSpeak();
?>

File:listing05.07.php


<?php
// listing05.06.php
$classname = "Task";
$path = "tasks/$classname.php";

if ( !
file_exists( $path ) ) {
    throw new
Exception( "No such file as $path" );
}
require_once(
$path );
if ( !
class_exists( $classname ) ) {
    throw new
Exception( "No such class as $classname" );
}

$myObj = new $classname();
$myObj->doSpeak();
?>

File:listing05.08.php


<?php
require_once( 'business/ShopProduct.php' );
require_once(
'util/UsefulClass.php' );

print_r( get_declared_classes() );
require_once(
'business/User.php' );
?>

File:listing05.09.php


<?php
require_once( 'ShopProduct.php' );

$product = getProduct();
print
get_class( $product );
if (
get_class( $product ) == 'cdproduct' ) {
    print
"\$product is a CdProduct object\n";
}

function
getProduct() {
    return new
CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
}
?>

File:listing05.10.php


<?php
require_once( 'ShopProduct.php' );

$product = getProduct();
if (
is_a( $product, 'ShopProduct' )  ) {
    print
"\$product is a ShopProduct object\n";
}

function
getProduct() {
    return new
CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
}

?>

File:listing05.11.php


<?php
require_once( 'ShopProduct.php' );

$product = getProduct();
if (
$product instanceof ShopProduct  ) {
    print
"\$product is a ShopProduct object\n";
}

function
getProduct() {
    return new
CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
}
?>

File:listing05.12.php


<?php
require_once( 'ShopProduct.php' );

$product = getProduct();
print_r( get_class_methods( 'CdProduct' ) );


function
getProduct() {
    return new
CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
}

// Array
// (
//     [0] => __construct
//     [1] => getPlayLength
//     [2] => getSummaryLine
//     [3] => getProducerFirstName
//     [4] => getProducerMainName
//     [5] => setDiscount
//     [6] => getDiscount
//     [7] => getTitle
//     [8] => getPrice
//     [9] => getProducer
//     [10] => discountPrice
// )

?>

File:listing05.13.php


<?php
require_once( 'ShopProduct.php' );

$product = getProduct(); // acquire an object
$method = "getTitle";     // define a method name
print $product->$method();  // invoke the method

function getProduct() {
    return new
CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
}
?>

File:listing05.14.php


<?php
require_once( 'ShopProduct.php' );

$product = getProduct(); // acquire an object
$method = "getTitle";     // define a method name

if ( in_array( $method, get_class_methods( $product ) ) ) {
    print
$product->$method();  // invoke the method
}

function
getProduct() {
    return new
CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
}
?>

File:listing05.15.php


<?php
require_once( 'ShopProduct.php' );

$product = getProduct(); // acquire an object
//$method = "getTitle";     // define a method name
$method = "discountPrice";     // define a method name

if ( is_callable( array( get_class($product), $method) ) ) {
    print
$product->$method();  // invoke the method
}

function
getProduct() {
    return new
CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
}
?>

File:listing05.16.php


<?php
require_once( 'ShopProduct.php' );

$product = getProduct(); // acquire an object
$method = "getTitle";     // define a method name
$method = "discountPrice";     // define a method name

if ( method_exists( $product, $method ) ) {
    print
$product->$method();  // invoke the method
}

function
getProduct() {
    return new
CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
}
?>

File:listing05.17.php


<?php
require_once( 'ShopProduct.php' );

print_r( get_class_vars( 'CdProduct' ) );
print_r( get_class_vars( 'ShopProduct' ) );
print_r( get_class_vars( 'BookProduct' ) );

// Array
// (
//     [cdproductplayLength] => 0
//     [coverUrl] =>
//     [shopproducttitle] =>
//     [shopproductproducerMainName] =>
//     [shopproductproducerFirstName] =>
//     [*price] =>
//     [shopproductdiscount] => 0
// )

?>

File:listing05.18.php


<?php
require_once( 'ShopProduct.php' );

print
get_parent_class( 'CdProduct' );

// shopproduct

?>

File:listing05.19.php


<?php
require_once( 'ShopProduct.php' );

$product = getProduct(); // acquire an object
if ( is_subclass_of( $product, 'ShopProduct' ) ) {
    print
"CdProduct is a subclass of ShopProduct\n";
}

function
getProduct() {
    return new
CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
}
?>

File:listing05.20.php


<?php
require_once( 'ShopProduct.php' );

$product = getProduct(); // acquire an object
call_user_func( array( $product, 'setDiscount' ), 20 );

function
getProduct() {
    return new
CdProduct(    "Exile on Coldharbour Lane",
                                
"The", "Alabama 3", 10.99, 60.33 );
}
?>

File:listing05.21.php


<?php
class AcmeShop {
    function
getStockArray( ) {
        return array(
"socks", "pants" );
    }
}

class
ShopTool {
    private
$thirdpartyShop;

    function
__construct( AcmeShop $thirdpartyShop ) {
        
$this->thirdpartyShop = $thirdpartyShop;
    }

    function
__call( $method, $args ) {
        if (
method_exists( $this->thirdpartyShop, $method ) ) {
            return
$this->thirdpartyShop->$method( );
        }
    }
}

$tool= new ShopTool( new AcmeShop() );
print_r( $tool->getStockArray() );
?>

File:listing05.22.php


<?php
class AcmeShop {
    function
getStockArray( ) {
        return array(
"socks", "pants" );
    }

    function
setDistrictCode( $country, $district ) {
        return
"$country, $district\n";
    }

}

class
ShopTool {
    private
$thirdpartyShop;

    function
__construct( AcmeShop $thirdpartyShop ) {
        
$this->thirdpartyShop = $thirdpartyShop;
    }

    function
__call( $method, $args ) {
        if (
method_exists( $this->thirdpartyShop, $method ) ) {
            return
call_user_func_array(
                        array(
$this->thirdpartyShop, $method ), $args );
        }
    }
}

$tool= new ShopTool( new AcmeShop() );
print_r( $tool->setDistrictCode( 'UK', 'BN' ) );
?>

File:listing05.23.php


<?php
require_once( 'ShopProduct.php' );
require_once(
'getCD.php' );
var_dump( getProduct() );

// object(CdProduct)#1 (7) {
//   ["playLength:private"]=>
//   float(60.33)
//   ["coverUrl"]=>
//   string(0) ""
//   ["title:private"]=>
//   string(25) "Exile on Coldharbour Lane"
//   ["producerMainName:private"]=>
//   string(9) "Alabama 3"
//   ["producerFirstName:private"]=>
//   string(3) "The"
//   ["price:protected"]=>
//   float(10.99)
//   ["discount:private"]=>
//   int(0)
// }



?>

File:listing05.24.php


<?php
require_once( 'ShopProduct.php' );
$cdproduct = new ReflectionClass( 'CdProduct' );
Reflection::export( $cdproduct );


?>

File:listing05.25.php


<?php
require_once( 'ShopProduct.php' );

$cdproduct = new ReflectionClass( 'CdProduct' );
print
classData( $cdproduct );

function
classData( ReflectionClass $class ) {
  
$details = "";
  
$name = $class->getName();
  if (
$class->isUserDefined() ) {
    
$details .= "$name is user defined\n";
  }
  if (
$class->isInternal() ) {
    
$details .= "$name is built-in\n";
  }
  if (
$class->isInterface() ) {
    
$details .= "$name is interface\n";
  }
  if (
$class->isAbstract() ) {
    
$details .= "$name is an abstract class\n";
  }
  if (
$class->isFinal() ) {
    
$details .= "$name is a final class\n";
  }
  if (
$class->isInstantiable() ) {
    
$details .= "$name can be instantiated\n";
  } else {
    
$details .= "$name can not be instantiated\n";
  }
  return
$details;
}

?>

File:listing05.26.php


<?php
require_once( 'ShopProduct.php' );

class
ReflectionUtil {
  static function
getClassSource( ReflectionClass $class ) {
    
$path = $class->getFileName();
    
$lines = @file( $path );
    
$from = $class->getStartLine();
    
$to   = $class->getEndLine();
    
$len  = $to-$from+1;
    return
implode( array_slice( $lines, $from-1, $len ));
  }
}

print
ReflectionUtil::getClassSource(
  new
ReflectionClass( 'CdProduct' ) );

?>

File:listing05.27.php


<?php
require_once( 'ShopProduct.php' );

$prod_class = new ReflectionClass( 'CdProduct' );
$methods = $prod_class->getMethods();

foreach (
$methods as $method ) {
  print
methodData( $method );
  print
"\n----\n";
}

function
methodData( ReflectionMethod $method ) {
  
$details = "";
  
$name = $method->getName();
  if (
$method->isUserDefined() ) {
    
$details .= "$name is user defined\n";
  }
  if (
$method->isInternal() ) {
    
$details .= "$name is built-in\n";
  }
  if (
$method->isAbstract() ) {
    
$details .= "$name is abstract\n";
  }
  if (
$method->isPublic() ) {
    
$details .= "$name is public\n";
  }
  if (
$method->isProtected() ) {
    
$details .= "$name is protected\n";
  }
  if (
$method->isPrivate() ) {
    
$details .= "$name is private\n";
  }
  if (
$method->isStatic() ) {
    
$details .= "$name is static\n";
  }
  if (
$method->isFinal() ) {
    
$details .= "$name is final\n";
  }
  if (
$method->isConstructor() ) {
    
$details .= "$name is the constructor\n";
  }
  if (
$method->returnsReference() ) {
    
$details .= "$name returns a reference (as opposed to a value)\n";
  }
  return
$details;
}

?>

File:listing05.28.php


<?php
require_once( 'ShopProduct.php' );

class
ReflectionUtil {
  static function
getMethodSource( ReflectionMethod $method ) {
    
$path = $method->getFileName();
    
$lines = @file( $path );
    
$from = $method->getStartLine();
    
$to   = $method->getEndLine();
    
$len  = $to-$from+1;
    return
implode( array_slice( $lines, $from-1, $len ));
  }
}

$class = new ReflectionClass( 'CdProduct' );
$method = $class->getMethod( 'getSummaryLine' );
print
ReflectionUtil::getMethodSource( $method );

?>

File:listing05.29.php


<?php
require_once( 'ShopProduct.php' );

$prod_class = new ReflectionClass( CdProduct );
$method = $prod_class->getMethod( "__construct" );
$params = $method->getParameters();

foreach (
$params as $param ) {
  print
argData( $param );
}

function
argData( ReflectionParameter $arg ) {
  
$details = "";
  
$name  = $arg->getName();
  
$class = $arg->getClass();

  if ( ! empty(
$class )  ) {
    
$classname = $class->getName();
    
$details .= "\$$name must be a $classname object\n";
  }
  if (
$arg->allowsNull() ) {
    
$details .= "\$$name can be null\n";
  }
  if (
$arg->isPassedByReference() ) {
    
$details .= "\$$name is passed by reference\n";
  }
  return
$details;
}

?>

File:listing05.30.php


<?php

class Person {
    public
$name;
    function
__construct( $name ) {
        
$this->name = name;
        print
"Person constructed with $name\n";
    }
}

interface
Module {
    function
execute();
}

class
FtpModule implements Module {
    function
setHost( $host ) {
        print
"FtpModule::setHost(): $host\n";
    }

    function
setUser( $user ) {
        print
"FtpModule::setUser(): $user\n";
    }

    function
execute() {
        
// do things
    
}
}

class
PersonModule implements Module {
    function
setPerson( Person $person ) {
        print
"PersonModule::setPerson(): {$person->name}\n";
    }
    
    function
execute() {
        
// do things
    
}
}

?>

File:listing05.31.php


<?php
require_once( 'listing05.30.php' );
class
ModuleRunner {
    private
$configData
            
= array(
                    
"PersonModule" => array( 'person'=>'bob' ),
                    
"FtpModule"    => array( 'host'  =>'example.com',
                                             
'user'  =>'anon' )
              );
    private
$modules = array();

    function
init() {
        
$interface = new ReflectionClass('Module');
        foreach (
$this->configData as $modulename => $params ) {
            
$module_class = new ReflectionClass( $modulename );
            if ( !
$module_class->isSubclassOf( $interface ) ) {
               throw new
Exception( "unknown module type: $modulename" );
            }
            
$module = $module_class->newInstance();
            foreach (
$module_class->getMethods() as $method ) {
                
$this->handleMethod( $module, $method, $params );
            }
            
array_push( $this->modules, $module );
        }
    }

    function
handleMethod(  Module $module,
                            
ReflectionMethod $method,
                            
$params ) {
        
$name = $method->getName();
        
$args = $method->getParameters();
        if (
count( $args ) != 1 ||
             
substr( $name, 0, 3 ) != "set" ) {
            return
false;
        }
        
$property = strtolower( substr( $name, 3 ));
        if ( ! isset(
$params[$property] ) ) {
            return
false;
        }
        
$arg_class = $args[0]->getClass();
        if ( empty(
$arg_class ) ) {
            
$method->invoke( $module, $params[$property] );
        } else {
            
$method->invoke( $module, $arg_class->newInstance( $params[$property] ) );
        }
    }
}

$test = new ModuleRunner();
$test->init();
?>

File:ShopProduct.php


<?php
class ShopProduct {
    private
$title;
    private
$producerMainName;
    private
$producerFirstName;
    protected
$price;
    private
$discount = 0;
    
    public function
__construct(   $title, $firstName,
                            
$mainName, $price ) {
        
$this->title             = $title;
        
$this->producerFirstName = $firstName;
        
$this->producerMainName  = $mainName;
        
$this->price             = $price;
    }


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

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

    public function
setDiscount( $num ) {
        print
"set discount called\n";
        
$this->discount=$num;
    }

    public function
getDiscount() {
        return
$this->discount;
    }
    
    public function
getTitle() {
        return
$this->title;
    }

    public function
getPrice() {
        return (
$this->price - $this->discount);
    }

    public function
getProducer() {
        return
"{$this->producerFirstName}".
               
" {$this->producerMainName}";
    }

    function
getSummaryLine() {
        
$base  = "$this->title ( $this->producerMainName, ";
        
$base .= "$this->producerFirstName )";
        return
$base;
    }

    protected function
discountPrice() {
        print
"discount price";        
    }
}

class
CdProduct extends ShopProduct {
    private
$playLength = 44;
    public
$coverUrl = "";

    public function
__construct(   $title, $firstName,
                            
$mainName, $price, $playLength ) {
        
parent::__construct(    $title, $firstName,
                                
$mainName, $price );
        
$this->playLength = $playLength;
    }

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

    function
getSummaryLine() {
        
$base = parent::getSummaryLine();
        
$base .= ": playing time - $this->playLength";
        return
$base;
    }

}

class
BookProduct extends ShopProduct {
    private
$numPages = 0;

    public function
__construct(   $title, $firstName,
                            
$mainName, $price, $numPages ) {
        
parent::__construct(    $title, $firstName,
                                
$mainName, $price );
        
$this->numPages = $numPages;
    }

    public function
getNumberOfPages() {
        return
$this->numPages;
    }
   
    function
getSummaryLine() {
        
$base = parent::getSummaryLine();
        
$base .= ": page count - $this->numPages";
        return
$base;
    }

    public function
getPrice() {
        return
$this->price;
    }
}
?>

File:bob-setup.php


<?php
require_once("DB.php");

$dsn[] = "mysql://bob:pass@localhost/test";
$dsn[] = "sqlite://./bobs_db.db";    
$table = "bobs_table";
$create =   "CREATE TABLE $table (  id INT PRIMARY KEY,
                                    lesson_name varchar(255),
                                    duration    int )"
;
$insert = array(    
            array(
"lesson_name" => "applied doodads",
                   
"duration"    => 3 ),
            array(
"lesson_name" => "how to spam",
                   
"duration"    => 2 ),
);

foreach (
$dsn as $str ) {
    
$db = DB::connect($str);
    @
$db->query( "DROP TABLE $table" );
    
$db->query( $create );

    
$delete_query = $db->query( "delete from $table" );
    if (
DB::isError( $delete_query ) ) {    
        die (
$delete_query->getMessage());
    }

    foreach (
$insert as $row ) {                    
        
$id = $db->nextId( $table.'_sequence');
        
$row['id'] = $id;
        
$db->autoExecute( $table, $row, DB_AUTOQUERY_INSERT );
        
$db->disconnect();
    }
}
?>

File:bob-setup.sql


INSERT INTO db VALUES ('localhost','bobs_db','bob','Y','Y','Y','Y','Y','Y','N','N','N','N');
INSERT INTO user VALUES ('localhost','bob', password('bobs_pass'),'N','N','N','N','N','N','N','N','N','N','N','N','N','N');

File:bobs_db.db


** This file contains an SQLite 2.1 database **(uãÚµ8Ì€2€
%022index(bobs_table autoindex 1)bobs_table3
É€
"$Établebobs_tablebobs_table4CREATE TABLE bobs_table (  id INT PRIMARY KEY, 
                                    lesson_name varchar(255),
                                    duration    int )Ð…€ $<>…tablebobs_table_sequence_seqbobs_table_sequence_seq5CREATE TABLE bobs_table_sequence_seq (id INTEGER UNSIGNED PRIMARY KEY)÷/\1€ 4LN1triggerbobs_table_sequence_seq_cleanupbobs_table_sequence_seq0CREATE TRIGGER bobs_table_sequence_seq_cleanup AFTER INSERT ON bobs_table_sequence_seq
                    BEGIN
                        DELETE FROM bobs_48
b0G1Z€'@
b0G1a€'@ÈT0€3applied doodads3€4how to spam2¬0€6@€6@Ðtable_sequence_seq WHERE id<LAST_INSERT_ROWID();
                    END

File:listing08.01.php


<?php
abstract class Lesson {
    protected
$duration;
    const     
FIXED = 1;
    const     
TIMED = 2;
    private   
$costtype = 1;

    function
__construct( $duration, $costtype=1 ) {
        
$this->duration = $duration;
        
$this->costtype = $costtype;
    }

    function
cost() {
        switch (
$this->costtype ) {
            CASE
self::TIMED :
                return (
5 * $this->duration);
                break;
            CASE
self::FIXED :
                return
30;
                break;
            default:
                
$this->costtype = self::FIXED;
                return
30;
        }
    }

    function
chargeType() {
        switch (
$this->costtype ) {
            CASE
self::TIMED :
                return
"hourly rate";
                break;
            CASE
self::FIXED :
                return
"fixed rate";
                break;
            default:
                
$this->costtype = self::FIXED;
                return
"fixed rate";
        }
    }

    
// more lesson methods...
}

class
Lecture extends Lesson {
    
// Lecture specific implementations ...
}

class
Seminar extends Lesson {
    
// Seminar specific implementations ...
}

$lesson = new Seminar( 4, Lesson::TIMED );
$lesson = new Seminar( 4, Lesson::FIXED );
$lesson = new Seminar( 4, 33 );
print
"lesson charge {$lesson->cost()}. Charge type: {$lesson->chargeType()}\n";
?>

File:listing08.02.php


<?php
abstract class Lesson {
    private   
$duration;
    private   
$costStrategy;

    function
__construct( $duration, CostStrategy $strategy ) {
        
$this->duration = $duration;
        
$this->costStrategy = $strategy;
    }

    function
cost() {
        return
$this->costStrategy->cost( $this );
    }

    function
chargeType() {
        return
$this->costStrategy->chargeType( );
    }

    function
getDuration() {
        return
$this->duration;
    }

    
// more lesson methods...
}

class
Lecture extends Lesson {
    
// Lecture specific implementations ...
}

class
Seminar extends Lesson {
    
// Seminar specific implementations ...
}

abstract class
CostStrategy {
    abstract function
cost( Lesson $lesson );
    abstract function
chargeType();
}

class
TimedCostStrategy extends CostStrategy {
    function
cost( Lesson $lesson ) {
        return (
$lesson->getDuration() * 5 );
    }
    function
chargeType() {
        return
"hourly rate";
    }
}

class
FixedCostStrategy extends CostStrategy {
    function
cost( Lesson $lesson ) {
        return
30;
    }

    function
chargeType() {
        return
"fixed rate";
    }
}

$lessons[] = new Seminar( 4, new TimedCostStrategy() );
$lessons[] = new Lecture( 4, new FixedCostStrategy() );

foreach (
$lessons as $lesson ) {
    print
"lesson charge {$lesson->cost()}. ";
    print
"Charge type: {$lesson->chargeType()}\n";
}

// output:
// lesson charge 20. Charge type: hourly rate
// lesson charge 30. Charge type: fixed rate

?>

File:listing08.03-errorhandling.php


<?php
require_once("DB.php");
$dsn_array[] = "mysql://bob:bobs_pass@localhost/bobs_db";
$dsn_array[] = "sqlite://./bobs_db.db";    

foreach (
$dsn_array as $dsn ) {
    
$db = DB::connect($dsn);
    if (
DB::isError($db) ) {    
        die (
$db->getMessage() );
    }

    
$query_result = $db->query( "SELECT * FROM bobs_table" );

    if (
DB::isError($query_result) ) {    
        die (
$query_result->getMessage());
    }

    while (
$row = $query_result->fetchRow( DB_FETCHMODE_ASSOC ) ) {
        
print_r( $row );
    }

    
$query_result->free();
    
$db->disconnect();
}

?>

File:listing08.03.loop.php


<?php
require_once("DB.php");
$dsn_array[] = "mysql://bob:bobs_pass@localhost/bobs_db";
$dsn_array[] = "sqlite://./bobs_db.db";    

foreach (
$dsn_array as $dsn ) {
    print
"$dsn\n\n";
    
$db = DB::connect($dsn);
    
$query_result = $db->query( "SELECT * FROM bobs_table" );
    while (
$row = $query_result->fetchRow( DB_FETCHMODE_ARRAY ) ) {
        
printf( "| %-4s| %-4s| %-25s|", $row[0], $row[2], $row[1] );
        print
"\n";
    }
    print
"\n";
    
$query_result->free();
    
$db->disconnect();
}

?>

File:listing08.03.php


<?php
require_once("DB.php");
$dsn_array[] = "mysql://bob:pass@localhost/bobs_db";
$dsn_array[] = "sqlite://./bobs_db.db";    

foreach (
$dsn_array as $dsn ) {
    print
"$dsn\n\n";
    
$db = DB::connect($dsn);
    
$query_result = $db->query( "SELECT * FROM bobs_table" );
    while (
$row = $query_result->fetchRow( DB_FETCHMODE_ARRAY ) ) {
        
printf( "| %-4s| %-4s| %-25s|", $row[0], $row[2], $row[1] );
        print
"\n";
    }
    print
"\n";
    
$query_result->free();
    
$db->disconnect();
}

?>

File:listing09.01.php


<?php

abstract class Employee {
    protected
$name;
    function
__construct( $name ) {
        
$this->name = $name;
    }
    abstract function
fire();
}

class
Minion extends Employee {
    function
fire() {
        print
"{$this->name}: I'll clear my desk\n";
    }
}

class
NastyBoss {
    private
$employees = array();

    function
addEmployee( $employeeName ) {
        
$this->employees[] = new Minion( $employeeName );
    }

    function
projectFails() {
        if (
count( $this->employees ) ) {
            
$emp = array_pop( $this->employees );
            
$emp->fire();
        }
    }
}

$boss = new NastyBoss();
$boss->addEmployee( "harry" );
$boss->addEmployee( "bob" );
$boss->addEmployee( "mary" );
$boss->projectFails();

// output:
// mary: I'll clear my desk
?>

File:listing09.02.php


<?php

abstract class Employee {
    protected
$name;
    function
__construct( $name ) {
        
$this->name = $name;
    }
    abstract function
fire();
}

class
Minion extends Employee {
    function
fire() {
        print
"{$this->name}: I'll clear my desk\n";
    }
}

class
CluedUp extends Employee {
    function
fire() {
        print
"{$this->name}: I'll call my lawyer\n";
    }
}

class
NastyBoss {
    private
$employees = array();

    function
addEmployee( Employee $employee ) {
        
$this->employees[] = $employee;
    }

    function
projectFails() {
        if (
count( $this->employees ) ) {
            
$emp = array_pop( $this->employees );
            
$emp->fire();
        }
    }
}

$boss = new NastyBoss();
$boss->addEmployee( new Minion( "harry" ) );
$boss->addEmployee( new CluedUp( "bob" ) );
$boss->addEmployee( new Minion( "mary" ) );
$boss->projectFails();
$boss->projectFails();
$boss->projectFails();

// output:
// mary: I'll clear my desk
// bob: I'll call my lawyer
// harry: I'll clear my desk

?>

File:listing09.03.php


<?php

abstract class Employee {
    protected
$name;
    private static
$types = array( 'minion', 'cluedup', 'wellconnected' );

    static function
recruit( $name ) {
        
$num = rand( 1, count( self::$types ) )-1;        
        
$class = self::$types[$num];
        return new
$class( $name );
    }

    function
__construct( $name ) {
        
$this->name = $name;
    }
    abstract function
fire();
}

class
Minion extends Employee {
    function
fire() {
        print
"{$this->name}: I'll clear my desk\n";
    }
}

class
WellConnected extends Employee {
    function
fire() {
        print
"{$this->name}: I'll call my dad\n";
    }
}

class
CluedUp extends Employee {
    function
fire() {
        print
"{$this->name}: I'll call my lawyer\n";
    }
}

class
NastyBoss {
    private
$employees = array();

    function
addEmployee( Employee $employee ) {
        
$this->employees[] = $employee;
    }

    function
projectFails() {
        if (
count( $this->employees ) ) {
            
$emp = array_pop( $this->employees );
            
$emp->fire();
        }
    }
}

$boss = new NastyBoss();
$boss->addEmployee( Employee::recruit( "harry" ) );
$boss->addEmployee( Employee::recruit( "bob" ) );
$boss->addEmployee( Employee::recruit( "mary" ) );
$boss->projectFails();
$boss->projectFails();
$boss->projectFails();
?>

File:listing09.04.php


<?php

class Preferences {
    private
$props = array();

    private function
__construct() { }

    public function
setProperty( $key, $val ) {
        
$this->props[$key] = $val;
    }

    public function
getProperty( $key ) {
        return
$this->props[$key];
    }
}

?>

File:listing09.05.php


<?php

abstract class ApptEncoder {
    abstract function
encode();
}

class
BloggsApptEncoder extends ApptEncoder {
    function
encode() {
        return
"Appointment data encode in BloggsCal format\n";
    }
}

abstract class
CommsManager {
    abstract function
getHeaderText();
    abstract function
getApptEncoder();
    abstract function
getFooterText();
}

class
BloggsCommsManager extends CommsManager {
    function
getHeaderText() {
        return
"BloggsCal header\n";
    }

    function
getApptEncoder() {
        return new
BloggsApptEncoder();
    }

    function
getFooterText() {
        return
"BloggsCal footer\n";
    }
}

$comms = new BloggsCommsManager();
$apptEncoder = $comms->getApptEncoder();
print
$comms->getHeaderText();
print
$apptEncoder->encode();
print
$comms->getFooterText();
?>

File:listing09.06.php


<?php

abstract class ApptEncoder {
    abstract function
encode();
}

class
BloggsApptEncoder extends ApptEncoder {
    function
encode() {
        return
"Appointment data encoded in BloggsCal format\n";
    }
}

class
MegaApptEncoder extends ApptEncoder {
    function
encode() {
        return
"Appointment data encoded in MegaCal format\n";
    }
}

class
CommsManager {
    const
BLOGGS = 1;    
    const
MEGA = 2;    
    private
$mode = 1;

    function
__construct( $mode ) {
        
$this->mode = $mode;
    }

    function
getApptEncoder() {
        switch (
$this->mode ) {
            case (
self::MEGA ):
                return new
MegaApptEncoder();                
            default:
                return new
BloggsEncoder();                
        }
    }
}

$comms = new CommsManager( CommsManager::MEGA );
$apptEncoder = $comms->getApptEncoder();
print
$apptEncoder->encode();
?>

File:listing09.07.php


<?php

abstract class ApptEncoder {
    abstract function
encode();
}

class
BloggsApptEncoder extends ApptEncoder {
    function
encode() {
        return
"Appointment data encoded in BloggsCal format\n";
    }
}

class
MegaApptEncoder extends ApptEncoder {
    function
encode() {
        return
"Appointment data encoded in MegaCal format\n";
    }
}

class
CommsManager {
    const
BLOGGS = 1;    
    const
MEGA = 2;    
    private
$mode = 1;

    function
__construct( $mode ) {
        
$this->mode = $mode;
    }

    function
getHeaderText() {
        switch (
$this->mode ) {
            case (
self::MEGA ):
                return
"MegaCal header\n";
            default:
                return
"BloggsCal header\n";
        }
    }

    function
getApptEncoder() {
        switch (
$this->mode ) {
            case (
self::MEGA ):
                return new
MegaApptEncoder();                
            default:
                return new
BloggsEncoder();                
        }
    }
}

$comms = new CommsManager( CommsManager::MEGA );
$apptEncoder = $comms->getApptEncoder();
print
$comms->getHeaderText();
print
$apptEncoder->encode();
?>

File:listing09.08.php


<?php

abstract class ApptEncoder {
    abstract function
encode();
}

abstract class
TtdEncoder {
    abstract function
encode();
}

abstract class
ContactEncoder {
    abstract function
encode();
}

class
BloggsApptEncoder extends ApptEncoder {
    function
encode() {
        return
"Appointment data encoded in BloggsCal format\n";
    }
}

class
BloggsContactEncoder extends ContactEncoder {
    function
encode() {
        return
"Contact data encoded in BloggsCal format\n";
    }
}

class
BloggsTtdEncoder extends ApptEncoder {
    function
encode() {
        return
"Things to do data encoded in BloggsCal format\n";
    }
}

class
MegaApptEncoder extends ApptEncoder {
    function
encode() {
        return
"Appointment data encoded in MegaCal format\n";
    }
}

abstract class
CommsManager {
    abstract function
getHeaderText();
    abstract function
getApptEncoder();
    abstract function
getTtdEncoder();
    abstract function
getContactEncoder();
    abstract function
getFooterText();
}

class
BloggsCommsManager extends CommsManager {
    function
getHeaderText() {
        return
"BloggsCal header\n";
    }

    function
getApptEncoder() {
        return new
BloggsApptEncoder();
    }

    function
getTtdEncoder() {
        return new
BloggsTtdEncoder();
    }

    function
getContactEncoder() {
        return new
BloggsContactEncoder();
    }

    function
getFooterText() {
        return
"BloggsCal footer\n";
    }
}

$comms = new BloggsCommsManager();
print
$comms->getHeaderText();
print
$comms->getApptEncoder()->encode();
print
$comms->getTtdEncoder()->encode();
print
$comms->getContactEncoder()->encode();
print
$comms->getFooterText();

?>

File:listing09.09.php


<?php

abstract class ApptEncoder {
    abstract function
encode();
}

abstract class
TtdEncoder {
    abstract function
encode();
}

abstract class
ContactEncoder {
    abstract function
encode();
}

class
BloggsApptEncoder extends ApptEncoder {
    function
encode() {
        return
"Appointment data encoded in BloggsCal format\n";
    }
}

class
BloggsContactEncoder extends ContactEncoder {
    function
encode() {
        return
"Contact data encoded in BloggsCal format\n";
    }
}

class
BloggsTtdEncoder extends ApptEncoder {
    function
encode() {
        return
"Things to do data encoded in BloggsCal format\n";
    }
}

class
MegaApptEncoder extends ApptEncoder {
    function
encode() {
        return
"Appointment data encoded in MegaCal format\n";
    }
}

abstract class
CommsManager {
    const
APPT    = 1;
    const
TTD     = 2;
    const
CONTACT = 3;
    abstract function
getHeaderText();
    abstract function
make( $flag_int );
    abstract function
getFooterText();
}

class
BloggsCommsManager extends CommsManager {
    function
getHeaderText() {
        return
"BloggsCal header\n";
    }

    function
make( $flag_int ) {
        switch (
$flag_int ) {
            case
self::APPT:
                return new
BloggsApptEncoder();
            case
self::CONTACT:
                return new
BloggsContactEncoder();
            case
self::TTD:
                return new
BloggsTtdEncoder();
        }
    }

    function
getFooterText() {
        return
"BloggsCal footer\n";
    }
}

$comms = new BloggsCommsManager();
print
$comms->getHeaderText();
print
$comms->make( CommsManager::APPT )->encode();
print
$comms->make( CommsManager::TTD )->encode();
print
$comms->make( CommsManager::CONTACT )->encode();
print
$comms->getFooterText();

?>

File:listing09.10.php


<?php
class Sea {}
class
EarthSea extends Sea {}
class
MarsSea extends Sea {}

class
Plains {}
class
EarthPlains extends Plains {}
class
MarsPlains extends Plains {}

class
Forest {}
class
EarthForest extends Forest {}
class
MarsForest extends Forest {}

class
TerrainFactory {
    private
$sea;
    private
$forest;
    private
$plains;

    function
__construct( Sea $sea, Plains $plains, Forest $forest ) {
        
$this->sea = $sea;
        
$this->plains = $plains;
        
$this->forest = $forest;
    }

    function
getSea( ) {
        return clone
$this->sea;
    }

    function
getPlains( ) {
        return clone
$this->plains;
    }

    function
getForest( ) {
        return clone
$this->forest;
    }
}

$factory = new TerrainFactory( new EarthSea(), new EarthPlains(), new EarthForest() );
print_r( $factory->getSea() );
print_r( $factory->getPlains() );
print_r( $factory->getForest() );

File:listing09.11.php


<?php
class Sea {
    private
$navigability = 0;
    function
__construct( $navigability ) {
        
$this->navigability = $navigability;
    }
}
class
EarthSea extends Sea {}
class
MarsSea extends Sea {}

class
Plains {}
class
EarthPlains extends Plains {}
class
MarsPlains extends Plains {}

class
Forest {}
class
EarthForest extends Forest {}
class
MarsForest extends Forest {}

class
TerrainFactory {
    private
$sea;
    private
$forest;
    private
$plains;

    function
__construct( Sea $sea, Plains $plains, Forest $forest ) {
        
$this->sea = $sea;
        
$this->plains = $plains;
        
$this->forest = $forest;
    }

    function
getSea( ) {
        return clone
$this->sea;
    }

    function
getPlains( ) {
        return clone
$this->plains;
    }

    function
getForest( ) {
        return clone
$this->forest;
    }
}

$factory = new TerrainFactory( new EarthSea( -1 ),
    new
EarthPlains(),
    new
EarthForest() );
print_r( $factory->getSea() );
print_r( $factory->getPlains() );
print_r( $factory->getForest() );

File:listing09.12.php


<?php

class Contained {
    public
$now = 5;
}

class
Container {
    public
$contained;
    function
__construct() {
        
$this->contained = new Contained();
    }

    function
__clone() {
        
// Ensure that cloned object holds a
        // clone of self::$contained and not
        // a reference to it
        
$this->contained = clone $this->contained;
    }
}

$original = new Container();
$copy = clone $original;
$original->contained->now = -1;
print_r( $original );
print_r( $copy );
?>

File:listing09.13.php


<?php
require_once( 'CommsClasses.php' );
require_once(
'Settings.php' );

class
AppConfig {
    private static
$instance;
    private
$commsManager;

    private function
__construct() {
        
// run once only
        
$this->init();
    }

    private function
init() {
        switch (
Settings::$COMMSTYPE ) {
            case
'Mega':    
                
$this->commsManager = new MegaCommsManager();
                break;
            default:        
                
$this->commsManager = new BloggsCommsManager();
        }
    }
    
    public static function
getInstance() {
        if ( empty(
self::$instance ) ) {
            
self::$instance = new self();
        }
        return
self::$instance;
    }

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

$commsMgr = AppConfig::getInstance()->getCommsManager();
print_r( $commsMgr );
?>

File:eg1.php


<?php

abstract class Unit {
    abstract function
bombardStrength();
}

class
Archer extends Unit {
    function
bombardStrength() {
        return
4;
    }
}

class
LaserCanonUnit extends Unit {
    function
bombardStrength() {
        return
44;
    }
}

class
Army {
    private
$units = array();

    function
addUnit( Unit $unit ) {
        
array_push( $this->units, $unit );
    }

    function
bombardStrength() {
        
$ret = 0;
        foreach(
$this->units as $unit ) {
            
$ret += $unit->bombardStrength();
        }
        return
$ret;
    }
}

$army = new Army();
$army->addUnit( new Archer() );
$army->addUnit( new LaserCanonUnit() );
print
"attacking with strength: {$army->bombardStrength()}\n";

File:eg10.php


<?php

function getProductFileLines( $file ) {
    return
file( $file );
}

function
getProductObjectFromId( $id, $productname ) {
    
// some kind of database lookup
    
return new Product( $id, $productname );
}

function
getNameFromLine( $line ) {
    if (
preg_match( "/.*-(.*)\s\d+/", $line, $array ) ) {
        return
str_replace( '_',' ', $array[1] );
    }
    return
'';
}

function
getIDFromLine( $line ) {
    if (
preg_match( "/^(\d{1,3})-/", $line, $array ) ) {
        return
$array[1];
    }
    return -
1;
}

class
Product {
    public
$id;
    public
$name;
    function
__construct( $id, $name ) {
        
$this->id = $id;
        
$this->name = $name;
    }
}

$lines = getProductFileLines( 'test.txt' );
$objects = array();
foreach (
$lines as $line ) {
    
$id = getIDFromLine( $line );
    
$name = getNameFromLine( $line );
    
$objects[$id] = getProductObjectFromID( $id, $name  );
}

print_r( $objects );

class
ProductFacade {
    private
$products = array();

    function
__construct( $file ) {
        
$this->file = $file;
        
$this->compile();
    }

    private function
compile() {
        
$lines = getProductFileLines( $this->file );
        foreach (
$lines as $line ) {
            
$id = getIDFromLine( $line );
            
$name = getNameFromLine( $line );
            
$this->products[$id] = getProductObjectFromID( $id, $name  );
        }
    }

    function
getProducts() {
        return
$this->products;
    }

    function
getProduct( $id ) {
        return
$this->products[$id];
    }
}
$facade = new ProductFacade( 'test.txt' );
print_r( $facade->getProducts() );
print
"--\n";
print_r( $facade->getProduct(234) );
?>

File:eg2.php


<?php

abstract class Unit {
    abstract function
bombardStrength();
}

class
Archer extends Unit {
    function
bombardStrength() {
        return
4;
    }
}

class
LaserCanonUnit extends Unit {
    function
bombardStrength() {
        return
44;
    }
}

class
Army {
    private
$units = array();
    private
$armies = array();

    function
addUnit( Unit $unit ) {
        
array_push( $this->units, $unit );
    }

    function
addArmy( Army $army ) {
        
array_push( $this->armies, $army );
    }

    function
bombardStrength() {
        
$ret = 0;
        foreach(
$this->units as $unit ) {
            
$ret += $unit->bombardStrength();
        }

        foreach(
$this->armies as $army ) {
            
$ret += $army->bombardStrength();
        }

        return
$ret;
    }
}

$main_army = new Army();
$main_army->addUnit( new Archer() );
$main_army->addUnit( new LaserCanonUnit() );

$sub_army = new Army();
$sub_army->addUnit( new Archer() );
$sub_army->addUnit( new Archer() );
$sub_army->addUnit( new Archer() );
$main_army->addArmy( $sub_army );

print
"attacking with strength: {$main_army->bombardStrength()}\n";

File:eg3.php


<?php

class UnitException extends Exception {}

abstract class
Unit {
    abstract function
addUnit( Unit $unit );
    abstract function
removeUnit( Unit $unit );
    abstract function
bombardStrength();
}

class
Archer extends Unit {
    function
addUnit( Unit $unit ) {
        throw new
UnitException( get_class($this)." is a leaf" );
    }

    function
removeUnit( Unit $unit ) {
        throw new
UnitException( get_class($this)." is a leaf" );
    }

    function
bombardStrength() {
        return
4;
    }
}

class
LaserCanonUnit extends Unit {
    function
addUnit( Unit $unit ) {
        throw new
UnitException( get_class($this)." is a leaf" );
    }

    function
removeUnit( Unit $unit ) {
        throw new
UnitException( get_class($this)." is a leaf" );
    }

    function
bombardStrength() {
        return
44;
    }
}

class
Army extends Unit {
    private
$units = array();

    function
addUnit( Unit $unit ) {
        foreach (
$this->units as $thisunit ) {
            if (
$unit === $thisunit ) {
                return;
            }
        }
        
$this->units[] = $unit;
    }

    function
removeUnit( Unit $unit ) {
        
$units = array();
        foreach (
$this->units as $thisunit ) {
            if (
$unit !== $thisunit ) {
                
$units[] = $thisunit;
            }
        }
        
$this->units = $units;
    }

    function
bombardStrength() {
        
$ret = 0;
        foreach(
$this->units as $unit ) {
            
$ret += $unit->bombardStrength();
        }
        return
$ret;
    }
}

$main_army = new Army();
$main_army->addUnit( new Archer() );
$main_army->addUnit( new LaserCanonUnit() );

$sub_army = new Army();
$sub_army->addUnit( new Archer() );
$sub_army->addUnit( $test = new Archer() );
$sub_army->addUnit( new Archer() );

$sub_army->removeUnit( $test );
$main_army->addUnit( $sub_army );

print
"attacking with strength: {$main_army->bombardStrength()}\n";

File:eg4.php


<?php

class UnitException extends Exception {}

abstract class
Unit {
    abstract function
bombardStrength();

    function
addUnit( Unit $unit ) {
        throw new
UnitException( get_class($this)." is a leaf" );
    }

    function
removeUnit( Unit $unit ) {
        throw new
UnitException( get_class($this)." is a leaf" );
    }
}

class
Archer extends Unit {
    function
bombardStrength() {
        return
4;
    }
}

class
LaserCanonUnit extends Unit {

    function
bombardStrength() {
        return
44;
    }
}

class
Army extends Unit {
    private
$units = array();

    function
addUnit( Unit $unit ) {
        foreach (
$this->units as $thisunit ) {
            if (
$unit === $thisunit ) {
                return;
            }
        }
        
$this->units[] = $unit;
    }

    function
removeUnit( Unit $unit ) {
        
$units = array();
        foreach (
$this->units as $thisunit ) {
            if (
$unit !== $thisunit ) {
                
$units[] = $thisunit;
            }
        }
        
$this->units = $units;
    }

    function
bombardStrength() {
        
$ret = 0;
        foreach(
$this->units as $unit ) {
            
$ret += $unit->bombardStrength();
        }
        return
$ret;
    }
}

// create an army
$main_army = new Army();

// add some units
$main_army->addUnit( new Archer() );
$main_army->addUnit( new LaserCanonUnit() );

// create a new army
$sub_army = new Army();

// add some units
$sub_army->addUnit( new Archer() );
$sub_army->addUnit( new Archer() );
$sub_army->addUnit( new Archer() );

// add the second army to the first
$main_army->addUnit( $sub_army );

// all the calculations handled behind the scenes
print "attacking with strength: {$main_army->bombardStrength()}\n";

File:eg5.php


<?php

class UnitException extends Exception {}

abstract class
Unit {
    function
getComposite() {
        return
null;
    }

    abstract function
bombardStrength();
}

class
Archer extends Unit {
    function
bombardStrength() {
        return
4;
    }
}

class
LaserCanonUnit extends Unit {
    function
bombardStrength() {
        return
44;
    }
}

abstract class
CompositeUnit extends Unit {
    private
$units = array();

    function
getComposite() {
        return
$this;
    }

    function
units() {
        return
$this->units;
    }

    function
removeUnit( Unit $unit ) {
        
$units = array();
        foreach (
$this->units as $thisunit ) {
            if (
$unit !== $thisunit ) {
                
$units[] = $thisunit;
            }
        }
        
$this->units = $units;
    }

    function
addUnit( Unit $unit ) {
        foreach (
$this->units as $thisunit ) {
            if (
$unit === $thisunit ) {
                return;
            }
        }
        
$this->units[] = $unit;
    }
}

class
Army extends CompositeUnit {

    function
bombardStrength() {
        
$ret = 0;
        foreach(
$this->units() as $unit ) {
            
$ret += $unit->bombardStrength();
        }
        return
$ret;
    }
}

$main_army = new Army();
$main_army->addUnit( new Archer() );
$main_army->addUnit( new LaserCanonUnit() );

UnitScript::joinExisting( new Archer(), $main_army );
$combined = UnitScript::joinExisting( new Archer(), new LaserCanonUnit() );
print_r( $combined );

class
UnitScript {
    static function
joinExisting( Unit $newUnit, Unit $occupyingUnit ) {
        
$comp;
        if (
$comp = $occupyingUnit->getComposite() ) {
            
$comp->addUnit( $newUnit );
        } else {
            
$comp = new Army();
            
$comp->addUnit( $occupyingUnit );
            
$comp->addUnit( $newUnit );
        }
        return
$comp;
    }
}

File:eg6.php


<?php

class UnitException extends Exception {}

abstract class
Unit {
    function
getComposite() {
        return
null;
    }

    abstract function
bombardStrength();
}

class
Archer extends Unit {
    function
bombardStrength() {
        return
4;
    }
}

class
Cavalry extends Unit {
    function
bombardStrength() {
        return
2;
    }
}

class
LaserCanonUnit extends Unit {
    function
bombardStrength() {
        return
44;
    }
}

abstract class
CompositeUnit extends Unit {
    private
$units = array();

    function
getComposite() {
        return
$this;
    }

    function
units() {
        return
$this->units;
    }

    function
removeUnit( Unit $unit ) {
        
$units = array();
        foreach (
$this->units as $thisunit ) {
            if (
$unit !== $thisunit ) {
                
$units[] = $thisunit;
            }
        }
        
$this->units = $units;
    }

    function
addUnit( Unit $unit ) {
        foreach (
$this->units as $thisunit ) {
            if (
$unit === $thisunit ) {
                return;
            }
        }
        
$this->units[] = $unit;
    }
}

class
TroopCarrier extends CompositeUnit {

    function
addUnit( Unit $unit ) {
        if (
$unit instanceof Cavalry ) {
            throw new
UnitException("Can't get a horse on the vehicle");
        }
        
parent::addUnit( $unit );
    }

    function
bombardStrength() {
        return
0;
    }
}

class
Army extends CompositeUnit {

    function
bombardStrength() {
        
$ret = 0;
        foreach(
$this->units() as $unit ) {
            
$ret += $unit->bombardStrength();
        }
        return
$ret;
    }
}

$main_army = new TroopCarrier();
$main_army->addUnit( new Archer() );
$main_army->addUnit( new LaserCanonUnit() );
$main_army->addUnit( new Cavalry() );

File:eg7.php


<?php

abstract class Tile {
    abstract function
getWealthFactor();
}

class
Plains extends Tile {
    private
$wealthfactor = 2;
    function
getWealthFactor() {
        return
$this->wealthfactor;
    }
}

class
DiamondPlains extends Plains {
    function
getWealthFactor() {
        return
parent::getWealthFactor() + 2;
    }
}

class
PollutedPlains extends Plains {
    function
getWealthFactor() {
        return
parent::getWealthFactor() - 4;
    }
}

$tile = new PollutedPlains();
print
$tile->getWealthFactor();
?>

File:eg8.php


<?php

abstract class Tile {
    abstract function
getWealthFactor();
}

class
Plains extends Tile {
    private
$wealthfactor = 2;
    function
getWealthFactor() {
        return
$this->wealthfactor;
    }
}

abstract class
TileDecorator extends Tile {
    protected
$tile;
    function
__construct( Tile $tile ) {
        
$this->tile = $tile;    
    }
}

class
DiamondDecorator extends TileDecorator {
    function
getWealthFactor() {
        return
$this->{tile}->getWealthFactor()+2;
    }
}

class
PollutionDecorator extends TileDecorator {
    function
getWealthFactor() {
        return
$this->{tile}->getWealthFactor()-4;
    }
}

$tile = new Plains();
print
$tile->getWealthFactor(); // 2
// Plains is a component. It simply returns 2

$tile = new DiamondDecorator( new Plains );
print
$tile->getWealthFactor(); // 4
// DiamondDecorator has a reference to a Plains object. It invokes
// getWealthFactor() before adding its own weighting of 2

$tile = new PollutionDecorator( new DiamondDecorator( new Plains() ));
print
$tile->getWealthFactor(); // 0
// PollutionDecorator has a reference to a DiamondDecorator object which
// has its own Tile reference.
?>

File:eg9.php


<?php

class RequestHelper{}

abstract class
ProcessRequest {
    abstract function
process( RequestHelper $req );
}

class
MainProcess extends ProcessRequest {
    function
process( RequestHelper $req ) {
        print
__CLASS__.": doing something useful with request\n";
    }
}

abstract class
DecorateProcess extends ProcessRequest {
    protected
$processrequest;
    function
__construct( ProcessRequest $pr ) {
        
$this->processrequest = $pr;
    }
}

class
LogRequest extends DecorateProcess {
    function
process( RequestHelper $req ) {
        print
__CLASS__.": logging request\n";
        
$this->processrequest->process( $req );
    }
}

class
AuthenticateRequest extends DecorateProcess {
    function
process( RequestHelper $req ) {
        print
__CLASS__.": authenticating request\n";
        
$this->processrequest->process( $req );
    }
}

class
StructureRequest extends DecorateProcess {
    function
process( RequestHelper $req ) {
        print
__CLASS__.": structuring request data\n";
        
$this->processrequest->process( $req );
    }
}

$process = new AuthenticateRequest( new StructureRequest(
                                    new
LogRequest (
                                    new
MainProcess()
                                    )));
$process->process( new RequestHelper() );

File:test.txt


234-ladies_jumper 55 
532-gents_hat 44

File:CommandFactory.php


<?php

class CommandNotFoundException extends Exception {}

class
CommandFactory {
    private static
$dir = 'commands';

    function
getCommand( $action='Default' ) {
        
$class = UCFirst(strtolower($action))."Command";  
        
$file = self::$dir."/$class.php";
        if ( !
file_exists( $file ) ) {
            throw new
CommandNotFoundException( "could not find '$file'" );
        }
        require_once(
$file );
        if ( !
class_exists( $class ) ) {
            throw new
CommandNotFoundException( "no '$class' class located" );
        }
        
$cmd = new $class();
        return
$cmd;
    }
}

$controller = new Controller();
// fake user request
$context = $controller->getContext();
$context->addParam('action', 'login' );
$context->addParam('username', 'bob' );
$context->addParam('pass', 'tiddles' );
$controller->process();

class
Controller {
    private
$context;
    function
__construct() {
        
$this->context = new CommandContext();
    }

    function
getContext() {
        return
$this->context;
    }

    function
process() {
        
$cmd = CommandFactory::getCommand( $this->context->get('action') );
        if ( !
$cmd->execute( $this->context ) ) {
            
// handle failure
        
} else {
            print
"all is well";
            
// success
        
}
    }
}    




// ------------- helper stuff
class User{
    private
$name;
    function
__construct( $name ) {
        
$this->name = $name;
    }
}

class
ReceiverFactory {
    static function
getMessageSystem() {
        return new
MessageSystem();
    }
    static function
getAccessManager() {
        return new
AccessManager();
    }
}

class
MessageSystem {
    function
send( $mail, $msg, $topic ) {
        return
true;
    }

    function
getError() {
        return
"move along now, nothing to see here";
    }
}

class
AccessManager {
    function
login( $user, $pass ) {
        
$ret = new User( $user );
        return
$ret;
    }

    function
getError() {
        return
"move along now, nothing to see here";
    }
}

class
CommandContext {
    private
$params = array();
    private
$error = "";

    function
__construct() {
        
$this->params = $_REQUEST;
    }

    function
addParam( $key, $val ) {
        
$this->params[$key]=$val;
    }

    function
get( $key ) {
        return
$this->params[$key];
    }

    function
setError( $error ) {
        
$this->error = $error;
    }
    function
getError() {
        return
$this->error;
    }
}
/*
$context = new CommandContext();
$context->addParam( "username", "bob" );
$context->addParam( "pass", "tiddles" );
$cmd = new LoginCommand( new AccessManager() );
if ( ! $cmd->execute( $context ) ) {
    print "an error occurred: ".$context->getError();
} else {
    print "successful login\n";
    $user_obj = $context->get( "user" );
}
*/

File:Command.php


<?php

abstract class Command {
    abstract function
execute( CommandContext $context );
}


?>

File:FeedbackCommand.php


<?php
require_once( "Command.php" );

class
FeedbackCommand extends Command {

    function
execute( CommandContext $context ) {
        
$msgSystem = ReceiverFactory::getMessageSystem();
        
$email = $context->get( 'email' );
        
$msg = $context->get( 'pass' );
        
$topic = $context->get( 'topic' );
        
$result = $msgSystem->despatch( $email, $msg, $topic );
        if ( !
$user ) {
            
$this->context->setError( $msgSystem->getError() );
            return
false;
        }
        
$context->addParam( "user", $user );
        return
true;
    }
}


?>

File:LoginCommand.php


<?php
require_once( "Command.php" );

class
LoginCommand extends Command {

    function
execute( CommandContext $context ) {
        
$manager = ReceiverFactory::getAccessManager();
        
$user = $context->get( 'username' );
        
$pass = $context->get( 'pass' );
        
$user = $manager->login( $user, $pass );
        if ( !
$user ) {
            
$this->context->setError( $manager->getError() );
            return
false;
        }
        
$context->addParam( "user", $user );
        return
true;
    }
}
?>

File:eg1.php


<?php
require( "lib/Context.php");
require(
"lib/ML_Interpreter.php");

$context = new Context();
$literal = new LiteralExpression( 'four');
$literal->interpret( $context );
print
$context->lookup( $literal );
?>

File:eg10.php


<?php

interface Observable {
    function
attach( Observer $observer );
    function
detach( Observer $observer );
    function
notify();
}

class
Login implements Observable {
    private
$observers = array();
    const
LOGIN_USER_UNKNOWN = 1;
    const
LOGIN_WRONG_PASS   = 2;
    const
LOGIN_ACCESS       = 3;

    function
attach( Observer $observer ) {
        
$this->observers[] = $observer;
    }

    function
detach( Observer $observer ) {
        
$this->observers = array_diff( $this->observers, array($observer) );
    }

    function
notify() {
        foreach (
$this->observers as $obs ) {
            
$obs->update( $this );
        }
    }

    function
handleLogin( $user, $pass, $ip ) {
        switch (
rand(1,3) ) {
            case
1:
                
$this->setStatus( self::LOGIN_ACCESS, $user, $ip );
                
$ret = true; break;
            case
2:
                
$this->setStatus( self::LOGIN_WRONG_PASS, $user, $ip );
                
$ret = false; break;
            case
3:
                
$this->setStatus( self::LOGIN_USER_UNKNOWN, $user, $ip );
                
$ret = false; break;
        }
        
$this->notify();
        return
$ret;
    }

    private function
setStatus( $status, $user, $ip ) {
        
$this->status = array( $status, $user, $ip );
    }

    function
getStatus() {
        return
$this->status;
    }

}

interface
Observer {
    function
update( Observable $observer );
}

class
SecurityMonitor extends Observer {
    function
update( Observable $observable ) {
        
$status = $observable->getStatus();
        if (
$status[0] == Login::LOGIN_WRONG_PASS ) {
            
// send mail to sysadmin
            
print __CLASS__.":\tsending mail to sysadmin\n";
        }
    }
}

class
GeneralLogger extends Observer {
    function
update( Observable $observable ) {
        
$status = $observable->getStatus();
        
// add login data to log
        
print __CLASS__.":\tadd login data to log\n";
    }
}

class
PartnershipTool extends Observer {
    function
update( Observable $observable ) {
        
$status = $observable->getStatus();
        
// check $ip address
        // set cookie if it matches a list
        
print __CLASS__.":\tset cookie if it matches a list\n";
    }
}

$login = new Login();
$login->attach( new SecurityMonitor() );
$login->attach( new GeneralLogger() );
$login->attach($pt = new PartnershipTool() );
$login->detach( $pt );
for (
$x=0; $x<1; $x++ ) {
    
$login->handleLogin( "bob","mypass", '158.152.55.35' );
    print
"\n";
}

?>

File:eg11.php


<?php

class UnitException extends Exception {}

abstract class
Unit {
    function
getComposite() {
        return
null;
    }

    abstract function
bombardStrength();

    function
textDump( $num=0 ) {
        
$ret = "";
        
$pad = 4*$num;
        
$ret .= sprintf( "%{$pad}s", "" );
        
$ret .= get_class($this).": ";
        
$ret .= "bombard: ".$this->bombardStrength()."\n";
        return
$ret;
    }

    function
unitCount() {
        return
1;
    }
}

class
Archer extends Unit {
    function
bombardStrength() {
        return
4;
    }
    function
unitCount() {
        return
1;
    }
}

class
Cavalry extends Unit {
    function
bombardStrength() {
        return
2;
    }
}

class
LaserCanonUnit extends Unit {
    function
bombardStrength() {
        return
44;
    }
}

abstract class
CompositeUnit extends Unit {
    private
$units = array();

    function
getComposite() {
        return
$this;
    }

    function
units() {
        return
$this->units;
    }

    function
removeUnit( Unit $unit ) {
        
$units = array();
        foreach (
$this->units as $thisunit ) {
            if (
$unit !== $thisunit ) {
                
$units[] = $thisunit;
            }
        }
        
$this->units = $units;
    }

    function
unitCount() {
        
$ret = 0;
        foreach (
$this->units as $unit ) {
            
$ret += $unit->unitCount();
        }
        return
$ret;
    }

    function
textDump( $num=0 ) {
        
$ret = "";
        
$pad = 4*$num;
        
$ret .= sprintf( "%{$pad}s", "" );
        
$ret .= get_class($this).": ";
        
$ret .= "bombard: ".$this->bombardStrength()."\n";
        foreach (
$this->units as $unit ) {
            
$ret .= $unit->textDump( $num + 1 );
        }
        return
$ret;
    }

    function
addUnit( Unit $unit ) {
        foreach (
$this->units as $thisunit ) {
            if (
$unit === $thisunit ) {
                return;
            }
        }
        
$this->units[] = $unit;
    }
}

class
TroopCarrier extends CompositeUnit {

    function
addUnit( Unit $unit ) {
        if (
$unit instanceof Cavalry ) {
            throw new
UnitException("Can't get a horse on the vehicle");
        }
        
parent::addUnit( $unit );
    }

    function
bombardStrength() {
        return
0;
    }
}

class
Army extends CompositeUnit {

    function
bombardStrength() {
        
$ret = 0;
        foreach(
$this->units() as $unit ) {
            
$ret += $unit->bombardStrength();
        }
        return
$ret;
    }
}

$main_army = new Army();
$main_army->addUnit( new Archer() );
$main_army->addUnit( new LaserCanonUnit() );
$sub_army=new Army();
$sub_army->addUnit( new Cavalry() );
$main_army->addUnit( $sub_army );
$main_army->addUnit( new Cavalry() );
print
$main_army->textDump();

File:eg12.php


<?php

class UnitException extends Exception {}

class
TextDumpArmyVisitor extends ArmyVisitor {
    private
$text="";

    function
visit( Unit $node ) {
        
$ret = "";
        
$pad = 4*$node->getDepth();
        
$ret .= sprintf( "%{$pad}s", "" );
        
$ret .= get_class($node).": ";
        
$ret .= "bombard: ".$node->bombardStrength()."\n";
        
$this->text .= $ret;
    }
    function
getText() {
        return
$this->text;
    }
}

class
TaxCollectionVisitor extends ArmyVisitor {
    private
$due=0;
    private
$report="";

    function
visit( Unit $node ) {
        
$this->levy( $node, 1 );
    }

    function
visitArcher( Archer $node ) {
        
$this->levy( $node, 2 );
    }

    function
visitCavalry( Cavalry $node ) {
        
$this->levy( $node, 3 );
    }

    function
visitTroopCarrierUnit( TroopCarrierUnit $node ) {
        
$this->levy( $node, 5 );
    }

    private function
levy( Unit $unit, $amount ) {
        
$this->report .= "Tax levied for ".get_class( $unit );
        
$this->report .= ": $amount\n";
        
$this->due += $amount;
    }

    function
getReport() {
        return
$this->report;
    }

    function
getTax() {
        return
$this->due;
    }
}

abstract class
ArmyVisitor  {
    abstract function
visit( Unit $node );

    function
visitArcher( Archer $node ) {
        
$this->visit( $node );
    }
    function
visitCavalry( Cavalry $node ) {
        
$this->visit( $node );
    }

    function
visitLaserCanonUnit( LaserCanonUnit $node ) {
        
$this->visit( $node );
    }

    function
visitTroopCarrierUnit( TroopCarrierUnit $node ) {
        
$this->visit( $node );
    }

    function
visitArmy( Army $node ) {
        
$this->visit( $node );
    }
}

abstract class
Unit {
    protected
$depth = 0;

    function
getComposite() {
        return
null;
    }
    
    protected function
setDepth( $depth ) {
        
$this->depth=$depth;
    }
    function
getDepth() {
        return
$this->depth;
    }

    abstract function
bombardStrength();

    function
accept( ArmyVisitor $visitor ) {
        
$method = "visit".get_class( $this );
        
$visitor->$method( $this );
    }
}

class
Archer extends Unit {
    function
bombardStrength() {
        return
4;
    }

}

class
Cavalry extends Unit {
    function
bombardStrength() {
        return
2;
    }
}

class
LaserCanonUnit extends Unit {
    function
bombardStrength() {
        return
44;
    }
}

abstract class
CompositeUnit extends Unit {
    private
$units = array();

    function
getComposite() {
        return
$this;
    }

    function
units() {
        return
$this->units;
    }

    function
removeUnit( Unit $unit ) {
        
$units = array();
        foreach (
$this->units as $thisunit ) {
            if (
$unit !== $thisunit ) {
                
$units[] = $thisunit;
            }
        }
        
$this->units = $units;
    }
/*
    function accept( ArmyVisitor $visitor ) {
        $method = "visit".get_class( $this );
        $visitor->$method( $this );
        foreach ( $this->units as $thisunit ) {
            $thisunit->accept( $visitor );
        }
    }
*/

    
function accept( ArmyVisitor $visitor ) {
        
parent::accept( $visitor );
        foreach (
$this->units as $thisunit ) {
            
$thisunit->accept( $visitor );
        }
    }

    function
addUnit( Unit $unit ) {
        foreach (
$this->units as $thisunit ) {
            if (
$unit === $thisunit ) {
                return;
            }
        }
        
$unit->setDepth($this->depth+1);
        
$this->units[] = $unit;
    }
}

class
TroopCarrier extends CompositeUnit {

    function
addUnit( Unit $unit ) {
        if (
$unit instanceof Cavalry ) {
            throw new
UnitException("Can't get a horse on the vehicle");
        }
        
parent::addUnit( $unit );
    }

    function
bombardStrength() {
        return
0;
    }
}

class
Army extends CompositeUnit {

    function
bombardStrength() {
        
$ret = 0;
        foreach(
$this->units() as $unit ) {
            
$ret += $unit->bombardStrength();
        }
        return
$ret;
    }
}

$main_army = new Army();
$main_army->addUnit( new Archer() );
$main_army->addUnit( new LaserCanonUnit() );
$main_army->addUnit( new Cavalry() );

$textdump = new TextDumpArmyVisitor();
$main_army->accept( $textdump  );
print
$textdump->getText();
$taxcollector = new TaxCollectionVisitor();
$main_army->accept( $taxcollector );
print
$taxcollector->getReport();
print
"TOTAL: ";
print
$taxcollector->getTax()."\n";

File:eg13.a.php


<?php
class User{
    private
$name;
    function
__construct( $name ) {
        
$this->name = $name;
    }
}

class
MessageSystem {
    function
send( $mail, $msg, $topic ) {
        return
true;
    }

    function
getError() {
        return
"move along now, nothing to see here";
    }
}

class
AccessManager {
    function
login( $user, $pass ) {
        
$ret = new User( $user );
        return
$ret;
    }

    function
getError() {
        return
"move along now, nothing to see here";
    }
}

class
CommandContext {
    private
$params = array();
    private
$error = "";

    function
addParam( $key, $val ) {
        
$this->params[$key]=$val;
    }

    function
get( $key ) {
        return
$this->params[$key];
    }

    function
setError( $error ) {
        
$this->error = $error;
    }
    function
getError() {
        return
$this->error;
    }
}

abstract class
Command {
    abstract function
execute();
}

class
FeedbackCommand {
    private
$msgSystem;
    function
__construct( MessageSystem $msgSystem ) {
        
$this->msgSystem = $msgSystem;
    }

    function
execute( CommandContext $context ) {
        
$email = $context->get( 'email' );
        
$msg = $context->get( 'pass' );
        
$topic = $context->get( 'topic' );
        
$result = $this->msgSystem->despatch( $email, $msg, $topic );
        if ( !
$user ) {
            
$this->context->setError( $this->msgSystem->getError() );
            return
false;
        }
        
$context->addParam( "user", $user );
        return
true;
    }
}

class
LoginCommand {
    private
$manager;
    function
__construct( AccessManager $mgr ) {
        
$this->manager = $mgr;
    }

    function
execute( CommandContext $context ) {
        
$user = $context->get( 'username' );
        
$pass = $context->get( 'pass' );
        
$user = $this->manager->login( $user, $pass );
        if ( !
$user ) {
            
$this->context->setError( $this->manager->getError() );
            return
false;
        }
        
$context->addParam( "user", $user );
        return
true;
    }
}


$context = new CommandContext();
$context->addParam( "username", "bob" );
$context->addParam( "pass", "tiddles" );
$cmd = new LoginCommand( new AccessManager() );
if ( !
$cmd->execute( $context ) ) {
    print
"an error occurred: ".$context->getError();
} else {
    print
"successful login\n";
    
$user_obj = $context->get( "user" );
}

File:eg13.php


<?php
class User{
    private
$name;
    function
__construct( $name ) {
        
$this->name = $name;
    }
}

class
ReceiverFactory {
    static function
getMessageSystem() {
        return new
MessageSystem();
    }
    static function
getAccessManager() {
        return new
AccessManager();
    }
}

class
MessageSystem {
    function
send( $mail, $msg, $topic ) {
        return
true;
    }

    function
getError() {
        return
"move along now, nothing to see here";
    }
}

class
AccessManager {
    function
login( $user, $pass ) {
        
$ret = new User( $user );
        return
$ret;
    }

    function
getError() {
        return
"move along now, nothing to see here";
    }
}

class
CommandContext {
    private
$params = array();
    private
$error = "";

    function
__construct() {
        
$this->params = $_REQUEST;
    }

    function
addParam( $key, $val ) {
        
$this->params[$key]=$val;
    }

    function
get( $key ) {
        return
$this->params[$key];
    }

    function
setError( $error ) {
        
$this->error = $error;
    }
    function
getError() {
        return
$this->error;
    }
}

abstract class
Command {
    abstract function
execute( CommandContext $context );
}

class
FeedbackCommand extends Command {

    function
execute( CommandContext $context ) {
        
$msgSystem = ReceiverFactory::getMessageSystem();
        
$email = $context->get( 'email' );
        
$msg = $context->get( 'pass' );
        
$topic = $context->get( 'topic' );
        
$result = $msgSystem->despatch( $email, $msg, $topic );
        if ( !
$user ) {
            
$this->context->setError( $msgSystem->getError() );
            return
false;
        }
        
$context->addParam( "user", $user );
        return
true;
    }
}


class
LoginCommand extends Command {

    function
execute( CommandContext $context ) {
        
$manager = ReceiverFactory::getAccessManager();
        
$user = $context->get( 'username' );
        
$pass = $context->get( 'pass' );
        
$user = $manager->login( $user, $pass );
        if ( !
$user ) {
            
$this->context->setError( $manager->getError() );
            return
false;
        }
        
$context->addParam( "user", $user );
        return
true;
    }
}


$context = new CommandContext();
$context->addParam( "username", "bob" );
$context->addParam( "pass", "tiddles" );
$cmd = new LoginCommand( new AccessManager() );
if ( !
$cmd->execute( $context ) ) {
    print
"an error occurred: ".$context->getError();
} else {
    print
"successful login\n";
    
$user_obj = $context->get( "user" );
}

File:eg2.php


<?php

class PrintMe{ }
$test = new PrintMe();
print
$test;
// output: Object id #1

File:eg3.php


<?php
require( "lib/Context.php");
require(
"lib/ML_Interpreter.php");


$context = new Context();
$myvar = new VariableExpression( 'input', 'four');
$myvar->interpret( $context );
print
$context->lookup( $myvar );
// output: four

$newvar = new VariableExpression( 'input' );
$newvar->interpret( $context );
print
$context->lookup( $newvar );
// output: four

$myvar->setValue("five");
$myvar->interpret( $context );
print
$context->lookup( $myvar );
// output: five
print $context->lookup( $newvar );
// output: five

?>

File:eg4.php


<?php
require_once "lib/ML_Interpreter.php";
require_once
"lib/Context.php";

$context = new Context();
$input = new VariableExpression( 'input' );
$statement = new BooleanOrExpression(
    new
EqualsExpression( $input, new LiteralExpression( 'four' ) ),
    new
EqualsExpression( $input, new LiteralExpression( '4' ) )
);

foreach ( array(
"four", "4", "52" ) as $val ) {
    
$input->setValue( $val );
    print
"$val:\n";
    
$statement->interpret( $context );
    if (
$context->lookup( $statement ) ) {
        print
"top marks\n\n";
    } else {
        print
"dunce hat on\n\n";
    }
}

?>

File:eg7.php


<?php
require_once( "parse/Parser.php" );
require_once(
"parse/MarkLogic.php" );

abstract class
Question {
    protected
$prompt;
    protected
$marker;

    function
__construct( $prompt, Marker $marker ) {
        
$this->prompt=$prompt;
        
$this->marker=$marker;
    }

    function
mark( $response ) {
        return
$this->marker->mark( $response );
    }
}

class
TextQuestion extends Question {
    
// do text question specific things
}

class
AVQuestion extends Question {
    
// do audiovisual question specific things
}

abstract class
Marker {
    protected
$test;

    function
__construct( $test ) {
        
$this->test = $test;
    }

    abstract function
mark( $response );
}

class
MarkLogicMarker extends Marker {
    private
$engine;
    function
__construct( $test ) {
        
parent::__construct( $test );
        
$this->engine = new MarkParse( $test );
    }

    function
mark( $response ) {
        return
$this->engine->evaluate( $response );
    }
}

class
MatchMarker extends Marker {
    function
mark( $response ) {
        return (
$this->test == $response );
    }
}

class
RegexpMarker extends Marker {
    function
mark( $response ) {
        return (
preg_match( "$this->test", $response ) );
    }
}

$markers = array(   new RegexpMarker( "/f.ve/" ),
                    new
MatchMarker( "five" ),
                    new
MarkLogicMarker( '$input equals "five"' )
        );

foreach (
$markers as $marker ) {
    print
get_class( $marker )."\n";
    
$question = new TextQuestion( "how many beans make five", $marker );
    foreach ( array(
"five", "four" ) as $response ) {
        print
"\tresponse: $response: ";
        if (
$question->mark( $response ) ) {
            print
"well done\n";
        } else {
            print
"never mind\n";
        }
    }
}

File:eg8.php


<?php

class Login {
    const
LOGIN_USER_UNKNOWN = 1;
    const
LOGIN_WRONG_PASS   = 2;
    const
LOGIN_ACCESS       = 3;

    function
handleLogin( $user, $pass, $ip ) {
        switch (
rand(1,3) ) {
            case
1:
                
$this->setStatus( self::LOGIN_ACCESS );
                return
true;
            case
2:
                
$this->setStatus( self::LOGIN_WRONG_PASS );
                return
false;        
            case
3:
                
$this->setStatus( self::LOGIN_USER_UNKNOWN );
                return
false;        
        }
    }

    private function
setStatus( $status ) {
        
$this->status = $status;
    }

    function
loginStatus() {
        return
$this->status;
    }

}

$login = new Login();
$login->handleLogin( "bob","mypass", '158.152.55.35' );
print
$login->loginStatus();
?>

File:eg9.php


<?php

class Login {
    const
LOGIN_USER_UNKNOWN = 1;
    const
LOGIN_WRONG_PASS   = 2;
    const
LOGIN_ACCESS       = 3;

    function
handleLogin( $user, $pass, $ip ) {
        switch (
rand(1,3) ) {
            case
1:
                
$this->setStatus( self::LOGIN_ACCESS );
                
$this->cookiePartners( $user, $pass, $ip );
                
$ret = true; break;
            case
2:
                
$this->setStatus( self::LOGIN_WRONG_PASS );
                
$ret = false; break;
            case
3:
                
$this->setStatus( self::LOGIN_USER_UNKNOWN );
                
$ret = false; break;
        }
        if ( !
$ret ) {
            
Notifier::mailWarning( $user, $ip,$this->loginStatus()  );
        }
        
Logger::logIP( $user, $ip, $this->loginStatus() );
        return
$ret;
    }

    function
cookiePartners( $user, $Ip ) {
        ;
    }

    private function
setStatus( $status ) {
        
$this->status = $status;
    }

    function
loginStatus() {
        return
$this->status;
    }

}

class
Notifier {
    function
mailWarning( $user, $ip, $status ) {
        
// mail sysadmin
    
}
}

class
Logger {
    function
logIP( $user, $ip, $status ) {
        
// log info
    
}
}

$login = new Login();
$login->handleLogin( "bob","mypass", '158.152.55.35' );
print
$login->loginStatus();
?>

File:eval.php


<?php

$form_input
= "print file_get_contents('/etc/passwd');";
eval(
$form_input );

?>

File:Context.php


<?php

class Context {
    private
$expressionstore = array();
    function
replace( Expression $exp, $value ) {
        
$this->expressionstore[$exp->getKey()] = $value;
    }

    function
lookup( Expression $exp ) {
        return
$this->expressionstore[$exp->getKey()];
    }
}

?>

File:ML_Interpreter.php


<?php

abstract class Expression {
    abstract function
interpret( Context $context );

    function
getKey() {
        return (string)
$this;
    }
}

class
LiteralExpression extends Expression {
    private
$value;

    function
__construct( $value ) {
        
$this->value = $value;
    }

    function
interpret( Context $context ) {
        
$context->replace( $this, $this->value );
    }
}

class
VariableExpression extends Expression {
    private
$name;
    private
$val;

    function
__construct( $name, $val=null ) {
        
$this->name = $name;
        
$this->val = $val;
    }

    function
interpret( Context $context ) {
        if ( !
is_null( $this->val ) ) {
            
$context->replace( $this, $this->val );
            
$this->val = null;
        }
    }

    function
setValue( $value ) {
        
$this->val = $value;
    }

    function
getKey() {
        return
$this->name;
    }
}

abstract class
OperatorExpression extends Expression {
    protected
$l_op;
    protected
$r_op;

    function
__construct( Expression $l_op, Expression $r_op ) {
        
$this->l_op = $l_op;
        
$this->r_op = $r_op;
    }

    function
interpret( Context $context ) {
        
$this->l_op->interpret( $context );
        
$this->r_op->interpret( $context );
        
$result_l = $context->lookup( $this->l_op );
        
$result_r = $context->lookup( $this->r_op  );
        
$this->doOperation( $context, $result_l, $result_r );
    }

    protected abstract function
doOperation( Context $context,
                                             
$result_l,
                                             
$result_r );
}


class
EqualsExpression extends OperatorExpression {
    protected function
doOperation( Context $context,
                                        
$result_l, $result_r ) {
            
$context->replace( $this, $result_l == $result_r );
    }
}

class
BooleanOrExpression extends OperatorExpression {
    protected function
doOperation( Context $context,
                                        
$result_l, $result_r ) {
        
$context->replace( $this, $result_l || $result_r );
    }
}

class
BooleanAndExpression extends OperatorExpression {
    protected function
doOperation( Context $context,
                                        
$result_l, $result_r ) {
        
$context->replace( $this, $result_l && $result_r );
    }
}

?>

File:MarkLogic.php


<?php
require_once( "parse/Parser.php" );
require_once(
"lib/Context.php" );

class
StringLiteralHandler implements Handler {
    function
handleMatch( Parser $parser, Scanner $scanner ) {
        
$value = $scanner->popResult();
        
$scanner->pushResult( new LiteralExpression( $value ) );
    }
}

class
EqualsHandler implements Handler {
    function
handleMatch( Parser $parser, Scanner $scanner ) {
        
$comp1 = $scanner->popResult();
        
$comp2 = $scanner->popResult();
        
$scanner->pushResult( new EqualsExpression( $comp1, $comp2 ) );
    }
}

class
VariableHandler implements Handler {
    function
handleMatch( Parser $parser, Scanner $scanner ) {
        
$varname = $scanner->popResult();
        
$scanner->pushResult( new VariableExpression( $varname ) );
    }
}

class
BooleanOrHandler implements Handler {
    function
handleMatch( Parser $parser, Scanner $scanner ) {
        
$comp1 = $scanner->popResult();
        
$comp2 = $scanner->popResult();
        
$scanner->pushResult( new BooleanOrExpression( $comp1, $comp2 ) );
    }
}

class
BooleanAndHandler implements Handler {
    function
handleMatch( Parser $parser, Scanner $scanner ) {
        
$comp1 = $scanner->popResult();
        
$comp2 = $scanner->popResult();
        
$scanner->pushResult( new BooleanAndExpression( $comp1, $comp2 ) );
    }
}

class
MarkParse {
    private
$expression;
    private
$operand;
    private
$interpreter;

    function
__construct( $statement ) {
        
$this->compile( $statement );
    }

    function
evaluate( $input ) {
        
$context = new Context();
        
$prefab = new VariableExpression('input', $input );
        
// add the input variable to Context
        
$prefab->interpret( $context );

        
$this->interpreter->interpret( $context );
        
$result = $context->lookup( $this->interpreter );
        return
$result;
    }

    function
compile( $statement ) {
        
// build parse tree
        
$scanner = new Scanner( $statement );
        
$statement = $this->expression();
        
$scanresult = $statement->scan( $scanner );
         
        if ( !
$scanresult || $scanner->token_type() != Scanner::EOF ) {
            
$msg  = "";
            
$msg .= " line: {$scanner->line_no()} ";
            
$msg .= " char: {$scanner->char_no()}";
            
$msg .= " token: {$scanner->token()}\n";
            throw new
Exception( $msg );
        }

        
$this->interpreter = $scanner->popResult();
    }

    function
expression() {
        if ( ! isset(
$this->expression ) ) {
            
$this->expression = new SequenceParse();
            
$this->expression->add( $this->operand() );
            
$bools = new RepetitionParse();
            
$whichbool = new AlternationParse();
            
$whichbool->add( $this->orExpr() );
            
$whichbool->add( $this->andExpr() );
            
$bools->add( $whichbool );
            
$this->expression->add( $bools );
        }
        return
$this->expression;
    }

    function
orExpr() {
        
$or = new SequenceParse( );
        
$or->add( new WordParse('or') )->discard();
        
$or->add( $this->operand() );
        
$or->setHandler( new BooleanOrHandler() );
        return
$or;
    }

    function
andExpr() {
        
$and = new SequenceParse();
        
$and->add( new WordParse('and') )->discard();
        
$and->add( $this->operand() );
        
$and->setHandler( new BooleanAndHandler() );
        return
$and;
    }

    function
operand() {
        if ( ! isset(
$this->operand ) ) {
            
$this->operand = new SequenceParse( );
            
$comp = new AlternationParse( );
            
$exp = new SequenceParse( );
            
$exp->add( new CharacterParse( '(' ))->discard();
            
$exp->add( $this->expression() );
            
$exp->add( new CharacterParse( ')' ))->discard();
            
$comp->add( $exp );
            
$comp->add( new StringLiteralParse() )
                ->
setHandler( new StringLiteralHandler() );
            
$comp->add( $this->variable() );
            
$this->operand->add( $comp );
            
$this->operand->add( new RepetitionParse() )->add($this->eqExpr());
        }
        return
$this->operand;
    }

    function
eqExpr() {
        
$equals = new SequenceParse();
        
$equals->add( new WordParse('equals') )->discard();
        
$equals->add( $this->operand() );
        
$equals->setHandler( new EqualsHandler() );
        return
$equals;
    }

    function
variable() {
        
$variable = new SequenceParse();
        
$variable->add( new CharacterParse( '$' ))->discard();
        
$variable->add( new WordParse());
        
$variable->setHandler( new VariableHandler() );
        return
$variable;
    }
}
?>

File:Parser.php


<?php
require_once('parse/Scanner.php');
require_once(
'lib/ML_Interpreter.php');

interface
Handler {
    abstract function
handleMatch( Parser $parser, Scanner $scanner );    
}

abstract class
Parser {
    protected
$debug = false;
    private   
$discard = false;
    protected
$name;

    function
__construct( $name=null ) {
        if (
is_null( $name ) ) {
            
$this->name = (string)$this;
        } else {
            
$this->name = $name;
        }
    }

    function
setHandler( Handler $handler ) {
        
$this->handler = $handler;
    }

    function
invokeHandler( Scanner $scanner ) {
        if ( ! empty(
$this->handler ) ) {
            if (
$this->debug ) {
                
$this->report( "calling handler: ".get_class( $this->handler ) );
            }
            
$this->handler->handleMatch( $this, $scanner );
        }
    }

    function
report( $msg ) {
        print
"<{$this->name}> ".get_class( $this ).": $msg\n";
    }

    function
push( Scanner $scanner ) {
        if (
$this->debug ) {
            
$this->report("pushing {$scanner->token()}");
        }
        
$scanner->pushResult( $scanner->token() );
    }

    function
scan( Scanner $scanner ) {
        
$ret = $this->doScan( $scanner );
        if (
$ret && ! $this->discard && $this->term() ) {
            
$this->push( $scanner );
        }
        if (
$ret ) {
            
$this->invokeHandler( $scanner );
        }
        if (
$this->debug ) {
            
$this->report("::scan returning $ret");
        }
        if (
$this->term() && $ret ) {
            
$scanner->nextToken();
            
$scanner->eatWhiteSpace();
        }

        return
$ret;
    }

    function
discard() {
        
$this->discard = true;
    }

    abstract function
trigger( Scanner $scanner );

    abstract protected function
doScan( Scanner $scan );

    function
term() {
        return
true;
    }
}

abstract class
CollectionParse extends Parser {
    protected
$parsers = array();
    function
add( Parser $p ) {
        if (
is_null( $p ) ) {
            throw new
Exception( "argument is null" );
        }
        
$this->parsers[]= $p;
        return
$p;
    }

    function
term() {
        return
false;
    }
}

class
RepetitionParse extends CollectionParse {
    function
trigger( Scanner $scanner ) {
        return
true;
    }

    protected function
doScan( Scanner $scanner ) {
        if ( empty(
$this->parsers ) ) {
            return
true;
        }
        
$parser = $this->parsers[0];

        if ( !
$parser->trigger( $scanner ) ) {
            
// no initial match is fine
            
return true;
        }
        if (
$parser->scan( $scanner ) ) {
            
// all is well. go again
            
$this->scan( $scanner );
        } else {
            
// we got a partial match but failed
            
return false;
        }
        return
true;
    }
}

class
AlternationParse extends CollectionParse {
    function
trigger( Scanner $scanner ) {
        foreach (
$this->parsers as $parser ) {
            if (
$parser->trigger( $scanner ) ) {
                return
true;
            }
        }
        return
false;
    }

    protected function
doScan( Scanner $scanner ) {
        
$type = $scanner->token_type();
        foreach (
$this->parsers as $parser ) {
            
$s_copy = clone $scanner;
            if (
$type == $parser->trigger( $s_copy ) &&
                 
$parser->scan( $s_copy ) ) {
                 
$scanner->updateToMatch($s_copy);
                 return
true;
            }
        }
        return
false;
    }
}

class
SequenceParse extends CollectionParse {

    function
trigger( Scanner $scanner ) {
        if ( empty(
$this->parsers ) ) {
            return
false;
        }
        return
$this->parsers[0]->trigger( $scanner );
    }

    protected function
doScan( Scanner $scanner ) {
        foreach(
$this->parsers as $parser ) {
            if ( ! (
$parser->trigger( $scanner ) &&
                    
$scan=$parser->scan( $scanner )) ) {
                return
false;
            }
        }
        return
true;
    }
}

class
CharacterParse extends Parser {
    private
$char;

    function
__construct( $char, $name=null ) {
        
parent::__construct( $name );
        
$this->char = $char;
    }

    function
trigger( Scanner $scanner ) {
        return (
$scanner->token() == $this->char );
    }

    protected function
doScan( Scanner $scanner ) {
        return (
$this->trigger( $scanner ) );
    }
}

class
StringLiteralParse extends Parser {
    function
trigger( Scanner $scanner ) {
        return (
$scanner->token_type() == Scanner::APOS ||
                 
$scanner->token_type() == Scanner::QUOTE );
    }

    function
push( Scanner $scanner ) {
        if (
$this->debug ) {
            
$this->report("pushing {$this->string}");
        }
        
$scanner->pushResult( $this->string );
    }

    protected function
doScan( Scanner $scanner ) {
        
$quotechar = $scanner->token_type();
        
$this->string = "";
        while (
$token = $scanner->nextToken() ) {
            if (
$token == $quotechar ) {
                return
true;
            }
            
$this->string .= $scanner->token();
        }
        return
false;
    }
}

class
WordParse extends Parser {
    function
WordParse( $word=null, $name=null ) {
        
parent::__construct( $name );
        
$this->word = $word;
    }

    function
trigger( Scanner $scanner ) {
        if (
$scanner->token_type() != Scanner::WORD ) {
            return
false;
        }
        if (
is_null( $this->word ) ) {
            return
true;
        }
        return (
$this->word == $scanner->token() );
    }

    protected function
doScan( Scanner $scanner ) {
        
$ret = ( $this->trigger( $scanner ) );
        return
$ret;
    }
}
?>

File:Scanner.php


<?php

class Scanner {
    const
WORD         = 1;
    const
QUOTE        = 2;
    const
APOS         = 3;
    const
WHITESPACE   = 6;
    const
EOL          = 8;
    const
CHAR         = 99;
    const
EOF          = 0;

    protected
$in;
    protected
$line_no = 1;
    protected
$char_no = 0;
    protected
$token;
    protected
$token_type;
    protected
$regexps;
    public
$resultstack = array();

    function
__construct( $in ) {
        
$this->in = $in;
        
$this->setRegexps();
        
$this->nextToken();
        
$this->eatWhiteSpace();
    }

    
// push a result on to the result stack
    
function pushResult( $mixed ) {
        
array_push( $this->resultstack, $mixed );
    }

    
// remove result from result stack
    
function popResult( ) {
        return
array_pop( $this->resultstack );
    }

    
// number of items on the result stack
    
function resultCount() {
        return
count( $this->resultstack );
    }

    
// return the last item on the result stack but
    // don't remove
    
function peekResult( ) {
        if ( empty(
$this->resultstack ) ) {
            throw new
Exception( "empty resultstack" );
        }
        return
$this->resultstack[count( $this->resultstack ) -1 ];
    }

    
// set up regular expressions for tokens
    
private function setRegexps() {
        
$this->regexps = array(
                      
self::WHITESPACE => '[ \t]',
                      
self::EOL => '\n',
                      
self::WORD => '[a-zA-Z0-9_-]+\b',
                      
self::QUOTE => '"',
                      
self::APOS => "'",
        );

        
$this->typestrings = array(
                      
self::WHITESPACE => 'WHITESPACE',
                      
self::EOL => 'EOL',
                      
self::WORD => 'WORD',
                      
self::QUOTE => 'QUOTE',
                      
self::APOS => "APOS",
                      
self::CHAR  => 'CHAR',
                      
self::EOF => 'EOF'
        
);
    }

    
// skip through any white space
    
function eatWhiteSpace( ) {
        
$ret = 0;
        if (
$this->token_type != self::WHITESPACE &&
             
$this->token_type != self::EOL ) {
            return
$ret;
        }
        while (
$this->nextToken() == self::WHITESPACE ||
                
$this->token_type == self::EOL ) {
            
$ret++;
        }
        return
$ret;
    }

    
// given a constant number, return a
    // string version
    // eg 1 => 'WORD',
    
function getTypeString( $int=-1 ) {
        if (
$int<0 ) {
            
$int=$this->token_type();
        }
        return
$this->typestrings[$int];
    }

    
// the type of the current token
    
function token_type() {
        return
$this->token_type;
    }

    
// the text being scanned
    // gets shorter as the tokens are
    // pulled from it
    
function input() {
        return
$this->in;
    }

    
// the current token
    
function token() {
        return
$this->token;
    }

    
// the current line number (great for error messages)
    
function line_no() {
        return
$this->line_no;
    }

    
// current char_no
    
function char_no() {
        return
$this->char_no;
    }

    
// attempt to pull another token from
    // the input. If no token match is found then
    // it's a character token
    
function nextToken() {
        if ( !
strlen( $this->in ) ) {
            return (
$this->token_type = self::EOF );
        }

        
$ret = 0;
        foreach (
$this->regexps as $type=>$regex ) {        
            if (
$ret = $this->testToken( $regex, $type ) ) {
                if (
$ret == self::EOL ) {
                    
$this->line_no++;
                    
$this->char_no = 0;
                } else {
                    
$this->char_no += strlen( $this->token() );
                }
                return
$ret;
            }
        }
        
$this->token = substr( $this->in, 0, 1 );
        
$this->in    = substr( $this->in, 1 );
        
$this->char_no += 1;
        return (
$this->token_type = self::CHAR );
    }

    
// given a regular expression check for a match
    
private function testToken( $regex, $type ) {
        
$matches = array();
        if (
preg_match( "/^($regex)(.*)/s", $this->in, $matches ) ) {
            
$this->token = $matches[1];
            
$this->in    = $matches[2];
            return (
$this->token_type  = $type );
        }
        return
0;
    }

    
// given another scanner, make this one a clone
    
function updateToMatch( Scanner $other ) {
        
$this->in = $other->in;
        
$this->token = $other->token;
        
$this->token_type = $other->token_type;
        
$this->char_no = $other->char_no;
        
$this->line_no = $other->line_no;
        
$this->resultstack = $other->resultstack;
    }
}
?>

File:applicationRegistry.txt


a:2:{s:3:"dsn";s:22:"sqlite://./data/woo.db";s:4:"cmap";O:28:"woo_controller_ControllerMap":3:{s:37:"woo_controller_ControllerMapviewMap";a:5:{s:7:"default";a:3:{i:0;s:4:"main";i:1;s:4:"main";i:2;s:5:"error";}s:10:"ListVenues";a:1:{i:0;s:10:"listvenues";}s:13:"QuickAddVenue";a:1:{i:0;s:8:"quickadd";}s:8:"AddVenue";a:1:{i:0;s:8:"addvenue";}s:8:"AddSpace";a:1:{i:0;s:8:"addspace";}}s:40:"woo_controller_ControllerMapforwardMap";a:2:{s:8:"AddVenue";a:1:{i:1;s:8:"AddSpace";}s:8:"AddSpace";a:1:{i:1;s:10:"ListVenues";}}s:42:"woo_controller_ControllerMapclassrootMap";a:4:{s:10:"ListVenues";s:0:"";s:13:"QuickAddVenue";s:8:"AddVenue";s:8:"AddVenue";s:0:"";s:8:"AddSpace";s:0:"";}}}

File:woo.db


** This file contains an SQLite 2.1 database **(uãÚVPT€è(€
 &((index(venue autoindex 1)venue3O€
Otablevenuevenue4CREATE TABLE venue ( id INT PRIMARY KEY, name TEXT )Œ(€
 &((index(space autoindex 1)space5°Z€
Ztablespacespace6CREATE TABLE space ( id INT PRIMARY KEY, venue INT, name TEXT ):(€
 &((index(event autoindex 1)event7Tt€
ttableeventevent8CREATE TABLE event ( id INT PRIMARY KEY, space INT, start long, duration int, name text )ðøøøøøø

File:woo_options.xml


<woo-options>
    <dsn>sqlite://./data/woo.db</dsn>

<control>
    <view>main</view>
    <view status="CMD_OK">main</view>
    <view status="CMD_ERROR">error</view>

    <command name="ListVenues">
        <view>listvenues</view>
    </command>

    <command name="QuickAddVenue">
        <classroot name="AddVenue" />
        <view>quickadd</view>
    </command>

    <command name="AddVenue">
        <view>addvenue</view>
        <status value="CMD_OK">
          <forward>AddSpace</forward>
          <!--<forward>AddVenue</forward> -->
        </status>
    </command>

    <command name="AddSpace">
        <view>addspace</view>
        <status value="CMD_OK">
            <forward>ListVenues</forward>
        </status>
    </command>
</control>
</woo-options>

File:db_setup.php


<?php
/*
set up script for transaction script example
*/

require_once( "DB.php");

$db = DB::Connect( "sqlite://./data/woo.db" );
#@$db->query( "DROP TABLE venue" );
$db->query( "CREATE TABLE venue ( id INT PRIMARY KEY, name TEXT )" );

$db->query( "DROP TABLE space" );
$db->query( "CREATE TABLE space ( id INT PRIMARY KEY, venue INT, name TEXT )" );

@
$db->query( "DROP TABLE event" );
$db->query( "CREATE TABLE event ( id INT PRIMARY KEY, space INT, start long, duration int, name text )" );

#$result = $db->query( "INSERT into venue (id, name) values(4, 'bob')" );
?>

File:index.php


<?php
#require_once( "woo/mapper.php" );
#require_once( "woo/domain.php" );
require_once( "woo/controller/Controller.php" );
woo_controller_Controller::run();

?>

File:AddVenue.php


<?php
require_once("woo/mapper/VenueMapper.php");
require_once(
"woo/domain/Venue.php");
require_once(
"woo/base/Registry.php");
require_once(
"woo/controller/Request.php");

abstract class
woo_controller_PageController {
    private
$request;
    function
__construct() {
        
$request = woo_base_RequestRegistry::getRequest();
        if ( !
$request ) { $request = new woo_controller_Request(); }
        
$this->request = $request;
        
print_r( $request );
    }

    abstract function
process();

    function
forward( $resource ) {
        include(
$resource );
        exit(
0 );
    }

    function
getRequest() {
        return
$this->request;
    }
}

class
woo_controller_AddVenueController extends woo_controller_PageController {
    function
process() {
        try {
            
$request = $this->getRequest();
            
$name = $request->getProperty( 'venue_name' );
            if ( !
$request->getProperty('submitted') ) {
               
$request->addFeedback("choose a name for the venue");
               
$this->forward( 'add_venue.php' );
            } else if ( !
$name ) {
               
$request->addFeedback("name is a required field");
               
$this->forward( 'add_venue.php' );
            }

            
$venue = new woo_domain_Venue( null, $name );

            
$this->forward( "venues.php" );
        } catch (
Exception $e ) {
            
$this->forward( 'error.php' );
        }
    }
}
$controller = new woo_controller_AddVenueController();
$controller->process();
?>

File:add_venue.php


<?php
require_once( "woo/base/Registry.php" );
$request = woo_base_RequestRegistry::getRequest();
?>
<html>
<head>
<title>Add Venue</title>
</head>
<body>
<h1>Add Venue</h1>

<table>
<tr>
<td>
<?php
print $request->getFeedbackString("</td></tr><tr><td>");
?>
</td>
</tr>
</table>

<form action="AddVenue.php" method="get">
    <input type="hidden" name="submitted" value="yes"/>
    <input type="text" name="venue_name" />
</form>

</body>
</html>

File:venues.php


<?php
require_once("woo/mapper/VenueMapper.php");
require_once(
"woo/domain/Venue.php");

try {
    
$venues = woo_domain_Venue::findAll();
} catch (
Exception $e ) {
    include(
'error.php' );
    exit(
0);
}

// default page follows
?>
<html>
<head>
<title>Venues</title>
</head>
<body>
<h1>Venues</h1>

<?php foreach( $venues as $venue ) { ?>
    <?php print $venue->getName(); ?><br />
<?php } ?>

</body>
</html>

File:Exceptions.php


<?php

class woo_base_AppException extends Exception {}

class
woo_base_DBException extends Exception {
    private
$error;
    function
__construct( DB_Error $error ) {
        
parent::__construct( $error->getMessage(), $error->getCode() );
        
$this->error = $db_error;
    }

    function
getErrorObject() {
        return
$this->error;
    }

}


?>

File:Registry.php


<?php

abstract class woo_base_Registry {
    private function
__construct() {}
    abstract protected function
get( $key );
    abstract protected function
set( $key, $val );

}

class
woo_base_RequestRegistry extends woo_base_Registry {
    private
$values = array();
    private static
$instance;

    static function
instance() {
        if ( !
self::$instance ) { self::$instance = new self(); }
        return
self::$instance;
    }

    protected function
get( $key ) {
        return
$this->values[$key];
    }

    protected function
set( $key, $val ) {
        
$this->values[$key] = $val;
    }

    static function
getRequest() {
        return
self::instance()->get('request');
    }

    static function
setRequest( woo_controller_Request $request ) {
        return
self::instance()->set('request', $request );
    }
}

class
woo_base_SessionRegistry extends woo_base_Registry {
    private static
$instance;
    private function
__construct() {
        
session_start();
    }

    static function
instance() {
        if ( !
self::$instance ) { self::$instance = new self(); }
        return
self::$instance;
    }

    protected function
get( $key ) {
        return
$_SESSION[__CLASS__][$key];
    }

    protected function
set( $key, $val ) {
        
$_SESSION[__CLASS__][$key] = $val;
    }

    function
setComplex( Complex $complex ) {
        return
self::instance()->set('complex', $complex);
    }

    function
getComplex( ) {
        return
self::instance()->get('complex');
    }
}

class
woo_base_ApplicationRegistry extends woo_base_Registry {
    private static
$instance;
    private
$freezefile = "data/applicationRegistry.txt";
    private
$values = array();
    private
$dirty = false;

    private function
__construct() {
        
$this->reload();
    }

    static function
instance() {
        if ( !
self::$instance ) { self::$instance = new self(); }
        return
self::$instance;
    }

    function
__destruct() {
        if (
$this->dirty ) {
            
$this->save();
        }
    }

    private function
reload() {
        if ( !
file_exists( $this->freezefile ) ) { return false; }
        
$serialized = file_get_contents( $this->freezefile, true );
        
$array = unserialize( $serialized );
        if (
is_array( $array ) ) {
            if (
$this->dirty ) {
                
$this->values = array_merge( $this->values, $values );
            } else {
                
$this->values = $array;
            }
            return
true;
        }
        return
false;
    }

    private function
save() {
        
$frozen = serialize( $this->values );
        
file_put_contents(  $this->freezefile, $frozen,
                            
FILE_USE_INCLUDE_PATH  );
        
$self->dirty = false;
    }

    protected function
get( $key ) {
        return
$this->values[$key];
    }

    protected function
set( $key, $val ) {
        
$this->dirty = true;
        
$this->values[$key] = $val;
    }

    static function
isEmpty() {
        return empty(
self::instance()->values );
    }

    static function
getDSN() {
        return
self::instance()->get('dsn');
    }

    static function
setDSN( $dsn ) {
        return
self::instance()->set('dsn', $dsn);
    }

    static function
getControllerMap( ) {
        return
self::instance()->get('cmap');
    }

    static function
setControllerMap( woo_controller_ControllerMap $map ) {
        return
self::instance()->set('cmap', $map);
    }

}

?>

File:AddSpace.php


<?php
require_once( "woo/mapper/VenueMapper.php" );
require_once(
"woo/domain/Venue.php" );

class
woo_command_AddSpace extends woo_command_Command {
    function
doExecute( woo_controller_Request $request ) {
        
$venue = $request->getObject( "venue" );
        if ( !
$venue ) {
            
$venue = woo_domain_Venue::
                        
find($request->getProperty( 'venue_id' ));
        }
        if ( !
$venue ) {
            
$request->addFeedback( "unable to find venue" );
            return
self::statuses('CMD_ERROR');
        }
        
$request->setObject( "venue", $venue );

        
$name = $request->getProperty("space_name");

        if ( !
$name ) {
            
$request->addFeedback( "please add name for the space" );
            return
self::statuses('CMD_INSUFFICIENT_DATA');
        } else {
            
$venue->addSpace( $space = new woo_domain_Space( null, $name ));
            
$request->addFeedback( "space '$name' added ({$venue->getId()})" );
            return
self::statuses('CMD_OK');
        }
    }
}

?>

File:AddVenue.php


<?php
require_once( "woo/mapper/VenueMapper.php" );
require_once(
"woo/domain/Venue.php" );

class
woo_command_AddVenue extends woo_command_Command {
    function
doExecute( woo_controller_Request $request ) {
        
$name = $request->getProperty("venue_name");
        if ( !
$name ) {
            
$request->addFeedback( "no name provided" );
            return
self::statuses('CMD_INSUFFICIENT_DATA');
        } else {
            
$venue_obj = new woo_domain_Venue( null, $name );
            
$request->setObject( 'venue', $venue_obj );
            
$request->addFeedback( "'$name' added ({$venue_obj->getId()})" );
            return
self::statuses('CMD_OK');
        }
        return
self::statuses('CMD_DEFAULT');
    }
}

?>

File:Command.php


<?php

abstract class woo_command_Command {

    private static
$STATUS_STRINGS = array (
        
'CMD_DEFAULT'=>0,
        
'CMD_OK' => 1,
        
'CMD_ERROR' => 2,
        
'CMD_INSUFFICIENT_DATA' => 3
    
);

    private
$status = 0;

    final function
__construct() { }

    function
execute( woo_controller_Request $request ) {
        
$this->status = $this->doExecute( $request );
        
$request->setCommand( $this );
    }

    function
getStatus() {
        return
$this->status;
    }

    static function
statuses( $str='CMD_DEFAULT' ) {
        if ( empty(
$str ) ) { $str = 'CMD_DEFAULT'; }
        print
"handling status: $str\n";
        return
self::$STATUS_STRINGS[$str];
    }

    abstract function
doExecute( woo_controller_Request $request );
}
?>

File:CommandResolver.php


<?php
require_once( "woo/command/Command.php" );
require_once(
"woo/command/DefaultCommand.php" );

class
woo_command_CommandResolver {
    private static
$base_cmd;
    private static
$default_cmd;

    function
__construct() {
        if ( !
self::$base_cmd ) {
            
self::$base_cmd = new ReflectionClass( "woo_command_Command" );
            
self::$default_cmd = new woo_command_DefaultCommand();
        }
    }

    function
getCommand( woo_controller_Request $request ) {
        
$cmd = $request->getProperty( 'cmd' );
        if ( !
$cmd ) {
            return
self::$default_cmd;
        }
        
$filepath = "woo/command/$cmd.php";
        
$classname = "woo_command_$cmd";
        if (
file_exists( $filepath ) ) {
            require_once(
"$filepath" );
            if (
class_exists( $classname) ) {
                
$cmd_class = new ReflectionClass($classname);
                if (
$cmd_class->isSubClassOf( self::$base_cmd ) ) {
                    return
$cmd_class->newInstance();
                } else {
                    
$request->addFeedback( "command '$cmd' is not a Command" );
                }
            }
        }
        
$request->addFeedback( "command '$cmd' not found" );
        return clone
self::$default_cmd;
    }
}

?>

File:DefaultCommand.php


<?php
require_once( "woo/command/Command.php" );

class
woo_command_DefaultCommand extends woo_command_Command {
    function
doExecute( woo_controller_Request $request ) {
        
$request->addFeedback( "Welcome to WOO" );
        include(
"woo/view/main.php");
    }
}

?>

File:ListVenues.php


<?php
require_once( "woo/domain/Venue.php" );

class
woo_command_ListVenues extends woo_command_Command {
    function
doExecute( woo_controller_Request $request ) {
        
$collection = woo_domain_Venue::findAll();
        
$request->setObject( 'venues', $collection );
        return
self::statuses( 'CMD_OK' );
    }
}

?>

File:AppController.php


<?php
require_once( 'woo/controller/Request.php' );

class
woo_controller_AppController {
    private static
$base_cmd;
    private static
$default_cmd;
    private
$controllerMap;
    private
$invoked = array();

    function
__construct( woo_controller_ControllerMap $map ) {
        
$this->controllerMap = $map;
        if ( !
self::$base_cmd ) {
            
self::$base_cmd = new ReflectionClass( "woo_command_Command" );
            
self::$default_cmd = new woo_command_DefaultCommand();
        }
    }

    function
getView( woo_controller_Request $req ) {
        
$view = $this->getResource( $req, "View" );
        return
$view;
    }

    function
getForward( woo_controller_Request $req ) {
        
$forward = $this->getResource( $req, "Forward" );
        if (
$forward ) {
            
$req->setProperty( 'cmd', $forward );
        }
        return
$forward;
    }

    private function
getResource( woo_controller_Request $req,
                                  
$res ) {
        
$cmd_str = $req->getProperty( 'cmd' );
        
$previous = $req->getLastCommand();
        
$status = $previous->getStatus();
        if (!
$status ) { $status = 0; }
        
$acquire = "get$res";
        
$resource = $this->controllerMap->$acquire( $cmd_str, $status );
        if ( !
$resource ) {
            
$resource = $this->controllerMap->$acquire( $cmd_str, 0 );
        }
        if ( !
$resource ) {
            
$resource = $this->controllerMap->$acquire( 'default', $status );
        }
        if ( !
$resource ) {
            
$resource = $this->controllerMap->$acquire( 'default', 0 );
        }
        return
$resource;
    }

    function
getCommand( woo_controller_Request $req ) {
        
$previous = $req->getLastCommand();
        if ( !
$previous ) {
            
$cmd = $req->getProperty('cmd');
            if ( !
$cmd ) {
                
$req->setProperty('cmd', 'default' );
                return  
self::$default_cmd;
            }
        } else {
            
$cmd = $this->getForward( $req );
            if ( !
$cmd ) { return null; }
        }

        
$cmd_obj = $this->resolveCommand( $cmd );
        if ( !
$cmd_obj ) {
            throw new
woo_base_AppException( "couldn't resolve '$cmd'" );
        }

        
$cmd_class = get_class( $cmd_obj );
        
$this->invoked[$cmd_class]++;
        if (
$this->invoked[$cmd_class] > 1 ) {
            throw new
woo_base_AppException( "circular forwarding" );
        }

        return
$cmd_obj;
    }

    function
resolveCommand( $cmd ) {
        
$classroot = $this->controllerMap->getClassroot( $cmd );
        
$filepath = "woo/command/$classroot.php";
        
$classname = "woo_command_$classroot";
        if (
file_exists( $filepath ) ) {
            require_once(
"$filepath" );
            if (
class_exists( $classname) ) {
                
$cmd_class = new ReflectionClass($classname);
                if (
$cmd_class->isSubClassOf( self::$base_cmd ) ) {
                    return
$cmd_class->newInstance();
                }
            }
        }
        return
null;
    }
}

class
woo_controller_ControllerMap {
    private
$viewMap = array();
    private
$forwardMap = array();
    private
$classrootMap = array();

    function
addClassroot( $command, $classroot ) {
        
$this->classrootMap[$command]=$classroot;
    }

    function
getClassroot( $command ) {
        return (
$name = $this->classrootMap[$command])?
            
$name : $command;
    }

    function
addView( $command='default', $status=0, $view ) {
        
$this->viewMap[$command][$status]=$view;
    }

    function
getView( $command, $status ) {
        return
$this->viewMap[$command][$status];
    }

    function
addForward( $command, $status=0, $newCommand ) {
        
$this->forwardMap[$command][$status]=$newCommand;
    }

    function
getForward( $command, $status ) {
        return
$this->forwardMap[$command][$status];
    }
}
?>

File:ApplicationHelper.php


<?php
require_once( 'woo/base/Registry.php' );
require_once(
'woo/base/Exceptions.php' );
require_once(
'woo/controller/AppController.php' );
require_once(
'DB.php' );

set_include_path( ".:/home/triffid/htdocs/frontcontroller_eg/"
                   
.get_include_path());

class
woo_controller_ApplicationHelper {
    private static
$instance;
    private
$config = "data/woo_options.xml";

    private function
__construct() {}

    static function
instance() {
        if ( !
self::$instance ) {
            
self::$instance = new self();
        }
        return
self::$instance;
    }

    function
init() {
        if ( !
woo_base_ApplicationRegistry::isEmpty() ) {
            return;
        }
        
$this->getOptions();
    }

    private function
getOptions() {
        
$this->ensure( file_exists( $this->config  ),
                            
"Could not find options file" );
        
$options = @SimpleXml_load_file( $this->config );
        
$this->ensure( $options instanceof SimpleXMLElement,
                            
"Could not resolve options file" );
        
$dsn = (string)$options->dsn;
        
$this->ensure( $dsn, "No DSN found" );
        
woo_base_ApplicationRegistry::setDSN( $dsn );

        
$map = new woo_controller_ControllerMap();

        foreach (
$options->control->view as $default_view ) {
            
$stat_str = trim($default_view['status']);
            
$status = woo_command_Command::statuses( $stat_str );
            
$map->addView( 'default', $status, (string)$default_view );
        }

        foreach (
$options->control->command as $command_view ) {
            
$command =  trim((string)$command_view['name'] );
            if (
$command_view->classalias ) {
                
$classroot = trim((string)$command_view->classroot['name']);
                
$map->addClassroot( $command, $classroot  );
            }
            if (
$command_view->view ) {
                
$view =  trim((string)$command_view->view);
                
$forward = trim((string)$command_view->forward);
                
$map->addView( $command, 0, $view );
                if (
$forward ) {
                    
$map->addForward( $command, 0, $forward );
                }
                foreach(
$command_view->status as $command_view_status ) {
                    
$view =  trim((string)$command_view_status->view);
                    
$forward = trim((string)$command_view_status->forward);
                    
$stat_str = trim($command_view_status['value']);
                    
$status = woo_command_Command::statuses( $stat_str );
                    if (
$view ) {
                        
$map->addView( $command, $status, $view );
                    }
                    if (
$forward ) {
                        
$map->addForward( $command, $status, $forward );
                    }
                }
            }
        }

        
woo_base_ApplicationRegistry::setControllerMap( $map );
    }

    private function
ensure( $expr, $message ) {
        if ( !
$expr ) {
            throw new
woo_base_AppException( $message );    
        }
    }

    function
DB() {
        
$dsn = woo_base_ApplicationRegistry::getDSN();
        
$this->ensure( $dsn, "No DSN" );
        if ( !
$this->db ) {
            
$this->db = DB::connect( $dsn );
        }
        
$this->ensure(  (! DB::isError( $this->db )),
                        
"Unable to connect to DB" );    
        return
$this->db;
    }

    function
appController() {
        
$map = woo_base_ApplicationRegistry::getControllerMap();
        
$this->ensure( is_object($map), "No ControllerMap" );
        return new
woo_controller_AppController( $map );
    }
}
?>

File:Controller.php


<?php
require_once( 'woo/controller/ApplicationHelper.php' );
require_once(
'woo/controller/Request.php' );
require_once(
'woo/command/CommandResolver.php' );
require_once(
'woo/controller/AppController.php' );

class
woo_controller_Controller {
    private
$applicationHelper;

    private function
__construct() {}

    static function
run() {
        
$instance = new woo_controller_Controller();
        
$instance->init();
        
$instance->handleRequest();
    }

    function
init() {
        
$this->applicationHelper
            
= woo_controller_ApplicationHelper::instance();
        
$this->applicationHelper->init();
    }

    function
handleRequest() {
        
$request = new woo_controller_Request();
        
$app_c = $this->applicationHelper->appController();
        while(
$cmd = $app_c->getCommand( $request ) ) {
            
$cmd->execute( $request );
        }
        
$this->forward( $app_c->getView( $request ) );
    }

    function
forward( $target ) {
        include(
"woo/view/$target.php" );
        exit;
    }
}
?>

File:Request.php


<?php
require_once( 'woo/base/Registry.php' );
require_once(
'woo/base/Exceptions.php' );

class
woo_controller_Request {
    private
$appreg;
    private
$properties;
    private
$objects = array();
    private
$feedback = array();
    private
$lastCommand;

    function
__construct() {
        
$this->init();
        
woo_base_RequestRegistry::setRequest($this );
    }

    function
init() {
        if (
$_SERVER['REQUEST_METHOD'] ) {
            
$this->properties = $_REQUEST;
            return;
        }
        foreach(
$_SERVER['argv'] as $arg ) {
            if (
strpos( $arg, '=' ) ) {
                list(
$key, $val )=explode( "=", $arg );
                
$this->setProperty( $key, $val );
            }
        }
    }

    function
getProperty( $key ) {
        return
$this->properties[$key];
    }

    function
setProperty( $key, $val ) {
        
$this->properties[$key] = $val;
    }
    
    function
__clone() {
        
$this->properties = array();
    }
    
    function
addFeedback( $msg ) {
        
array_push( $this->feedback, $msg );
    }

    function
getFeedback( ) {
        return
$this->feedback;
    }

    function
getFeedbackString( $separator="\n" ) {
        return
implode( $separator, $this->feedback );
    }

    function
setObject( $name, $object ) {
        
$this->objects[$name] = $object;
    }

    function
getObject( $name ) {
        return
$this->objects[$name];
    }

    function
setCommand( woo_command_Command $command ) {
        
$this->lastCommand = $command;
    }

    function
getLastCommand() {
        return
$this->lastCommand;
    }
}
?>

File:Collections.php


<?php

interface woo_domain_VenueCollection extends Iterator {
    function
add( woo_domain_Venue $venue );
}

interface
woo_domain_SpaceCollection extends Iterator {
    function
add( woo_domain_Space $space );
}

interface
woo_domain_EventCollection extends Iterator {
    function
add( woo_domain_Event $event );
}

?>

File:DomainObject.php


<?php
require_once( "woo/domain/Collections.php" );
require_once(
"woo/domain/ObjectWatcher.php" );
require_once(
"woo/domain/HelperFactory.php" );

abstract class
woo_domain_DomainObject {
    private
$id;

    function
__construct( $id=null ) {
        
$this->id = $id;
        if ( !
$this->id ) {
            
$this->id = $this->finder()->newId();
            
$this->markNew();
        }
    }

    function
markNew() {
        
woo_domain_ObjectWatcher::addNew( $this );
    }

    function
markDeleted() {
        
woo_domain_ObjectWatcher::addDelete( $this );
    }

    function
markDirty() {
        
woo_domain_ObjectWatcher::addDirty( $this );
    }

    function
markClean() {
        
woo_domain_ObjectWatcher::addClean( $this );
    }


    function
getId( ) {
        return
$this->id;
    }

    static function
getCollection( $type ) {
        return
woo_domain_HelperFactory::getCollection( $type );
    }

    function
collection() {
        return
self::getCollection( get_class( $this ) );
    }

    function
finder() {
        return
self::getFinder( get_class( $this ) );
    }

    static function
getFinder( $type ) {
        return
woo_domain_HelperFactory::getFinder( $type );
    }

    function
__clone() {
        
$this->id = null;
    }
}
?>

File:Event.php


<?php
require_once( "woo/domain/DomainObject.php" );

class
woo_domain_Event extends woo_domain_DomainObject {
    private
$start;
    private
$duration;
    private
$name;
    private
$space;

    function
__construct( $id=null, $name="unknown" ) {
        
parent::__construct( $id );
        
$this->name = $name;
    }

    function
setStart( $start_l ) {
        
$this->start = $start_l;
    }

    function
getStart( ) {
        return
$this->start;
    }

    function
setSpace( woo_domain_Space $space ) {
        
$this->space = $space;
        
$this->markDirty();
    }

    function
getSpace( ) {
        return
$this->space;
    }

    function
setDuration( $duration_i ) {
        
$this->duration = $duration_i;
        
$this->markDirty();
    }
    
    function
getDuration() {
        return
$this->duration;
    }

    function
setName( $name_s ) {
        
$this->name = $name_s;
        
$this->markDirty();
    }
    
    function
getName() {
        return
$this->name;
    }
}
?>

File:Finders.php


<?php

interface woo_domain_Finder {
    function
find( $id );
    function
findAll();
    function
newId();

    function
update( woo_domain_DomainObject $object );
    function
insert( woo_domain_DomainObject $obj );
    
//function delete();
}

interface
woo_domain_SpaceFinder extends woo_domain_Finder {
    function
findByVenue( $id );
}

interface
woo_domain_VenueFinder  extends woo_domain_Finder {
}

interface
woo_domain_EventFinder  extends woo_domain_Finder {
}
?>

File:HelperFactory.php


<?php
require_once( "woo/mapper/VenueMapper.php" );
require_once(
"woo/mapper/SpaceMapper.php" );
require_once(
"woo/mapper/EventMapper.php" );
require_once(
"woo/mapper/Collections.php" );

class
woo_domain_HelperFactory {
    static function
getFinder( $type ) {
        
$type = preg_replace( "/^.*_/", "", $type );
        
$mapper = "woo_mapper_{$type}Mapper";
        if (
class_exists( $mapper ) ) {
            return new
$mapper();
        }
        throw new
woo_base_AppException( "Unknown: $mapper" );
    }

    static function
getCollection( $type ) {
        
$type = preg_replace( "/^.*_/", "", $type );
        
$collection = "woo_mapper_{$type}Collection";
        if (
class_exists( $collection ) ) {
            return new
$collection();
        }
        throw new
woo_base_AppException( "Unknown: $collection" );
    }
}
?>

File:ObjectWatcher.php


<?php
require_once( "woo/base/Registry.php" );

class
woo_domain_ObjectWatcher {
    private
$all = array();
    private
$dirty = array();
    private
$new = array();
    private
$delete = array();
    private static
$instance;

    private function
__construct() { }

    static function
instance() {
        if ( !
self::$instance ) {
            
self::$instance = new woo_domain_ObjectWatcher();
        }
        return
self::$instance;
    }

    function
globalKey( woo_domain_DomainObject $obj ) {
        
$key = get_class( $obj ).".".$obj->getId();
        return
$key;
    }
  
    static function
add( woo_domain_DomainObject $obj ) {
        
$inst = self::instance();
        
$inst->all[$inst->globalKey( $obj )] = $obj;
    }

    static function
exists( $classname, $id ) {
        
$inst = self::instance();
        
$key = "$classname.$id";
        return
$inst->all[$key];
    }

    static function
addDelete( woo_domain_DomainObject $obj ) {
        
$self = self::instance();
        
$self->delete[$self->globalKey( $obj )] = $obj;
    }


    static function
addDirty( woo_domain_DomainObject $obj ) {
        
$inst = self::instance();
        if ( !
$inst->new[$inst->globalKey( $obj )] ) {
            
$inst->dirty[$inst->globalKey( $obj )] = $obj;
        }
    }

    static function
addNew( woo_domain_DomainObject $obj ) {
        
$inst = self::instance();
        
$inst->new[$inst->globalKey( $obj )] = $obj;
    }

    static function
addClean(woo_domain_DomainObject $obj ) {
        
$self = self::instance();
        unset(
$self->delete[$self->globalKey( $obj )] );
        unset(
$self->dirty[$self->globalKey( $obj )] );
    }

    function
performOperations() {
        foreach (
$this->dirty as $key=>$obj ) {
            print
"updating {$obj->getName()}\n";
            
$obj->finder()->update( $obj );
        }
        foreach (
$this->new as $key=>$obj ) {
            print
"inserting {$obj->getName()}\n";
            
$obj->finder()->insert( $obj );
        }
        
$this->dirty = array();
        
$this->new = array();
    }

    function
__destruct() {
        
$this->performOperations();
    }
}

File:Space.php


<?php
require_once( "woo/domain/DomainObject.php" );

class
woo_domain_Space extends woo_domain_DomainObject {
    private
$name;
    private
$events;
    private
$venue;

    function
__construct( $id=null, $name='main' ) {
        
parent::__construct( $id );
        
//$this->events = self::getCollection("woo_domain_Event");
        
$this->events = null;
        
$this->name = $name;
    }

    function
setEvents( woo_domain_EventCollection $events ) {
        
$this->events = $events;
    }

    function
getEvents() {
        
#return $this->events;
        
if ( is_null($this->events) ) {
            
$this->events = self::getFinder('woo_domain_Event')
                ->
findBySpaceId( $this->getId() );
        }
        return
$this->events;
    }

    function
addEvent( woo_domain_Event $event ) {
        
$this->events->add( $event );
        
$event->setSpace( $this );
    }

    function
setName( $name_s ) {
        
$this->name = $name_s;
        
$this->markDirty();
    }

    function
setVenue( woo_domain_Venue $venue ) {
        
$this->venue = $venue;
        
$this->markDirty();
    }

    function
getVenue( ) {
        return
$this->venue;
    }

    function
getName() {
        return
$this->name;
    }
}
?>

File:Venue.php


<?php
require_once( "woo/domain/DomainObject.php" );

class
woo_domain_Venue extends woo_domain_DomainObject {
    private
$name;
    private
$spaces;

    function
__construct( $id=null, $name=null ) {
        
$this->name = $name;
        
$this->spaces = self::getCollection("woo_domain_Space");
        
parent::__construct( $id );
    }
    
    function
setSpaces( woo_domain_SpaceCollection $spaces ) {
        
$this->spaces = $spaces;
    }

    function
getSpaces() {
        return
$this->spaces;
    }

    function
addSpace( woo_domain_Space $space ) {
        
$this->spaces->add( $space );
        
$space->setVenue( $this );
    }

    function
setName( $name_s ) {
        
$this->name = $name_s;
        
$this->markDirty();
    }

    function
getName( ) {
        return
$this->name;
    }
    
    static function
findAll() {
        
$finder = self::getFinder( __CLASS__ );
        return
$finder->findAll();
    }
    static function
find( $id ) {
        
$finder = self::getFinder( __CLASS__ );
        return
$finder->find( $id );
    }

}

?>

File:domain.php


<?php
$dir
= "woo/domain/" ;
$dh = opendir( "$dir" );
while(
$file = readdir( $dh ) ) {
    if (
substr( $file, -4 ) == ".php" ) {
        require_once(
"$dir/$file" );
    }
}

?>

File:Collection.php


<?php
require_once( "woo/domain/Collections.php" );

abstract class
woo_mapper_Collection {
    private
$mapper;
    private
$result;
    private
$total = 0;
    private
$pointer = 0;
    private
$objects = array();
    private
$raw = array();

    function
__construct( $result=null, $mapper=null ) {
        if (
$result && $mapper ) {
            
$this->init_db( $result, $mapper );
        }
    }

    protected function
init_db( DB_Result $result,
                     
woo_mapper_Mapper $mapper ) {
        
$this->result = $result;
        
$this->mapper = $mapper;
        
$this->total  += $result->numrows();
        while (
$row = $this->result->fetchRow( DB_FETCHMODE_ASSOC ) ) {
            
$this->raw[] = $row;
        }
    }

    protected function
doAdd( woo_domain_DomainObject $object ) {
        
$this->notifyAccess();
        
$this->objects[$this->total] = $object;
        
$this->total++;

    }

    protected function
notifyAccess() {
        
// deliberately left blank!
    
}

    private function
getRow( $num ) {
        
$this->notifyAccess();
        if (
$num >= $this->total || $num < 0 ) {
            return
null;
        }   
        if (
$this->objects[$num] ) {
            return
$this->objects[$num];
        }

        if (
$this->raw[$num] ) {
            
$this->objects[$num]=$this->mapper->loadArray( $this->raw[$num] );
            return
$this->objects[$num];
        }
    }

    public function
rewind() {
       
$this->pointer = 0;
    }

   public function
current() {
       return
$this->getRow( $this->pointer );
   }

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

   public function
next() {
        
$row = $this->getRow( $this->pointer );
        if (
$row ) { $this->pointer++; }
        return
$row;
   }

   public function
valid() {
       return ( !
is_null( $this->current() ) );
   }
}

?>

File:Collections.php


<?php
require_once( "woo/mapper.php" );
require_once(
"woo/domain/Collections.php" );
require_once(
"woo/mapper/Collection.php" );
require_once(
"woo/domain/Venue.php" );

class
woo_mapper_VenueCollection
        
extends woo_mapper_Collection
        
implements woo_domain_VenueCollection {

    function
add( woo_domain_Venue $venue ) {
        
$this->doAdd( $venue );
    }
}

class
woo_mapper_SpaceCollection
        
extends woo_mapper_Collection
        
implements woo_domain_SpaceCollection {

    function
add( woo_domain_Space $space ) {
        
$this->doAdd( $space );
    }
}

class
woo_mapper_EventCollection
        
extends woo_mapper_Collection
        
implements woo_domain_EventCollection {

    function
add( woo_domain_Event $event ) {
        
$this->doAdd( $event );
    }
}

class
woo_mapper_DeferredEventCollection
        
extends woo_mapper_EventCollection {
    private
$stmt;
    private
$valueArray;
    private
$mapper;
    private
$run=false;

    function
__construct( woo_mapper_Mapper $mapper, $stmt_handle,
                        
$valueArray ) {
        
parent::__construct( );
        
$this->stmt = $stmt_handle;
        
$this->valueArray = $valueArray;
        
$this->mapper = $mapper;
    }

    function
notifyAccess() {
        if ( !
$this->run ) {
            
$result =
                
$this->mapper->doStatement( $this->stmt, $this->valueArray );
            
$this->init_db( $result, $this->mapper );
        }
        
$this->run=true;
    }
}



?>

File:EventMapper.php


<?php

require_once( "woo/base/Exceptions.php" );
require_once(
"woo/mapper.php" );
require_once(
"woo/mapper/Mapper.php" );
require_once(
"woo/mapper/Collections.php" );
require_once(
"woo/domain.php" );

class
woo_mapper_EventMapper extends woo_mapper_Mapper
                             
implements woo_domain_EventFinder {

    function
__construct() {
        
parent::__construct();
        
$this->selectAllStmt = self::$DB->prepare(
                            
"SELECT * FROM event");
        
$this->selectBySpaceStmt = self::$DB->prepare(
                            
"SELECT * FROM event where space=?");
        
$this->selectStmt = self::$DB->prepare(
                            
"SELECT * FROM event WHERE id=?");
        
$this->updateStmt = self::$DB->prepare(
                            
"UPDATE event SET start=?, duration=?, name=?, id=? WHERE id=?");
        
$this->insertStmt = self::$DB->prepare(
                            
"INSERT into event (start, duration, space, name, id)
                             values( ?, ?, ?, ?, ?)"
);
    }
    
    function
doFind( $id ) {
        
$result = $this->doStatement( $this->selectStmt, array( $id ) );
        return
$this->load( $result );
    }

    function
findAll( ) {
        
$result = $this->doStatement( $this->selectAllStmt, array() );
        return new
woo_mapper_EventCollection( $result, $this );
    }

    function
findBySpaceId( $s_id ) {
        return new
woo_mapper_DeferredEventCollection(
                    
$this, $this->selectBySpaceStmt, array( $s_id ) );
    }

    protected function
doLoad( $array ) {
        
$obj = new woo_domain_Event( $array['id'] );
        
$obj->setstart( $array['start'] );
        
$obj->setduration( $array['duration'] );
        
$obj->setname( $array['name'] );
        
$space_mapper = new woo_mapper_SpaceMapper();
        
$space = $space_mapper->find( $array['space'] );
        
$obj->setSpace( $space );

        
$obj->markClean();
        return
$obj;
    }

    protected function
targetClass() {
        return
"woo_domain_Event";
    }

    protected function
doInsert( woo_domain_DomainObject $object ) {
    
#   $id = $self->newId();
        
$space = $object->getSpace();
        if ( !
$space ) {
            throw new
woo_base_AppException( "cannot save without space" );
        }

        
$values = array( $object->getstart(), $object->getduration(), $space->getId(), $object->getname(), $object->getid() );
        print
"doing insert: ";
        
print_r($values);
        print
"\n\n";
        
$this->doStatement( $this->insertStmt, $values );
    
#   $object->setId( $id );    
    
}
    
    public function
newId() {
        return
self::$DB->nextId('event');
    }

    function
update( woo_domain_DomainObject $object ) {
        
$values = array( $object->getstart(), $object->getduration(), $object->getname(), $object->getid(), $object->getId() );
        
$this->doStatement( $this->updateStmt, $values );
    }

    
# custom
    # end_custom
}

File:Mapper.php


<?php

require_once("woo/base/Registry.php");
require_once(
"woo/base/Exceptions.php");
require_once(
"woo/domain/Finders.php");
require_once(
"woo/controller/ApplicationHelper.php");

abstract class
woo_mapper_Mapper implements woo_domain_Finder {
    protected static
$DB;
    function
__construct() {
        if ( !
self::$DB ) {
            
self::$DB = woo_controller_ApplicationHelper::
                        
instance()->DB( );
        }
    }

    function
load( DB_Result $result ) {
        
$array = $result->fetchRow( DB_FETCHMODE_ASSOC );
        if ( !
is_array( $array ) ) { return null; }
        if ( !
$array['id'] ) { return null; }
        
$object = $this->loadArray( $array );
        return
$object;
    }

    function
getFromMap( $id ) {
        return
woo_domain_ObjectWatcher::exists
                
( $this->targetClass(), $id );
    }

    function
addToMap( woo_domain_DomainObject $obj ) {
        return
woo_domain_ObjectWatcher::add( $obj );
    }


    function
find( $id ) {
        
$old = $this->getFromMap( $id );
        if (
$old ) { return $old; }
        return
$this->doFind( $id );
    }

    function
loadArray( $array ) {
        
$old = $this->getFromMap( $array['id']);
        if (
$old ) { return $old; }
        
$obj = $this->doLoad( $array );
        
$this->addToMap( $obj );
        
$obj->markClean();
        return
$obj;
    }

    function
insert( woo_domain_DomainObject $obj ) {
        
$this->doInsert( $obj );
    }

    function
doStatement( $sth, $values ) {
        
$db_result = self::$DB->execute( $sth, $values );
        if (
DB::isError( $db_result ) ) {
            throw new
woo_base_DBException( $db_result );
        }
        return
$db_result;
    }

    
//protected abstract function update( woo_domain_DomainObject $object );
    
protected abstract function doLoad( $array );
    protected abstract function
doFind( $id );
    protected abstract function
doInsert( woo_domain_DomainObject $object );
    protected abstract function
targetClass();
}

File:SpaceMapper.php


<?php

require_once( "woo/base/Exceptions.php" );
require_once(
"woo/mapper.php" );
require_once(
"woo/mapper/Mapper.php" );
require_once(
"woo/mapper/VenueMapper.php" );
require_once(
"woo/mapper/Collections.php" );
require_once(
"woo/domain.php" );

class
woo_mapper_SpaceMapper extends woo_mapper_Mapper
                             
implements woo_domain_SpaceFinder {

    function
__construct() {
        
parent::__construct();
        
$this->selectAllStmt = self::$DB->prepare(
                            
"SELECT * FROM space");
        
$this->selectStmt = self::$DB->prepare(
                            
"SELECT * FROM space WHERE id=?");
        
$this->updateStmt = self::$DB->prepare(
                            
"UPDATE space SET name=?, id=? WHERE id=?");
        
$this->insertStmt = self::$DB->prepare(
                            
"INSERT into space (name, venue, id)
                             values( ?, ?, ?)"
);
        
$this->findByVenueStmt = self::$DB->prepare(
                            
"SELECT * FROM space where venue=?");
    }
    
    function
doFind( $id ) {
        
$result = $this->doStatement( $this->selectStmt, array( $id ) );
        return
$this->load( $result );
    }

    function
findAll( ) {
        
$result = $this->doStatement( $this->selectAllStmt, array() );
        return new
woo_mapper_SpaceCollection( $result, $this );
    }

    protected function
doLoad( $array ) {
        
$obj = new woo_domain_Space( $array['id'] );
        
$obj->setname( $array['name'] );
        
$ven_mapper = new woo_mapper_VenueMapper();
        
$venue = $ven_mapper->find( $array['venue'] );
        
$obj->setVenue( $venue );

        
$event_mapper = new woo_mapper_EventMapper();
        
$event_collection = $event_mapper->findBySpaceId( $array['id'] );        
        
$obj->setEvents( $event_collection );
        
$obj->markClean();
        return
$obj;
    }

    protected function
targetClass() {
        return
"woo_domain_Space";
    }

    protected function
doInsert( woo_domain_DomainObject $object ) {
        
$venue = $object->getVenue();
        if ( !
$venue ) {
            throw new
woo_base_AppException( "cannot save without venue" );
        }
        
$values = array( $object->getname(), $venue->getId(), $object->getid() );
        
$this->doStatement( $this->insertStmt, $values );
    }
    
    public function
newId() {
        return
self::$DB->nextId('space');
    }

    function
update( woo_domain_DomainObject $object ) {
        
$values = array( $object->getname(), $object->getid(), $object->getId() );
        
$this->doStatement( $this->updateStmt, $values );
    }

    
# custom
    
function findByVenue( $vid ) {
        
$result = $this->doStatement( $this->findByVenueStmt, array( $vid ) );
        return new
woo_mapper_SpaceCollection( $result, $this );
    }
    
# end_custom
}

File:VenueMapper.php


<?php

require_once( "woo/base/Exceptions.php" );
require_once(
"woo/mapper.php" );
require_once(
"woo/mapper/Mapper.php" );
require_once(
"woo/mapper/Collections.php" );
require_once(
"woo/domain.php" );

class
woo_mapper_VenueMapper extends woo_mapper_Mapper
                             
implements woo_domain_VenueFinder {

    function
__construct() {
        
parent::__construct();
        
$this->selectAllStmt = self::$DB->prepare(
                            
"SELECT * FROM venue");
        
$this->selectStmt = self::$DB->prepare(
                            
"SELECT * FROM venue WHERE id=?");
        
$this->updateStmt = self::$DB->prepare(
                            
"UPDATE venue SET name=?, id=? WHERE id=?");
        
$this->insertStmt = self::$DB->prepare(
                            
"INSERT into venue (name, id)
                             values( ?, ?)"
);
    }
    
    function
doFind( $id ) {
        
// factor this out
        
$result = $this->doStatement( $this->selectStmt, array( $id ) );
        return
$this->load( $result );
    }

    function
findAll( ) {
        
$result = $this->doStatement( $this->selectAllStmt, array() );
        return new
woo_mapper_VenueCollection( $result, $this );
    }

    protected function
doLoad( $array ) {
        
$obj = new woo_domain_Venue( $array['id'] );
        
$obj->setname( $array['name'] );
        
$space_mapper = new woo_mapper_SpaceMapper();
        
$space_collection = $space_mapper->findByVenue( $array['id'] );
        
$obj->setSpaces( $space_collection );
        
$obj->markClean();
        return
$obj;
    }

    protected function
targetClass() {
        return
"woo_domain_Venue";
    }

    protected function
doInsert( woo_domain_DomainObject $object ) {
        
$values = array( $object->getname(), $object->getid() );
        
$this->doStatement( $this->insertStmt, $values );
    }
    
    public function
newId() {
        return
self::$DB->nextId('venue');
    }

    function
update( woo_domain_DomainObject $object ) {
        
$values = array( $object->getname(), $object->getid(), $object->getId() );
        
$this->doStatement( $this->updateStmt, $values );
    }

    
# custom
    # end_custom
}

File:mapper.php


<?php
$dir
="woo/mapper/";
$dh = opendir( "$dir" );
while(
$file = readdir( $dh ) ) {
    if (
substr( $file, -4 ) == ".php" ) {
        require_once(
"$dir/$file" );
    }
}
?>

File:addspace.php


<?php 
require_once( "woo/view/ViewHelper.php" );
$request = VH::getRequest();
$venue = $request->getObject('venue');
?>

<html>
<head>
<title>Add a Space for venue <?php echo $venue->getName() ?></title>
</head>
<body>
<h1>Add a Space for Venue '<?php print $venue->getName() ?>'</h1>

<table>
<tr>
<td>
<?php print $request->getFeedbackString("</td></tr><tr><td>"); ?>
</td>
</tr>
</table>
[add space]
<form method="post">
    <input type="text" value="<?php echo $request->getProperty( 'space_name' ) ?>" name="space_name"/>
    <input type="hidden" name="cmd" value="AddSpace" />
    <input type="hidden" name="venue_id" value="<?php echo $venue->getId() ?>" />
    <input type="submit" value="submit" />
</form>

</body>
</html>

File:addvenue.php


<?php 
require_once( "woo/view/ViewHelper.php" );
$request = VH::getRequest();
?>

<html>
<head>
<title> Add a Venue </title>
</head>
<body>

<table>
<tr>
<td>
<?php print $request->getFeedbackString("</td></tr><tr><td>"); ?>
</td>
</tr>
</table>

<form method="post">
    <input type="text" value="<?php echo $request->getProperty( 'space_name' ) ?>" name="venue_name" />
    <input type="submit" value="submit" />
</form>

</body>
</html>

File:listvenues.php


<?php 
require_once( "woo/view/ViewHelper.php" );
$request = VH::getRequest();
$venues = $request->getObject('venues');
?>

<html>
<head>
<title>Here are the venues</title>
</head>
<body>

<table>
<tr>
<td>
<?php print $request->getFeedbackString("</td></tr><tr><td>"); ?>
</td>
</tr>
</table>
<?php
foreach( $venues as $venue ) {
    print
"{$venue->getName()}<br />\n";
    foreach(
$venue->getSpaces() as $space ) {
        print
"&nbsp;  {$space->getName()}<br />\n";
    }
}
?>

</body>
</html>

File:main.php


<?php 
require_once( "woo/view/ViewHelper.php" );
$request = VH::getRequest();
?>

<html>
<head>
<title>Woo! it's WOO!</title>
</head>
<body>

<table>
<tr>
<td>
<?php print $request->getFeedbackString("</td></tr><tr><td>"); ?>
</td>
</tr>
</table>

</body>
</html>

File:ViewHelper.php


<?php
require_once( "woo/base/Registry.php" );

class
VH {
    static function
getRequest() {
        return
woo_base_RequestRegistry::getRequest();
    }
}

?>

File:run.php


<?php
require_once('DB.php');
require_once(
'woo/process/VenueManager.php');
require_once(
'woo/base/Registry.php');

$halfhour = (60*30);
$hour     = (60*60);
$day      = (24*$hour);

$db = DB::Connect( "sqlite://./woo/data/woo.db" );
woo_base_RequestRegistry::setDB( $db );


$mgr = new woo_process_VenueManager();
$ret = $mgr->addVenue( "The Eyeball Inn",
                array(
'The Room Upstairs', 'Main Bar' ));
$space_id = $ret['spaces'][0][0];
$mgr->bookEvent( $space_id, "Running like the rain", time()+($day), ($hour) );
$mgr->bookEvent( $space_id, "Running like the trees", time()+($day-$hour), (60*60) );

?>

File:setup.php


<?php
/*
set up script for transaction script example
*/

require_once( "DB.php");

$db = DB::Connect( "sqlite://./woo/data/woo.db" );
@
$db->query( "DROP TABLE venue" );
$db->query( "CREATE TABLE venue ( id INT PRIMARY KEY, name TEXT )" );

$db->query( "DROP TABLE space" );
$db->query( "CREATE TABLE space ( id INT PRIMARY KEY, venue INT, name TEXT )" );

@
$db->query( "DROP TABLE event" );
$db->query( "CREATE TABLE event ( id INT PRIMARY KEY, space INT, start long, duration int, name text )" );
?>

File:Constants.php


<?php

class woo_base_Constants {
    public static
$DATA_DIR = "%DATA_DIR%";
    public static
$DSN = '%DSN';
}
?>

File:Exceptions.php


<?php

class woo_base_AppException extends Exception {}

class
woo_base_DBException extends Exception {
    private
$error;
    function
__construct( DB_Error $error ) {
        
parent::__construct( $error->getMessage(), $error->getCode() );
        
$this->error = $db_error;
    }

    function
getErrorObject() {
        return
$this->error;
    }

}


?>

File:Registry.php


<?php
require_once("DB.php");

abstract class
woo_base_Registry {
    private function
__construct() {}
    abstract protected function
get( $key );
    abstract protected function
set( $key, $val );

}

class
woo_base_RequestRegistry extends woo_base_Registry {
    private
$values = array();
    private static
$instance;

    static function
instance() {
        if ( !
self::$instance ) { self::$instance = new self(); }
        return
self::$instance;
    }

    protected function
get( $key ) {
        return
$this->values[$key];
    }

    protected function
set( $key, $val ) {
        
$this->values[$key] = $val;
    }

    static function
getRequest() {
        return
self::instance()->get('request');
    }

    static function
setRequest( woo_controller_Request $request ) {
        return
self::instance()->set('request', $request );
    }

    static function
getDB() {
        return
self::instance()->get('db');
    }

    static function
setDB( DB_Common $db ) {
        return
self::instance()->set('db', $db);
    }


}

class
woo_base_SessionRegistry extends woo_base_Registry {
    private static
$instance;
    private function
__construct() {
        
session_start();
    }

    static function
instance() {
        if ( !
self::$instance ) { self::$instance = new self(); }
        return
self::$instance;
    }

    protected function
get( $key ) {
        return
$_SESSION[__CLASS__][$key];
    }

    protected function
set( $key, $val ) {
        
$_SESSION[__CLASS__][$key] = $val;
    }

    function
setComplex( Complex $complex ) {
        return
self::instance()->set('complex', $complex);
    }

    function
getComplex( ) {
        return
self::instance()->get('complex');
    }
}

class
woo_base_ApplicationRegistry extends woo_base_Registry {
    private static
$instance;
    private
$freezefile = "data/applicationRegistry.txt";
    private
$values = array();
    private
$dirty = false;

    private function
__construct() {
        
$this->doReload( $this );
    }

    static function
instance() {
        if ( !
self::$instance ) { self::$instance = new self(); }
        return
self::$instance;
    }

    function
__destruct() {
        if (
$this->dirty ) {
            
$this->save();
        }
    }

    static function
reload() {
        
self::instance()->doReload();
    }

    private function
doReload() {
        if ( !
file_exists( $this->freezefile ) ) { return false; }
        
$serialized = file_get_contents( $this->freezefile, true );
        
$array = unserialize( $serialized );
        if (
is_array( $array ) ) {
            
$array = array_merge( $array, $this->values );
            
$this->values = $array;
            return
true;
        }
        return
false;
    }

    private function
save() {
        
$frozen = serialize( $this->values );
        
file_put_contents(  $this->freezefile, $frozen,
                            
FILE_USE_INCLUDE_PATH  );
        
$this->dirty = false;
    }

    protected function
get( $key ) {
        return
$this->values[$key];
    }

    protected function
set( $key, $val ) {
        
$this->dirty = true;
        
$this->values[$key] = $val;
    }

    static function
isEmpty() {
        return empty(
self::instance()->values );
    }

    static function
getDSN() {
        return
self::instance()->get('dsn');
    }

    static function
setDSN( $dsn ) {
        return
self::instance()->set('dsn', $dsn);
    }
}

?>

File:woo.db


** This file contains an SQLite 2.1 database **(uãÚKå€
 *,åtriggerspace_seq_cleanupspace_seq0CREATE TRIGGER space_seq_cleanup AFTER INSERT ON space_seq
                    BEGIN
                        DELETE FROM space_seq WHERE id<LAST_INSERT_ROWID();
                    ENDØt[€  "[tablevenue_seqvenue_seq4CREATE TABLE venue_seq (id INTEGER UNSIGNED PRIMARY KEY)¿lå€ *,åtriggervenue_seq_cleanupvenue_seq0CREATE TRIGGER venue_seq_cleanup AFTER INSERT ON venue_seq
                    BEGIN
                        DELETE FROM venue_seq WHERE id<LAST_INSERT_ROWID();
                    END[€      "[tablespace_seqspace_seq8CREATE TABLE space_seq (id INTEGER UNSIGNED PRIMARY KEY)(€5ä€4Ðha€0a€Da€Xa€la€€a€”a€¨a€¼a€    Ða€
äa€ øa€  a€  a€
8b0G1l€B
Pb0G1m€B
b0G1n€˜H/€    /4810975041553600Running like the rain¸LhO€  Otablevenuevenue9CREATE TABLE venue ( id INT PRIMARY KEY, name TEXT )¤)€  &))index(venue autoindex 1)venue11[€  ablespacespace12CREATE TABLE space ( id INT PRIMARY KEY, venue INT, name TEXT )¿”)€  &))index(space autoindex 1)space10|€(€ &((index(event autoindex 1)event5\t€ ttableeventevent6CREATE TABLE event ( id INT PRIMARY KEY, space INT, start long, duration int, name text )„\€  #\tableevent_seqevent_seq13CREATE TABLE event_seq (id INTEGER UNSIGNED PRIMARY KEY)å€ *,åtriggerevent_seq_cleanupevent_seq0CREATE TRIGGER event_seq_cleanup AFTER INSERT ON event_seq
                    BEGIN
                        DELETE FROM event_seq WHERE id<LAST_INSERT_ROWID();
                    END„€;ä€:ÐÈ0€30The Eyeball InnX€31The Eyeball Inn€€32The Eyeball Inn¨€33The Eyeball InnЀ34The Eyeball Innø€35The Eyeball Inn €36The Eyeball InnH€37The Eyeball Innp€    38The Eyeball Inn˜€
39The Eyeball InnÀ€ 40The Eyeball Innè€ 41The Eyeball Inn€ 42The Eyeball Inn8€ 43The Eyeball Inn`€44The Eyeball Innˆ€45The Eyeball Inn°€46The Eyeball InnØ€47The Eyeball Inn€48The Eyeball Inn(€49The Eyeball InnP€50The Eyeball Innx€51The Eyeball Inn €52The Eyeball Inn€53The Eyeball Inn8  b0G2WW€BàH
b0G1|€B
8b0G1~€B Pb0G2WW€B hb0G2WX€B €b0G2WY€B ˜b0G2WZ€B °b0G2Wa€B Èb0G2Wb€B àb0G2Wc€    B øb0G2Wd€
B b0G2We€ B (b0G2Wf€ B @b0G2Wg€ B Xb0G2Wh€ B pb0G2Wi€B ˆb0G2Wj€B  b0G2Wk€B ¸b0G2Wl€B Ðb0G2Wm€B èb0G2Wn€B b0G2Wo€B b0G2Wp€B 0b0G2Wq€B b0G2Wr€B¸, €
3742Main BarBÔirsÌ€ä€Ðô4€
1230The Room UpstairsX€
1330Main BarB„€
1431The Room Upstairs¨€
1531Main BarBÔ€
1632The Room Upstairsø€
1732Main BarB$€
1833The Room UpstairsH€
1933Main BarBt€    
2034The Room Upstairs˜€

2134Main BarBÄ€ 
2235The Room Upstairsè€ 
2335Main BarB€ 
2436The Room Upstairs8€ 
2536Main BarBd€
2637The Room Upstairsˆ€
2737Main BarB´€
2838The Room Upstairs؀
2938Main BarB€
3039The Room Upstairs(€
3139Main BarBT€
3240The Room Upstairsx€
3340Main BarB¤€
3441The Room UpstairsȀ
3541Main BarB€
3642The Room Upstairs x4€
3843The Room UpstairsX€
3943Main BarB„€
4044The Room Upstairs¨€
4144Main BarBÔ€
4245The Room Upstairsø€ 
4345Main BarB$€!
4446The Room UpstairsH€"
4546Main BarBt€#
4647The Room Upstairs˜€$
4747Main BarBÄ€%
4848The Room Upstairsè€&
4948Main BarB€'
5049The Room Upstairs8€(
5149Main BarBd€)
5250The Room Upstairsˆ€*
5350Main BarB´€+
5451The Room Upstairs؀,
5551Main Bar€-
5652The Room Upstairs(€.
5752Main BarT€/
5853The Room Upstairs€0
5953Main Barˆè
b0G1i€B
8b0G1j€B
Pb0G1k€B
hb0G1l€B
€b0G1m€B
˜b0G1n€B
°b0G1o€B
Èb0G1p€B
àb0G1q€    B
øb0G1r€
B
b0G1s€ B
(b0G1t€ B
@b0G1u€ B
Xb0G1v€ B
pb0G1w€B
ˆb0G1x€B
 b0G1y€B
¸b0G1z€B
Ðb0G1|€B
b0G1~€B b0G2WX€B 8b0G2WY€B Pb0G2WZ€B hb0G2Wa€B €b0G2Wb€B ˜b0G2Wc€ °b0G2Wd€ Èb0G2We€ àb0G2Wf€ øb0G2Wg€ b0G2Wh€ (b0G2Wi€! @b0G2Wj€" Xb0G2Wk€# pb0G2Wl€$ ˆb0G2Wm€%  b0G2Wn€& ¸b0G2Wo€' Ðb0G2Wp€( èb0G2Wq€) b0G2Wr€* b0G2Ws€+ 0b0G2Wt€,B Hb0G2Wu€-B `b0G2Wv€.B xb0G2Ww€/B b0G2Wx€0BpÈH/€',/Running like the rain1097502851360028ˆ/€    /4010975040723600Running like the rainÈ0€    04010975148723600Running like the trees/€    /4210975040963600Running like the rainH/€    /4410975041153600Running like the rainˆ0€    04410975095153600Running like the trees/€    /4610975041343600Running like the rain8TH0€        04810975005553600Running like the treesˆ/€
    /5010993107963600Running like the rainÈ0€     05010993071963600Running like the trees/€     /5210993108023600Running like the rainH0€     05210993072023600Running like the treesˆ/€     /5410993108803600Running like the rainÌ2€     2155610999491993600Running like the rainB3€     3165610999455993600Running like the treesB2€     2175810999492153600Running like the rain1¬

File:Base.php


<?php
require_once( 'woo/base/Registry.php' );
require_once(
'woo/base/Exceptions.php' );

abstract class
woo_process_Base {
    static
$DB;
    static
$stmts = array();
   
    function
__construct() {
        
self::$DB = woo_base_RequestRegistry::getDB( "DB" );
        if ( !
self::$DB ) {
            throw new
woo_base_AppException( "No DB object" );
        }
        if (
DB::isError( self::$DB ) ) {
            throw new
woo_base_DBException( self::$DB );
        }
    }

    function
prepareStatement( $stmt_s ) {
        if (
self::$stmts[$stmt_s] ) {
            return
self::$stmts[$stmt_s];
        }
        
$stmt_handle = self::$DB->prepare($stmt_s);
        if (
DB::isError( $stmt_handle ) ) {
            throw new
woo_base_DBException( $stmt_handle );
        }
        
self::$stmts[$stmt_s]=$stmt_handle;
        return
$stmt_handle;
    }

    protected function
doStatement( $stmt_s, $values_a ) {
        
$sth = $this->prepareStatement( $stmt_s );
        
$db_result = self::$DB->execute( $sth, $values_a );
        if (
DB::isError( $db_result ) ) {
            throw new
woo_base_DBException( $db_result );
        }
        return
$db_result;
    }
}

File:EventManager.php


<?php


class woo_process_VenueBooker {

    

}

File:VenueManager.php


<?php
require_once( 'woo/process/Base.php' );

class
woo_process_VenueManager extends woo_process_Base {
    static
$add_venue =  "INSERT INTO venue
                          ( id, name )
                          values( ?, ? )"
;
    static
$add_space  = "INSERT INTO space
                          ( id, name, venue )
                          values( ?, ?, ? )"
;
    static
$check_slot = "SELECT id, name
                          FROM event
                          WHERE space=?
                          AND (start+duration) > ?
                          AND start < ?"
;
    static
$add_event =  "INSERT INTO event
                          ( id, name, space, start, duration )
                          values( ?, ?, ?, ?, ? )"
;

    function
addVenue( $name, $space_array ) {
        
$ret = array();
        
$v_id = self::$DB->nextId('venue');
        
$ret['venue'] = array( $v_id, $name );
        
$this->doStatement( self::$add_venue, $ret['venue']);
        
$ret['spaces'] = array();
        foreach (
$space_array as $space_name ) {
            
$s_id = self::$DB->nextId('space');
            
$values = array($s_id, $space_name, $v_id );
            
$this->doStatement( self::$add_space, $values);
            
$ret['spaces'][] = $values;
        }
        return
$ret;
    }
    
    function
bookEvent( $venue_id, $name, $time, $duration ) {
        
$result =
            
$this->doStatement( self::$check_slot,
                array(
$venue_id, $time, ($time+$duration) ) );
        if (
$result->numRows() > 0 ) {
            throw new
woo_base_AppException( "double booked! try again" );
        }
        
$e_id = self::$DB->nextId('event');
        
$this->doStatement( self::$add_event,
            array(
$e_id, $name, $venue_id, $time, $duration ) );
    }
}
?>

File:main.php


<?php

require_once( "User.php" );
require_once(
"UserStore.php" );
require_once(
"Validator.php" );

$user = new User( 'bob', 'williams', 'bob@example.com', 'bibblepops' );
print
$user->fullname();

$store = new UserStore();
$store->addUser( 'bob williams', 'bob@example.com', 'bibblepops');
$validator = new Validator( $store );

if (
$validator->validateUser('bob@example.com', 'bibblepops') ) {
    print
"pass friend\n";
} else {
    print
"who are you?\n";
}

?>

File:AllTests.php


<?php
define
('PHPUnit2_MAIN_METHOD', 'AppTests::main');

require_once(
"PHPUnit2/Framework/TestSuite.php" );
require_once(
"PHPUnit2/TextUI/TestRunner.php" );
require_once(
"tests/UserTest.php" );
require_once(
"tests/UserStoreTest.php" );
require_once(
"tests/ValidatorTest.php" );


class
AppTests {
    public static function
main() {
        
$ts = new PHPUnit2_Framework_TestSuite( 'User Classes');
        
$ts->addTestSuite('UserTest');
        
$ts->addTestSuite('UserStoreTest');
        
$ts->addTestSuite('ValidatorTest');
        
PHPUnit2_TextUI_TestRunner::run( $ts );
    }
}

AppTests::main();
?>

File:UserStoreTest.php


<?php
require_once('UserStore.php');
require_once(
'PHPUnit2/Framework/TestCase.php');


class
UserStoreTest extends PHPUnit2_Framework_TestCase {
    private
$store;

    public function
setUp() {
        
$this->store = new UserStore();
    }
    
    public function  
testAddUser_IncompleteData() {
        
$this->assertFalse(
            
$this->store->addUser(  "bob williams" ),
            
"Insufficient arguments should cause false retval"
        
);
    }

    public function  
testAddUser_ShortPass() {
        try {
            
$this->store->addUser(  "bob williams", "a@b.com", "ff" );
        } catch (
Exception $e ) { return; }
        
$this->fail("Short password exception expected");
    }

    public function  
testAddUser_success() {
        
$this->assertTrue(
            
$this->store->addUser(  "bob williams", "a@b.com", "12345" ),
            
"User added with valid arguments. Method should return true"
        
);
    }

    public function  
testGetUser() {
        
$this->store->addUser(  "bob williams", "a@b.com", "12345" );
        
$user = $this->store->getUser(  "a@b.com" );
        
$this->assertEquals( $user->getMail(), "a@b.com" );
    }

}

?>

File:UserTest.php


<?php
require_once('User.php');
require_once(
'PHPUnit2/Framework/TestCase.php');


class
UserTest extends PHPUnit2_Framework_TestCase {
    private
$user;

    public function
setUp() {
        
$this->user = new User( "bob williams",
                                
"bob@example.com",
                                
"fantopedia" );
    }
    
    public function  
testGetMail() {
        
$mail = $this->user->getMail();
        
$this->assertType(  "string", $mail );
        
$this->assertEquals(  "bob@example.com", $mail );
    }
}

?>

File:ValidatorTest.php


<?php
require_once('UserStore.php');
require_once(
'Validator.php');
require_once(
'PHPUnit2/Framework/TestCase.php');


class
ValidatorTest extends PHPUnit2_Framework_TestCase {
    private
$validator;

    public function
setUp() {
        
$store = new UserStore();
        
$store->addUser(  "bob williams", "a@b.com", "12345" );
        
$this->validator = new Validator( $store );
    }

    public function
testValidate_WrongPass() {
        
$this->assertFalse(
            
$this->validator->validateUser( "a@b.com", "wrong" ) );
    }

    public function
testValidate_CorrectPass() {
        
$this->assertTrue(
            
$this->validator->validateUser( "a@b.com", "12345" ),
            
"Expecting successful validation"
            
);
    }

}

?>

File:User.php


<?php

class User {
    private
$name;
    private
$mail;
    private
$pass;

    function
__construct( $name, $mail, $pass ) {
        
$this->name       = $name;
        
$this->mail       = $mail;
        
$this->pass       = $pass;
    }

    function
getMail() {
        return
$this->mail;
    }
}
?>

File:UserStore.php


<?php

class UserStore {
    private
$users = array();
    function
addUser( $name=null, $mail=null, $pass=null ) {
        if (
is_null( $name ) || is_null( $mail ) || is_null( $pass ) ) {
            return
false;
        }

        
$this->users[$mail] = new User( $name, $mail, $pass );

        if (
strlen( $pass ) < 5 ) {
            throw new
Exception("Password must have 5 or more letters");
        }
        return
true;
    }

    function
getUser( $mail ) {
        return (
$this->users[$mail] );
    }
}

?>

File:Validator.php


<?php
class Validator {
    private
$store;
    public function
__construct( UserStore $store ) {
        
$this->store = $store;
    }

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

    public function
validateUser( $mail, $pass ) {
        if ( !
is_array($user = $this->store->getUser( $mail )) ) {
            return
false;
        }
        if (
$user['pass'] == $pass ) {
            return
true;
        }
        return
false;
    }
}
?>

File:main.php


<?php

require_once( "User.php" );
require_once(
"UserStore.php" );
require_once(
"Validator.php" );

$user = new User( 'bob', 'williams', 'bob@example.com', 'bibblepops' );
print
$user->fullname();

$store = new UserStore();
$store->addUser( 'bob williams', 'bob@example.com', 'bibblepops');
$validator = new Validator( $store );

if (
$validator->validateUser('bob@example.com', 'bibblepops') ) {
    print
"pass friend\n";
} else {
    print
"who are you?\n";
}

?>

File:AllTests.php


<?php
define
('PHPUnit2_MAIN_METHOD', 'AppTests::main');

require_once(
"PHPUnit2/Framework/TestSuite.php" );
require_once(
"PHPUnit2/TextUI/TestRunner.php" );

require_once(
"tests/UserTest.php" );
require_once(
"tests/UserStoreTest.php" );
require_once(
"tests/ValidatorTest.php" );


class
AppTests {
    public static function
main() {
        
$ts = new PHPUnit2_Framework_TestSuite( 'User Classes');
        
$ts->addTestSuite('UserTest');
        
$ts->addTestSuite('UserStoreTest');
        
$ts->addTestSuite('ValidatorTest');
        
PHPUnit2_TextUI_TestRunner::run( $ts );
    }
}

AppTests::main();
?>

File:UserStoreTest.php


<?php
require_once('UserStore.php');
require_once(
'PHPUnit2/Framework/TestCase.php');


class
UserStoreTest extends PHPUnit2_Framework_TestCase {
    private
$store;

    public function
setUp() {
        
$this->store = new UserStore();
    }

    public function
tearDown() {
    }
    
    public function  
testAddUser_IncompleteData() {
        
$this->assertFalse(
            
$this->store->addUser(  "bob williams" ),
            
"Insufficient arguments should cause false retval"
        
);
    }

    public function  
testAddUser_ShortPass() {
        try {
            
$this->store->addUser(  "bob williams", "a@b.com", "ff" );
        } catch (
Exception $e ) { return; }
        
$this->fail("Short password exception expected");
    }

    public function  
testAddUser_success() {
        
$this->assertTrue(
            
$this->store->addUser(  "bob williams", "a@b.com", "12345" ),
            
"User added with valid arguments. Method should return true"
        
);
    }

    public function  
testGetUser() {
        
$this->store->addUser(  "bob williams", "a@b.com", "12345" );
        
$user = $this->store->getUser(  "a@b.com" );
        
$this->assertEquals( $user['mail'], "a@b.com" );
        
$this->assertEquals( $user['name'], "bob williams" );
        
$this->assertEquals( $user['pass'], "12345", 0, "abcd" );
    }

}
?>

File:UserTest.php


<?php
require_once('User.php');
require_once(
'PHPUnit2/Framework/TestCase.php');
require_once(
'PHPUnit2/Framework/Test.php');


class
UserTest extends PHPUnit2_Framework_TestCase {
    private
$user;

    public function
setUp() {
        
$this->user = new User( "bob williams",
                                
"bob@example.com",
                                
"fantopedia" );
    }
    
    public function  
testGetMail() {
        
$mail = $this->user->getMail();
        
$this->assertType(  "string", $mail );
        
$this->assertEquals(  "bob@example.com", $mail );
    }
}

?>

File:ValidatorTest.php


<?php
require_once('UserStore.php');
require_once(
'Validator.php');
require_once(
'PHPUnit2/Framework/TestCase.php');


class
ValidatorTest extends PHPUnit2_Framework_TestCase {
    private
$validator;

    public function
setUp() {
        
$store = new UserStore();
        
$store->addUser(  "bob williams", "a@b.com", "12345" );
        
$this->validator = new Validator( $store );
    }

    public function
testValidate_WrongPass() {
        
$this->assertFalse(
            
$this->validator->validateUser( "a@b.com", "wrong" ) );
    }

    public function
testValidate_CorrectPass() {
        
$this->assertTrue(
            
$this->validator->validateUser( "a@b.com", "12345" ) );
    }

}

?>

File:User.php


<?php

class User {
    private
$name;
    private
$mail;
    private
$pass;

    function
__construct( $name, $mail, $pass ) {
        
$this->name       = $name;
        
$this->mail       = $mail;
        
$this->pass       = $pass;
    }

    function
getMail() {
        return
$this->mail;
    }
}
?>

File:UserStore.php


<?php

class UserStore {
    private
$users = array();
    function
addUser( $name=null, $mail=null, $pass=null ) {
        if (
is_null( $name ) || is_null( $mail ) || is_null( $pass ) ) {
            return
false;
        }

        if (
strlen( $pass ) < 5 ) {
            throw new
Exception(
                
"Password must have 5 or more letters");
        }

        
$this->users[$mail] = array( 'pass' => $pass,
                                     
'mail' => $mail,
                                     
'name' => $name );

        return
true;
    }

    function
getUser( $mail ) {
        return (
$this->users[$mail] );
    }
}

?>

File:Validator.php


<?php
class Validator {
    private
$store;
    public function
__construct( UserStore $store ) {
        
$this->store = $store;
    }

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

    public function
validateUser( $mail, $pass ) {
        if ( !
is_array($user = $this->store->getUser( $mail )) ) {
            return
false;
        }
        if (
$user['pass'] == $pass ) {
            return
true;
        }
        return
false;
    }
}
?>

File:cli-dialekt.php


<?php
require_once( "Dialekt.php" );
print
"This is the Dialekt command line interface!\n";
?>

File:alig.txt



File:dalek.txt



File:AliG.php


<?php
print "I am a Ali G\n";
?>

File:Dalek.php


<?php
print "I am a Dalek\n";
?>

File:Dialekt.php


<?php
/*
* Use this from PHP scripts, for a CLI implementation use
* @bin_dir@/dialekt
*/

require_once("PEAR.php");
class
Dialekt extends PEAR {
    const
DIALEKT_ALIG=1;
    const
DIALEKT_DALEK=2;

    function
__construct() {
        
parent::PEAR();
    }

    public static function
getDialekt( $int_dia ) {
        return
PEAR::RaiseError( "bum",  444 );     
    }    
}

$ret = Dialekt::getDialekt(2);
if (
PEAR::isError( $ret ) ) {
    print
"message:    ". $db->getMessage()   ."\n";
    print
"code:       ". $db->getCode()      ."\n\n";
    print
"Backtrace:\n";
    
    foreach (
$db->getBacktrace() as $caller ) {
        print
$caller['class'].$caller['type'].$caller['function']."() ";
        print
"line ".$caller['line']."\n";
    }
}
?>

File:package.xml


<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
<package version="1.0">
    <name>dialekt</name>
    <summary>    
               A package for translating text and web pages
               into silly tones of voice
    </summary>
    <description>
               Be the envy of your friends with this
               hilarious dialect translator. Easy to extend
               and altogether delightful.
    </description>
    <maintainers>
    <maintainer>
        <user>bibble</user>
        <name>Matt Zandstra</name>
        <email>matt@example.com</email>
        <role>developer</role>
    </maintainer>
    </maintainers>

    <release>
        <version>0.2</version>
        <date>2004-01-01</date>
        <license>PHP License</license>
        <state>beta</state>
        <notes>initial work</notes>
        <filelist>
            <file role="php" name="cli-dialekt.php" />

            <file role="php" name="Dialekt.php">
                <replace type="pear-config" from="@bin_dir@" to="bin_dir"/>
            </file>

            <file role="script"
                platform="(.*nix|.*nux)"
                install-as="dialekt"
                name="script/dialekt.sh">
                <replace type="pear-config" from="@php_dir@" to="php_dir"/>
                <replace type="pear-config" from="@bin_dir@" to="bin_dir"/>
                <replace type="pear-config" from="@php_bin@" to="php_bin"/>
            </file>

            <file role="script"
                platform="windows"
                name="script/dialekt.bat">
                <replace type="pear-config" from="@php_dir@" to="php_dir"/>
                <replace type="pear-config" from="@bin_dir@" to="bin_dir"/>
                <replace type="pear-config" from="@php_bin@" to="php_bin"/>
            </file>

            <file role="php" name="Dialekt.php">
                <replace type="pear-config" from="@bin_dir@" to="bin_dir"/>
                <replace type="pear-config" from="@php_bin@" to="php_bin"/>
            </file>

<!--
            
            <file role="php" name="Dialekt/Dalek.php" />
            <file role="php" name="Dialekt/AliG.php" />
            <file role="data"
                    install-as="dalek" name="data/dalek.txt" />
            <file role="data"
                    install-as="alig" name="data/alig.txt" />
-->
            <dir name="/Dialekt" role="php">
                <file name="Dalek.php" />
                <file name="AliG.php" />
            </dir>

            <dir name="data" role="data">
                <file install-as="dalek" name="dalek.txt" />
                <file install-as="alig" name="alig.txt" />
            </dir>
        </filelist>
        <deps>
        <dep type="php" rel="ge" version="5.0.0"/>
        <dep type="pkg" rel="ge" version="10.5" optional="yes">DB</dep>
<!--        <dep type="pkg" rel="ge" version="10.5">Fandango</dep> -->
        </deps>
    </release>
</package>

File:dialekt.bat


#!/bin/sh

exec @php_bin@ -d include_dir=@php_dir@ @php_dir@/dialekt_cli.php "$@"

File:dialekt.sh


#!/bin/sh

exec @php_bin@ -d include_dir=@php_dir@ @php_dir@/dialekt_cli.php "$@"

File:generate.php


<?php
require_once('PEAR/PackageFileManager.php');
$pkg_man = new PEAR_PackageFileManager();
$e = $pkg_man->setOptions(
    array(
    
'baseinstalldir'     => '/',
    
'version'            => '0.1',
    
'packagedirectory'   => '.',
    
'simpleoutput'       =>  true,
    
'packagefile'        => 'test.xml',
    
'state'              => 'beta',
    
'package'            => 'dialekt',
    
'summary'            => 'A package for translating text '.
                            
'and web pages into silly tones '.
                            
'of voice',
    
'description'        => 'Be the envy of your friends with '.
                            
'this hilarious dialect translator. '.
                            
'Easy to extend and altogether'.
                            
'delightful.',
    
'notes'              => 'autogenerated build',
    
'dir_roles'          =>  array( 'script' => 'script',
                                    
'data' => 'data'),
    
'installas'          =>  array( 'data/alig.txt' => 'alig',
                                    
'data/dalek.txt' => 'dalek',
                                    
'script/dialekt.bat' => 'dialekt',
                                    
'script/dialekt.sh' => 'dialekt',
                            )
    )
);

$pkg_man->addMaintainer (
    
'mattz', 'developer',
    
'Matt Zandstra', 'matt@example.com');

$pkg_man->addPlatformException('script/dialekt.bat', 'windows');
$pkg_man->addPlatformException('script/dialekt.sh', 'linux');

$pkg_man->addReplacement(
    
'Dialekt.php', 'pear-config',
    
'@bin_dir@', 'bin_dir');
$pkg_man->addReplacement(
    
'script/dialekt.sh', 'pear-config',
    
'@php_bin@', 'php_bin');
$pkg_man->addReplacement(
    
'script/dialekt.sh', 'pear-config',
    
'@bin_dir@', 'bin_dir');
$pkg_man->addReplacement(
    
'script/dialekt.sh', 'pear-config',
    
'@php_dir@', 'php_dir');

if (
$_SERVER['argv'][1] == 'make') {
    
$e = $pkg_man->writePackageFile();
} else {
    
$e = $pkg_man->debugPackageFile();
}

if (
PEAR::isError($e)) {
    echo
$e->getMessage();
    die();
}
?>

File:peardb.php


<?php
require_once("DB.php");

function
connect() {

$dsn = "sqlite://./test.db";    
$db = DB::connect($dsn);

return
$db;
}
$db = connect();

if (
PEAR::isError( $db ) ) {
    print
"message:    ". $db->getMessage()   ."\n";
    print
"code:       ". $db->getCode()      ."\n\n";
    print
"Backtrace:\n";
    
    foreach (
$db->getBacktrace() as $caller ) {
        print
$caller['class'].$caller['type'].$caller['function']."() ";
        print
"line ".$caller['line']."\n";
        
print_r( $caller );
    }
    die;
}

//drop and recreate table 'scores'
$db->query( "DROP TABLE scores" );
$db->query( "CREATE TABLE scores (  id INT PRIMARY KEY,
                                    name varchar(255),
                                    score INT )"
);

//add some rows
foreach ( array(
            array(
'harry', 44),
            array(
'mary', 66 ) ) as $row ) {
    
$id = $db->nextId('score_sequence');
    
$ret = $db->query( "insert into scores values( $id, '$row[0]', $row[1])" );
}

// output the rows
$query_result = $db->query( "SELECT * FROM scores");
while (
$row = $query_result->fetchRow( DB_FETCHMODE_ASSOC ) ) {
    print
"row: {$row['id']} {$row['name']} {$row['score']}\n";
}

$query_result->free();
$db->disconnect();

?>

File:build.xml


<?xml version="1.0"?>
<!-- build xml -->

<project name="megaquiz"
         default="main"
         basedir=".">

    <target name="main">
        <echo>name:     ${phing.project.name}</echo>
        <echo>base:     ${project.basedir}</echo>
        <echo>start:    ${application.startdir}</echo>
        <echo>home:     ${user.home}</echo>
        <echo>pass:     ${env.DBPASS}</echo>
    </target>

</project>

File:build.xml.passwordprompt


<?xml version="1.0"?>
<!-- build xml -->

<project name="megaquiz"
         default="main"
         basedir=".">

    <target name="setpass" unless="dbpass">
        <input
               propertyName="dbpass"
               message="You don't seem to have set a db password"
               defaultValue="default"
               promptChar=" >"
        />
    </target>
<!--
-->
    <target name="main" depends="setpass">
       <echo>pass:     ${dbpass}</echo>
    </target>

    <target name="clean">
        <delete dir="build" />
    </target>


</project>

File:build.xml.properties


<?xml version="1.0"?>
<!-- build xml -->

<project name="megaquiz"
         default="main"
         basedir=".">

    <target name="main">
        <echo>name:     ${phing.project.name}</echo>
        <echo>base:     ${project.basedir}</echo>
        <echo>start:    ${application.startdir}</echo>
        <echo>home:     ${user.home}</echo>
        <echo>pass:     ${env.DBPASS}</echo>
    </target>

</project>

File:build.xml.targetchain


<?xml version="1.0"?>
<!-- build xml -->
                                                                                
<project name="megaquiz"
         default="main"
         basedir=".">
    <target name="runfirst"
            description="The first target" />
    <target name="runsecond"
            depends="runfirst"
            description="The second target" />
    <target name="main"
            depends="runsecond"
            description="The main target" />
</project>

File:Command.php


<?php



abstract class Command {


    abstract function
execute( CommandContext $context );
}


?>

File:CommandContext.php


<?php




class CommandContext {

    public
$applicationName;


    private
$params = array();


    private
$error = "";

    function
__construct( $appname ) {
        
$this->params = $_REQUEST;
        
$this->applicationName = $appname;
    }

    function
addParam( $key, $val ) {
        
$this->params[$key]=$val;
    }

    function
get( $key ) {
        return
$this->params[$key];
    }

    function
setError( $error ) {
        
$this->error = $error;
    }

    function
getError() {
        return
$this->error;
    }
}

?>

File:FeedbackCommand.php


<?php



require_once( "Command.php" );


class
FeedbackCommand extends Command {

    function
execute( CommandContext $context ) {
        
$msgSystem = ReceiverFactory::getMessageSystem();
        
$email = $context->get( 'email' );
        
$msg = $context->get( 'pass' );
        
$topic = $context->get( 'topic' );
        
$result = $msgSystem->despatch( $email, $msg, $topic );
        if ( !
$result ) {
            
$this->context->setError( $msgSystem->getError() );
            return
false;
        }
        
$context->addParam( "user", $user );
        return
true;
    }
}


?>

File:LoginCommand.php


<?php



require_once( "Command.php" );
require_once(
"quiztools/AccessManager.php" );


class
LoginCommand extends Command {

    function
execute( CommandContext $context ) {
        
$manager = ReceiverFactory::getAccessManager();
        
$user = $context->get( 'username' );
        
$pass = $context->get( 'pass' );
        
$user = $manager->login( $user, $pass );
        if ( !
$user ) {
            
$this->context->setError( $manager->getError() );
            return
false;
        }
        
$context->addParam( "user", $user );
        return
true;
    }
}
?>

File:Config.php


<?php


class Config {
    public
$dbname ="megaquiz";
    public
$dbpass ="";
    public
$dbhost ="localhost";
}

File:Config.php


<?php

class Config {
    public
$dbname ="@dbname@";
    public
$dbpass ="@dbpass@";
    public
$dbhost ="@dbhost@";
}

File:description.txt


jijkj

File:FinishedTest.php


jkjkj

File:Tree.php


kjx

File:TreeTest.php


kjkj

File:User.php


<?php
<<<<<<< User.php


=======


>>>>>>>
1.2
class User {}
?>

File:User_test.php


kksj

File:AccessManager.php


<?php



require_once("quizobjects/User.php");


class
AccessManager {
    function
login( $user, $pass ) {
        
$ret = new User( $user );
        return
$ret;
    }

    function
getError() {
        return
"move along now, nothing to see here";
    }
}


class
ReceiverFactory {
    static function
getAccessManager() {
        return new
AccessManager();
    }
}

?>

File:build.xml


<?xml version="1.0"?>

<project name="megaquiz" default="build" basedir=".">
    <property name="dbname"  value="megaquiz" override="true" />
    <property name="dbpass"  value="" override="true" />
    <property name="dbhost" value="localhost" override="true" />

    <property name="src" value="./src" />
    <property name="build" value="./build" />
    <property name="projname" value="${phing.project.name}" />
    <property name="installbase"    value="${env.HOME}/htdocs/${projname}"  override="true" />
    <property name="install_lib"    value="${installbase}/lib"  override="true" />
    <property name="install_config" value="${installbase}/config"  override="true" />
    <property name="install_view"   value="${installbase}/view"  override="true" />

    <fileset dir="${src}/lib" id="srclib">
        <exclude name="CVS" />
    </fileset>

    <target if="dbname" name="setupconfig">
        <copy todir="${build}/lib/config">
            <filterchain>
                <stripphpcomments />
                <replacetokens>
                    <token key="dbname" value="${dbname}" />
                    <token key="dbhost" value="${dbhost}" />
                    <token key="dbpass" value="${dbpass}" />
                </replacetokens>
            </filterchain>
            <fileset dir="${src}/config">
                <exclude name="CVS" />
            </fileset>
        </copy>
    </target>

    <target name="install" depends="build">
        <copy todir="${install_lib}">
            <fileset dir="${build}/lib" />
        </copy>
    </target>


    <target name="build" depends="setupconfig">
        <copy todir="${build}/lib">
            <filterchain>
                <stripphpcomments />
            </filterchain>

            <fileset refid="srclib"/>
        </copy>
    </target>

    <target name="clean">
        <echo>Cleaning out build directory</echo>
        <delete dir="${build}" />
    </target>

    <target name="complete" depends="clean,build"/>

</project>

File:Config.php


<?php

/*
* Quick and dirty Conf class
*
*/
class Config {
    public
$dbname ="@dbname@";
    public
$dbpass ="@dbpass@";
    public
$dbhost ="@dbhost@";
}

File:Command.php


<?php
/**
* @license   http://www.example.com Borsetshire Open License
* @package   command
*/

/**
* Defines core functionality for commands.
* Command classes perform specific tasks in a system via
* the {@link execute()} method
*
* @package command
* @author  Clarrie Grundie
* @copyright 2004 Ambridge Technologies Ltd
*/
abstract class Command {

/**
* Perform the key operation encapsulated by the class.
* Command classes encapsulate a single operation. They
* are easy to add to and remove from a project, can be
* stored after instantiation and execute() can then be  
* invoked at leisure.
* @param  $context {@link CommandContext} Shared contextual data
* @return bool     false on failure, true on success
* @uses CommandContext
* @link http://www.example.com More info
*/
    
abstract function execute( CommandContext $context );
}


?>

File:CommandContext.php


<?php
/**
* @license   http://www.example.com Borsetshire Open License
* @package   command
*/

/**
* Encapsulates data for passing to, from and between Commands.
* Commands require disparate data according to context. The
* CommandContext object is passed to the {@link Command::execute()}
* method, and contains data in key/value format. The class
* automatically extracts the contents of the $_REQUEST
* superglobal.
*
* @package command
* @author  Clarrie Grundie
* @copyright 2004 Ambridge Technologies Ltd
*/

class CommandContext {
/**
* The application name.
* Used by various clients for error messages, etc.
* @var string
*/
    
public $applicationName;

/**
* Encapsulated Keys/values.
* This class is essentially a wrapper for this array
* @var array
*/
    
private $params = array();

/**
* An error message.
* @var string
*/
    
private $error = "";

    function
__construct( $appname ) {
        
$this->params = $_REQUEST;
        
$this->applicationName = $appname;
    }

    function
addParam( $key, $val ) {
        
$this->params[$key]=$val;
    }

    function
get( $key ) {
        return
$this->params[$key];
    }

    function
setError( $error ) {
        
$this->error = $error;
    }

    function
getError() {
        return
$this->error;
    }
}

?>

File:FeedbackCommand.php


<?php
/**
* @license   http://www.example.com Borsetshire Open License
* @package   command
*/

/**
* includes
*/
require_once( "Command.php" );

/**
* @package command
*/
class FeedbackCommand extends Command {

    function
execute( CommandContext $context ) {
        
$msgSystem = ReceiverFactory::getMessageSystem();
        
$email = $context->get( 'email' );
        
$msg = $context->get( 'pass' );
        
$topic = $context->get( 'topic' );
        
$result = $msgSystem->despatch( $email, $msg, $topic );
        if ( !
$result ) {
            
$this->context->setError( $msgSystem->getError() );
            return
false;
        }
        
$context->addParam( "user", $user );
        return
true;
    }
}


?>

File:LoginCommand.php


<?php
/**
* @license   http://www.example.com Borsetshire Open License
* @package   command
*/

/**
* includes
*/
require_once( "Command.php" );
require_once(
"quiztools/AccessManager.php" );

/**
* @package command
*/
class LoginCommand extends Command {

    function
execute( CommandContext $context ) {
        
$manager = ReceiverFactory::getAccessManager();
        
$user = $context->get( 'username' );
        
$pass = $context->get( 'pass' );
        
$user = $manager->login( $user, $pass );
        if ( !
$user ) {
            
$this->context->setError( $manager->getError() );
            return
false;
        }
        
$context->addParam( "user", $user );
        return
true;
    }
}
?>

File:Config.php


<?php

class Config {
    public
$dbname ="@dbname@";
    public
$dbpass ="@dbpass@";
    public
$dbhost ="@dbhost@";
}

File:description.txt


jijkj

File:FinishedTest.php


jkjkj

File:Tree.php


kjx

File:TreeTest.php


kjkj

File:User.php


<?php
/**
* @package  quizobjects
*/

/**
* @license   http://www.example.com Borsetshire Open License
* @package  quizobjects
*/

>>>>>>> 1.2
class User {}
?>

File:User_test.php


kksj

File:AccessManager.php


<?php
/**
* @license   http://www.example.com Borsetshire Open License
* @package quiztools
*/

/**
* includes
*/
require_once("quizobjects/User.php");

/**
* @package quiztools
* Handles user access
*/
class AccessManager {
    function
login( $user, $pass ) {
        
$ret = new User( $user );
        return
$ret;
    }

    function
getError() {
        return
"move along now, nothing to see here";
    }
}

/**
* @package quiztools
*/
class ReceiverFactory {
    static function
getAccessManager() {
        return new
AccessManager();
    }
}

?>

File:main.php


<?php
// ...
?>

File:index.html


<!-- ... -->

File:cr_index.php


<?php /*

********************************************************************
* Module: index.php
* Author: Mihails Bogdanovs
*
* Goal:   To organize all examples from the PHP5 patterns book for
*         convenient use during lectures' time.
* Parameters: -
* Calls:      -
********************************************************************/

//********************************************************************
function processDirs( $cur_path, $cur_dir, $level, &$links, &$body )
{
  
$dp = opendir( $cur_dir );
  if ( !
$dp ) {return;}

  while ( (
$file_name = readdir($dp)) !== FALSE ) {
    if (
$file_name{0} == '.' ) {continue;}
    if (
$file_name == 'cr_index_ru.php' ) {continue;}

    if (
is_dir( $cur_path. $file_name ) ) {
      if (
$level == 0 ) {
      
$links .= "<hr>\n";
      }
      
$links .= str_repeat( '  ', $level ). $file_name ."/\n";
      
processDirs( $cur_path. $file_name. '/', $cur_path. $file_name, $level+1, $links, $body );
      continue;
    }

    
$fname = str_replace( './', '', $cur_path. $file_name );
    
$fname = str_replace( '/', '_', $fname );
    
$links .= str_repeat( '  ', $level ). "<a href='#".$fname."'>".$file_name."</a>\n";

    
$body .= "<h2><a name='".$fname."'>File:".
             
$file_name."</a></h2>\n";

    
$body .= "<table><tr><td bgcolor='F0F0F0'>\n<pre>";

    
$prog_txt = show_source( $cur_path. $file_name, TRUE );

    
$body .= preg_replace("/".chr(9)."/", "  ", $prog_txt);

    
$body .= "</pre></td></tr></table>\n";
  }
  
closedir($dp);
}

?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <title>Examples from PHP5 patterns book.</title>
  <meta http-equiv="Content-Type"
        content="text/html; charset=windows-1257">
  <style>
    <!--
      pre {font-size:110%; font-weight:bold}

      pre.links {font-size:80%; font-weight:bold}
    -->
  </style>
</head>

<body>
  <h1>Copy of materials from <i>Matt Zandstra</i> book
      "<a href="http://www.apress.com/book/bookDisplay.html?bID=358">PHP
      5 Objects, Patterns, and Practice</a>"</h1>

<?php
  $links
= "<pre class='links'>\n";
  
$body = "";

  
processDirs( './', '.', 0, $links, $body );

  
$links .= "</pre>\n<hr>\n";

  print(
$links);
  print(
$body);
?>
</body>
</html>