class ActivityTest extends PHPUnit_Framework_TestCase
{

    public function testNewPost()
    {
        $userId = 60;
        $title = "Lorem Ipsum";
        $contents = "Lorem ipsum dolor sit amet";
        $date = 1356173771;

        $a = new Activity($userId, $title, $contents, $date);

        $this->assertEquals($userId, $a->getUserId());
        $this->assertEquals($title, $a->getTitle());
        $this->assertEquals($contents, $a->getContents());
        $this->assertEquals($date, $a->getDate());
    }
}

Class Activity extends Article
{
    /**
     * Post a new activity
     */
    public function newPost($userId, $title, $contents, $date)
    {
        $newInfo = array();
        $newInfo['userId'] = $userId;
        $newInfo['title'] = $title;
        $newInfo['contents'] = $contents;
        $newInfo['date'] = $date;

        $this->fromArray($newInfo);
        return $this;
    }
}
 
Class Article extends DBObject
{

    function __construct($source = null)
    {   
        echo "Article __construct called\n";
        $args = func_get_args();
        if (count($args) > 1) {
            call_user_func_array(array($this, 'newPost'), $args);
        } else {
            parent::__construct($args);
        }   
    }  
}

/**
 * The class that manages all interfacing between models and the
 * database. By extending this, all models can be created easily 
 * using their id or a sql string.
 * All getters and setters are generated automatically.
 */
Class DBObject
{
    public $info;

    /**
     * Construct a new database model object. You can pass either a key-value array
     * or an sql query to the constructor.
     * @param Array Key-Value based array containing all info
     * @param Sql query where all values are replaced by %s %i etc., and provided
     * as extra arguments.
     */
    function __construct($source = null)
    {
        echo "DBObject constructed called\n";
        if (is_array($source))
            $this->fromArray($source);
        else if ($source != null) {
            $args = func_get_args();
            $this->fromSql($args);
        }

        if (!isset($this->info))
            $this->info = Array();

        $this->changed = false;
        $this->changeSet = Array();
    }
 /**
     * Create an object from an sql query of the form:
     *  "select [] from [table] where name=%s and id=%i', 'Steenman', 60"
     * Values are automatically escaped and sanitized.
     */
    function fromSql()
    {
        $args = func_get_args();
        $arr = call_user_func_array(array('DB', 'queryFirstRow'), $args[0]);
        $this->fromArray($arr);
    }

    /**
     * Create the object from a key-value array, e.g. if you want to test
     * things. Called by fromSql after querying.
     */
    function fromArray($array)
    {
        $this->info = $array;
    }

    /**
     * Write the object to the database. Only writes if changed() is true.
     */
    function write($table = null, $where = null)
    {
        if (!$this->changed)
            return;

        if (!isset($this->info->id)) { // Completely new object
            DB::insert($table ? $table : $this->table, $this->info);
            $this->setId(DB::insertId());
        }

        var_dump($this->changeSet);

        DB::update($table ? $table : $this->table, $this->changeSet, "id=%i", $this->getId());
    }

    /**
     * * Dynamic getters and setters than maintain getX and setX formati. They can be overwritten
     * * if custom processing is needed. Setters also mark the DBObject as changed, enabling writing
     * * it.

     * * if custom processing is needed. Setters also mark the DBObject as changed, enabling writing
     * * it.
     * *
     * * @param string $method
     * * @param array $arguments
     * * @return mixed
     * */
    function __call($method, $arguments) {
        #Is this a get or a set
        $prefix = strtolower(substr($method, 0, 3));

        #What is the get/set class attribute
        if (!($prefix == "get" || $prefix == "set")) {
            $prefix = "get";
            $property = strtolower(preg_replace('/([A-Z])/', '_$1', lcfirst($method)));
        } else {
            $property = preg_replace('/([A-Z])/', '_$1', lcfirst(substr($method, 3)));
            $property = strtolower($property);
        }
        if (empty($property) || empty($prefix)) { #Did not match a get/set call
            throw New Exception("Calling a get/set without a method: $method");
        }

        echo "Calling $prefix $property\n";
        var_dump($this->info);
        echo "\n";

        #Check if the get/set paramter exists within this class as an attribute
        $match=false;
        foreach($this->info as $class_var=>$class_var_value){
            echo "Comparing ".strtolower($class_var)." and ".strtolower($property)."\n";
            if(strtolower($class_var) == strtolower($property)){
                $property = $class_var;
                $match=true;
            }
        }

        #Get attribute
        if ($match && $prefix == "get" && (isset($this->info[$property]) || is_null($this->info[$property]))) {
            return $this->info[$property];
        } #Set
        else if ($prefix == "set") {
            $this->info[$property] = $arguments[0];
        } else {
            throw new Exception("Calling a get/set method that does not exist: $property");
        }
        return null;
    }
}