Thursday, February 28, 2013

Dynamic Web Application

You can easily build a web application with an Object Relational Bridge (O.R.B). The O.R.B should handle the connection and transformation of data to/from the database SQL queries, the request from the web server HTTP Request querystring and display data from the O.R.B with displayers. I started a prototype in php back in 2004.

The Relational language SQL looks like

 select DOC_CONTENT from DOCUMENT_EN;  

it's better to generate the query with an O.R.B and object model such as

 // Main Database  
 $en = new DBModel("en","en");  
 $en->setConnection ($GLOBALS['config_class']->getProperty('en.server'),  
               $GLOBALS['config_class']->getProperty('en.user'),  
               $GLOBALS['config_class']->getProperty('en.password'),  
               $GLOBALS['config_class']->getProperty('en.db'));  
 // Document Table  
 $status = array (1=>"Draft",2=>"Publish",3=>"Archive");  
 $document = new DBTable("document","DOCUMENT_EN");  
 $document->addField ("id", new DBNumberKeyField ("id","DOC_ID",true));  
 $document->addField ("name", new DBTextField ("name","DOC_NAME",true));  
 $document->addField ("subject", new DBTextField ("subject","DOC_SUBJECT",true));  
 $document->addField ("content", new DBWikiField ("content","DOC_CONTENT",true));  
 $document->addField ("status", new DBStaticListField ("status","DOC_STATUS",$status,true));  
 $document->addField ("owner", new DBListField ("owner","DOC_OWNER","SELECT USR_ID as id, USR_FULLNAME as label FROM USER_EN",true));  
 $document->addField ("modifier", new DBListField ("modifier","DOC_MODIFIER","SELECT USR_ID as id, USR_FULLNAME as label FROM USER_EN",true));
 $document->addField ("creationdate",new DBDateField ("creationdate","DOC_CREATION_DATE",true));  
 $date_field = new DBDateField ("modificationdate","DOC_MODIFICATION_DATE",true);  
 $date_field->setValue (date ("Y-m-d H:i:s"));  
 $document->addField ("modificationdate",$date_field);  
 $document->setColumns(array("document_id","document_subject","document_status","document_owner"));  
 $document->addJoinField ("documentuser","id","did");  
 $document->addJoinField ("documentgroup","id","did");  
 ...  
 $en->addTable("document",$document);  


Obviously, you need an index page to access the web application. This index page will only use the O.R.B to handle the request and display the information or actions. Everything related to the website will be data of the O.R.B: css, menu, header, footer, plugins and pages content which means that once you have made the O.R.B, you never update the source code but you interact with it. An example is the recent changes plugin use by the web application. The plugin is a wiki page which contains runtime php code store in the database and call by the DbWikiField of the O.R.B when asked by another page.

The innovation is the DbWikiField

 

 require_once("db/dbtextfield.php");  
 require_once("util/wiki2xhtml.php");  
 require_once("db/dbcriteria.php");  
 include "plugins/TablePlugin.php";  

...

 /**  
  * CALLBACK FUNCTIONS  
  **/   
 /**  
  *  function eval php code within a wiki page  
  *  
  *  @param string      Php Code  
  **/    
 function eval_buffer($string) {  
   ob_start();  
   eval("$string[2];");  
   $ret = ob_get_contents();  
   ob_end_clean();  
   return $ret;  
 }   

...

class DBWikiField extends DBTextField 
  
  ...  
  

  function displayView ($table,$sql_row,$model,$prefix) {  
   $in = $this->get($table,$sql_row);  
   if ($this->simplified == false) {  
    $in = preg_replace_callback("/(<\?source)(.*?)source\?>/si","eval_phptag",$in);  
    $in = preg_replace_callback("/(<\?\s)(.*?)\s\?>/si","eval_buffer",$in);   
    $in = preg_replace_callback("/(<\?macro\s)(.*?)\smacro\?>/si","eval_buffer",$in);  
    $in = preg_replace_callback("/(<\?table)(.*?)table\?>/si","eval_table",$in);  
    if (preg_match('/(.*)(<no_wiki_parsing>)(.*)/',$in)) {  
     $in = preg_replace_callback("/(<no_wiki_parsing>)/si","eval_removetag",$in);   
     $this->setWikiParsing(false);  
    }  
   }  
   if ($this->wiki_parsing == true) {   
    $in = $this->wiki->transform($in);  
   }  
   if ($this->simplified == false) {  
    $in = preg_replace_callback("/(<plugin_)(.*?)>/si","eval_phpplugin",$in); # Parse plugin  
    $in = preg_replace_callback("/(<source_)(.*?)>/si","eval_phpsource",$in); # ADD BY <?source  
    $in = preg_replace_callback("/(<filesource_)(.*?)>/si","eval_phpfilesource",$in); # Parse Highlight from file  
    $in = preg_replace_callback("/(<plugindoc_)(.*?)>/si","eval_phpplugindoc",$in); # Parse Highlight from file  
   }  
   return $in;   
  }  


The DbWikiField constraints are in what we call a SandBox (See wikipedia Sandbox) because you can put programmable content in the field. A sandbox limits the programming right of a user. For example, Javascript client which runs on your computer when you surf the internet with your browser is a Sandbox. It's a limited language so that nothing really bad happens to the end user against his own will. I didn't implement a sandbox for this prototype. The Sandbox limits Global scopes in your programs for obvious safety and security reasons meanwhile the O.R.B ensures the addressing of the diversity of your production database.

For the database, you need to consider a Star Schema Database because your ORB can automatically link tables to build the queries without loops (There is only one way from one table to another in a star schema database). You can read this white paper from Craig Utley which put forward another advantage of Star Schema Database for large volume of data in read only mode and aggregated data.

Related Link
- Apache Torque

No comments:

Post a Comment