--- /dev/null
+<?php
+// +----------------------------------------------------------------------
+// | PHP Source
+// +----------------------------------------------------------------------
+// | Copyright (C) 2009 by Konrad Rosenbaum <konrad@silmor.de>
+// +----------------------------------------------------------------------
+// |
+// | Copyright: See COPYING file that comes with this distribution
+// +----------------------------------------------------------------------
+//
+
+$AUTOCLASS["WobTable"]="inc/wbase/table.php";
+$AUTOCLASS["WobSchemaBase"]="inc/wbase/schema.php";
+$AUTOCLASS["WobTransactionBase"]="inc/wbase/transaction.php";
+$AUTOCLASS["WobXmlException"]="inc/wbase/exception.php";
+$AUTOCLASS["WObject"]="inc/wbase/object.php";
+
+function __autoload($cname)
+{
+ global $AUTOCLASS;
+ if(isset($AUTOCLASS[$cname]))
+ require_once $AUTOCLASS[$cname];
+}
+
+?>
--- /dev/null
+<?
+//
+// PHP Implementation: exception
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+class WobXmlException extends Exception {};
+
+?>
\ No newline at end of file
--- /dev/null
+<?php
+// +----------------------------------------------------------------------
+// | PHP Source
+// +----------------------------------------------------------------------
+// | Copyright (C) 2009 by Konrad Rosenbaum <konrad@silmor.de>
+// +----------------------------------------------------------------------
+// |
+// | Copyright: See COPYING file that comes with this distribution
+// +----------------------------------------------------------------------
+//
+
+class WObject {
+ protected function __construct(){}
+
+ /**helper function that returns only the elements directly beneith the one given as $root*/
+ public static function elementsByTagName($root,$tag)
+ {
+ $list=array();
+ foreach($root->childNodes as $node){
+ if($node->nodeType == XML_ELEMENT_NODE)
+ if($node->tagName == $tag)
+ $list[]=$node;
+ }
+ return $list;
+ }
+};
+
+?>
--- /dev/null
+<?
+/**This class parses the high-level description of the database structure generated by woc; access it via $dbScheme*/
+class WobSchemaBase {
+ protected static $scheme;
+ protected static $preset;
+ protected static $sversion;
+ protected static $backup;
+
+ function __construct()
+ {
+ }
+
+ /**return the version of this scheme*/
+ public function version(){return $this->sversion;}
+
+ /**return the tables to be created in order*/
+ public function tableNames()
+ {
+ return array_keys($this->scheme);
+ }
+
+ /**returns whether a table exists in the schema*/
+ public function hasTable($t)
+ {
+ return in_array($t,array_keys($this->scheme));
+ }
+
+ /**return the tables that are included in the backup*/
+ public function backupTables()
+ {
+ return $this->backup;
+ }
+
+ /**return the full definition of a table, or false if it does not exist*/
+ public function tableDefinition($tab)
+ {
+ if(!isset($this->scheme[$tab]))
+ return false;
+ return $this->scheme[$tab];
+ }
+
+ /**return the names of all columns of a table, or false if the table does not exist*/
+ public function tableColumns($tab)
+ {
+ if(!isset($this->scheme[$tab]))
+ return false;
+ $r=array();
+ foreach(array_keys($this->scheme[$tab]) as $c)
+ if(substr($c,0,1)!=":")
+ $r[]=$c;
+ return $r;
+ }
+
+ /**return whether the table has this column*/
+ public function tableHasColumn($tab,$col)
+ {
+ return isset($this->scheme[$tab][$col]);
+ }
+
+ /**return default lines of the table for the initialization; returns empty array if there are none*/
+ public function tableDefaults($tab)
+ {
+ if(isset($this->preset[$tab]))return $this->preset[$tab];
+ else return array();
+ }
+
+ /**return the type of a column, or false if it does not exist*/
+ public function columnType($tab,$col)
+ {
+ if(!isset($this->scheme[$tab][$col]))
+ return false;
+ return $this->scheme[$tab][$col][0];
+ }
+
+ /**return the flags of a column, empty array if no flags are set, or false if the column does not exist*/
+ public function columnFlags($tab,$col)
+ {
+ if(!isset($this->scheme[$tab][$col]))
+ return false;
+ $tmp=$this->scheme[$tab][$col];
+ unset($tmp[0]);
+ return array_values($tmp);
+ }
+
+ /**returns true if the given column is of an integer type*/
+ public function isIntColumn($tab,$col)
+ {
+ if(!isset($this->scheme[$tab][$col]))
+ return false;
+ $tpa=explode(":",$this->scheme[$tab][$col][0]);
+ switch($tpa[0]){
+ case "int32":case "seq32":case "int64":case "seq64":case "enum":case "enum32":case "enum64":
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**returns the sequence column name if the table has a sequence, false otherwise*/
+ public function hasSequence($tab)
+ {
+ if(!isset($this->scheme[$tab]))
+ return false;
+ foreach($this->scheme[$tab] as $cl => $def){
+ if($def[0] == "seq32" || $def[0] == "seq64")
+ return $cl;
+ }
+ return false;
+ }
+
+ /**returns true if the given column is of a string type*/
+ public function isStringColumn($tab,$col)
+ {
+ if(!isset($this->scheme[$tab][$col]))
+ return false;
+ $tpa=explode(":",$this->scheme[$tab][$col][0]);
+ switch($tpa[0]){
+ case "string":case "text":
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**returns true if the given column is of a blob type*/
+ public function isBlobColumn($tab,$col)
+ {
+ if(!isset($this->scheme[$tab][$col]))
+ return false;
+ $tpa=explode(":",$this->scheme[$tab][$col][0]);
+ switch($tpa[0]){
+ case "blob":
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**returns true if the given column is of a bool type*/
+ public function isBoolColumn($tab,$col)
+ {
+ if(!isset($this->scheme[$tab][$col]))
+ return false;
+ $tpa=explode(":",$this->scheme[$tab][$col][0]);
+ switch($tpa[0]){
+ case "bool":
+ case "boolean":
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**returns the names of all primary key columns of the table*/
+ public function primaryKeyColumns($tab)
+ {
+ $r=array();
+ //search for direct mark
+ foreach($this->scheme[$tab] as $col=>$def)
+ if(in_array("primarykey",$def))
+ $r[]=$col;
+ //search for special mark
+ if(isset($this->scheme[$tab][":primarykey"]))
+ foreach($this->scheme[$tab][":primarykey"] as $col)
+ if(!in_array($col,$r))
+ $r[]=$col;
+ //return result
+ return $r;
+ }
+};
+?>
\ No newline at end of file
--- /dev/null
+<?
+//
+// PHP Implementation: wob table base class
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+/**thrown by WobTable if a property change is out of range*/
+class ValueOutOfRange extends Exception
+{
+ public function __construct($tab,$col,$val)
+ {
+ $this->message="Value of table '$tab' column '$col' is out of range. Value '$val' not allowed.";
+ }
+};
+
+/**parent class of all tables*/
+abstract class WobTable
+{
+ protected $data;
+ protected $cdata;
+ private $isfromdb;
+ private $table;
+
+ /**constructs a basic table*/
+ protected function __construct(array $data,$isfromdb,$table)
+ {
+ $this->data=array();
+ if($isfromdb)$this->data=$data;
+ else
+ foreach($data as $k=>$d){
+ //silently ignore garbage
+ if(!$this->hasProperty($k))continue;
+ //verify non-garbage
+ $vm="verifyValue".$k;
+ if(method_exists($this,$vm))
+ if(!$this->$vm($d))
+ throw ValueOutOfRange($this->table,$k,$d);
+ //set
+ $this->data[$k]=$d;
+ }
+ $this->isfromdb=$isfromdb;
+ $this->table=$table;
+ $this->cdata=array();
+ }
+
+ /**set properties*/
+ public function __set($name,$value)
+ {
+ //check for property
+ if(!$this->hasProperty($name)){
+ $trace=debug_backtrace();
+ trigger_error("Trying to set undefined property ".$name." in ".$trace[0]['file']." on line ".$trace[0]['line'],E_USER_NOTICE);
+ }
+ //verify value (TODO: what about NULL?)
+ $vm="verifyValue".$name;
+ if(method_exists($this,$vm))
+ if(!$this->$vm($value))
+ throw ValueOutOfRange($this->table,$name,$value);
+ //set
+ $this->cdata[$name]=$value;
+ }
+
+ /**reverts changes to the property*/
+ public function revert($name)
+ {
+ if(!$this->hasProperty($name)){
+ $trace=debug_backtrace();
+ trigger_error("Trying to revert undefined property ".$name." in ".$trace[0]['file']." on line ".$trace[0]['line'],E_USER_NOTICE);
+ }
+ if(array_key_exists($name,$this->cdata))unset($this->cdata[$name]);
+ }
+
+ /**reverts all changes to properties*/
+ public function revertAll()
+ {
+ $this->cdata=array();
+ }
+
+ /**returns the name of the table*/
+ public function tableName(){return $this->table;}
+
+ /**returns whether the table contains a specific column*/
+ public function hasColumn($c)
+ {
+ global $dbScheme;
+ return $dbScheme->tableHasColumn($this->table,$name);
+ }
+
+ /**overridden by woc, returns true if the property exists*/
+ abstract public function hasProperty($c);
+
+ /**returns whether this is an auditable table*/
+ public function isAuditable(){return false;}
+
+ /**overridden by woc, if this an auditable table; used in insert and update*/
+ protected function createAudit(){}
+
+ /**returns the where clause to find this instance (via primary key columns)*/
+ public function where()
+ {
+ global $dbScheme,$db;
+ $r="";
+ $pk=$dbScheme->primaryKeyColumns($this->table);
+ foreach($pk as $c){
+ if($r!="")$r.=" AND ";
+ $r.=$c."=".$db->escapeColumn($this->table,$c,$this->data[$c]);
+ }
+ return $r;
+ }
+
+ /**returns the property/column*/
+ public function __get($name)
+ {
+ //verify name
+ if(!$this->hasProperty($name)){
+ $trace=debug_backtrace();
+ trigger_error("Accessing undefined property ".$name." in ".$trace[0]['file']." on line ".$trace[0]['line'],E_USER_NOTICE);
+ }
+ //return value or null
+ if(array_key_exists($name,$this->cdata))return $this->cdata[$name];
+ if(array_key_exists($name,$this->data))return $this->data[$name];
+ else return null;
+ }
+
+ /**checks whether a column exists*/
+ public function __isset($name)
+ {
+ global $db;
+ //verify name and return true on existence AND notnull
+ if(array_key_exists($name,$this->cdata))return isset($this->cdata[$name]);
+ if(array_key_exists($name,$this->data))return isset($this->data[$name]);
+ else return false;
+ }
+
+ /**unsets column-properties to NULL*/
+ public function __unset($name)
+ {
+ global $dbScheme;
+ //reset to null
+ if($this->hasProperty($name))$this->cdata[$name]=null;
+ }
+
+ /**returns whether any property has changed since the last DB sync*/
+ public function isChanged()
+ {
+ return count($this->cdata)>0;
+ }
+
+ /**returns whether a specific column has changed since the last DB sync*/
+ public function isColumnChanged($c)
+ {
+ return array_key_exists($c,$this->cdata);
+ }
+
+ /**insert the object under a new primary key value into the DB (implicitly calls newKey); returns true on success*/
+ public function insert()
+ {
+ global $dbScheme,$db;
+ $this->isfromdb=false;
+ //create new key
+ $this->newKey();
+ //now insert
+ $data=array();
+ foreach($this->data as $k=>$d)$data[$k]=$d;
+ foreach($this->cdata as $k=>$d)$data[$k]=$d;
+ $r=$db->insert($this->table,$data);
+ if($r===false)return false;
+ $this->isfromdb=true;
+ $this->data=$data;
+ $this->cdata=array();
+ $this->createAudit();
+ //assign primary key if sequence (otherwise newKey has done it)
+ $seq=$dbScheme->hasSequence($this->table);
+ if($seq!==false)
+ $this->data[$seq]=$r;
+ //return success
+ return true;
+ }
+
+ /**generate a new primary key value for insert and marks the object as not yet in the DB; the default sets the primary key to NULL if it is a sequence; call the original first if you overwrite it*/
+ public function newKey()
+ {
+ global $dbScheme;
+ $this->isfromdb=false;
+ $pk=$dbScheme->hasSequence($this->table);
+ if($pk!==false){
+ if(array_key_exists($pk,$this->data))unset($this->data[$pk]);
+ if(array_key_exists($pk,$this->cdata))unset($this->cdata[$pk]);
+ }
+ }
+
+ /**updates the object in the database; returns true on success; fails if it did not come from the DB - use insertOrUpdate in this case; succeeds without asking the database if nothing has changed*/
+ public function update()
+ {
+ if(!$this->isfromdb)return false;
+ if(count($this->cdata)==0)return true;
+ global $db;
+ $succ=$db->update($this->table,$this->cdata,$this->where())!==false;
+ if($succ){
+ foreach($this->cdata as $k=>$d)$this->data[$k]=$d;
+ $this->cdata=array();
+ $this->createAudit();
+ }
+ return $succ;
+ }
+
+ /**updates existing object in the database or inserts it if it does not exist in the DB yet*/
+ public function insertOrUpdate()
+ {
+ if($this->isfromdb)return $this->update();
+ else return $this->insert();
+ }
+
+ /**deletes this instance from the database; returns true if it actually executed*/
+ public function deleteFromDb()
+ {
+ if(!$this->isfromdb)return false;
+ global $db;
+ //obliterate audit data
+ if($this->isAuditable())
+ $db->deleteRows($this->table."_audit",$this->where());
+ //delete data
+ $db->deleteRows($this->table,$this->where());
+ //mark as outsider
+ $this->isfromdb=false;
+ return true;
+ }
+};
+
+?>
\ No newline at end of file
--- /dev/null
+<?
+//
+// PHP Implementation: transaction
+//
+// Description:
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+/**Ancestor of all Transactions*/
+class WobTransactionBase {
+ protected $ainput;
+ protected $tinput;
+ protected $aoutput;
+ protected $toutput;
+
+ protected static $running="";
+
+ static public function getExecutingName(){return self::$running;}
+
+ /**called to determine the correct transaction, aborts the script if there is none.*/
+ static public function getTransactionName(){
+ global $_SERVER;
+ if($_SERVER["REQUEST_METHOD"] != "POST"){
+ header("X-WobResponse-Status: Error");
+ print("<WobResponse status=\"error\"><Error type=\"non-post\">Request is not a POST Request, Aborting.</Error></WobResponse>\n");
+ exit();
+ }
+ if(!isset($_SERVER["HTTP_X_WOBREQUEST"])){
+ header("X-WobResponse-Status: Error");
+ print("<WobResponse status=\"error\"><Error type=\"non-wob\">Request is not a Wob Request, Aborting.</Error></WobResponse>\n");
+ exit();
+ }
+ self::$running=$_SERVER["HTTP_X_WOBREQUEST"];
+ return self::$running;
+ }
+ /**called to determine the session id*/
+ static public function getHeader($hd)
+ {
+ $hd="HTTP_X_".strtoupper(str_replace("-","_",$hd));
+ if(isset($_SERVER[$hd]))return $_SERVER[$hd];
+ else return "";
+ }
+ /**called if the transaction is not known. aborts the script.*/
+ static public function noSuchTransaction()
+ {
+ header("X-WobResponse-Status: Error");
+ print("<WobResponse status=\"error\"><Error type=\"non-wob\">Request is not known, Aborting.</Error></WobResponse>\n");
+ exit();
+ }
+
+ /**called if authentication fails*/
+ public function notAuthenticated(){
+ header("X-WobResponse-Status: Error");
+ print("<WobResponse status=\"error\"><Error type=\"auth\">User is not authenticated or does not have permission to execute this request, Aborting.</Error></WobResponse>\n");
+ exit();
+ }
+
+ /**called if XML parsing fails*/
+ public function xmlParserError(){
+ header("X-WobResponse-Status: Error");
+ print("<WobResponse status=\"error\"><Error type=\"xml\">Error while parsing request XML, Aborting.</Error></WobResponse>\n");
+ exit();
+ }
+
+ /**called for generic exception handling*/
+ public function handleException($ex){
+ header("X-WobResponse-Status: Error");
+ print("<WobResponse status=\"error\"><Error type=\"exception\">".xq($ex->getMessage())."</Error></WobResponse>\n");
+ exit();
+ }
+
+ /**called to abort a transactions flow
+ \param $type \b optional defines the source of the error (should be only one word, defaults to "server")
+ \param $text the human readable text returned to the client
+ */
+ public function abortWithError($text,$type="server"){
+ header("X-WobResponse-Status: Error");
+ print("<WobResponse status=\"error\"><Error type=\"".xq($type)."\">".xq($text)."</Error></WobResponse>\n");
+ exit();
+ }
+
+ /**called internally if a transaction is not implemented*/
+ protected function abortNotImplemented()
+ {
+ $this->abortWithError(tr("Transaction not implemented."));
+ }
+};
+
+?>
\ No newline at end of file