first steps on implementing DB table wrapper in woc
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Mon, 2 Feb 2009 18:19:55 +0000 (18:19 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Mon, 2 Feb 2009 18:19:55 +0000 (18:19 +0000)
git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@259 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

14 files changed:
README
doc/prog_woc.html
wob/basics.wolf
wob/magicsmoke.wolf
wob/order.wolf
wob/user.wolf
woc/phpout.cpp
woc/phpout.h
woc/processor.cpp
woc/processor.h
woc/qtout.cpp
woc/qtout.h
www/inc/wbase/autoload.php
www/inc/wbase/table.php

diff --git a/README b/README
index b8c9ce7..d334a34 100644 (file)
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
-Magic Smoke Ticketing System - README
-=======================================
+Magic Smoke Ticket Sale System - README
+========================================
 
 Magic Smoke was written to keep track of tickets for events (like concerts
 or theatric plays), sell them online or through retailers. It does not keep
@@ -23,22 +23,23 @@ invariant sections, but will be relicensed when SFDL is released by the FSF.
 See COPYING.FDL for details. (COPYING.SFDL contains the current draft of SFDL
 as a preview, but is currently not binding.)
 
-Directory src:
+Directories src, woc, mkdist:
 The CPP-source files are licensed under GPLv3 or at your option any newer version
 of the license. See COPYING.GPL for details.
 
-Directory src/zip
-The ZIP code used by this program was copied from LinTouch and are licensed
+Directory zip
+The ZIP code used by this program was copied from LinTouch and is licensed
 under LGPL v.2.1. See src/zip/README and src/zip/COPYING for details. The
 source has been adapted by Konrad Rosenbaum to work with Qt 4.x instead of
 Qt 3.x.
 
-Directory www:
-The web-code (PHP files) is licensed under GNU AGPLv3 (see COPYING.AGPL for
-details). This excludes the template sub-directory.
+Directory www, wob:
+The web-code (PHP files) and object meta files (*.wolf) are licensed under 
+GNU AGPLv3 (see COPYING.AGPL for details). This excludes the www/template
+sub-directory.
 
 Directories www/template and examples:
-Templates for web-pages (www/template) and examples for ODT and ticket templates
+Templates for web-pages (www/template) and examples for ODF and ticket templates
 (examples) are in the public domain.
 Which means eg. they can be freely modified and then put under any license when
 you create your own web-site using this software.
index d2e8dbc..ca6f426 100644 (file)
@@ -18,6 +18,10 @@ The Web Object Compiler (woc) helps implementing these three-tier architecture i
 </table>
 <i>Three Tier Architecture</i><p>
 
+<h2>Overall File Format</h2>
+
+Woc translates Web Object Language Files (*.wolf) into PHP or C++/Qt code. The wolf files are simple XML syntax.
+
 <h2>Database Abstraction Layer</h2>
 
 The Database Abstraction Layer is the servers lower bound towards the database. It is a simple translation of the database structure into usable PHP objects.
index de63028..f8e0598 100644 (file)
@@ -1,3 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Basic MagicSmoke WOLF
+  - base tables for login etc.
+  -
+  - (c) Konrad Rosenbaum, 2009
+  - this file is protected under the GNU AGPLv3 or at your option any newer
+  - see COPYING.AGPL for details
+  -->
 <Wolf>
        <Table name="host">
                <Column name="hostname" type="string:64" primarykey="yes"/>
index 4073733..f0316be 100644 (file)
@@ -1,14 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Main MagicSmoke WOLF
+  - makes some basic settings and then includes the real object files.
+  -
+  - (c) Konrad Rosenbaum, 2009
+  - this file is protected under the GNU AGPLv3 or at your option any newer
+  - see COPYING.AGPL for details
+  -->
 <Wolf>
        <!-- generic settings -->
        <Project baseDir=".." wobDir="wob"/>
-       <Version comm="0100" needcomm="0100" humanReadable="1.1 alpha">
-               <Svn target="." cacheFile="svn_*.xml"/>
-       </Version>
+       <Version comm="0100" needcomm="0100" humanReadable="1.1 alpha" svnTarget="."/>
        <DataBase instance="db" scheme="dbScheme"/>
        
        <!-- configure output -->
        <QtClientOutput sourceDir="src" subDir="wob" priInclude="wob.pri"/>
-       <PHPServerOutput sourceDir="www" subDir="inc/wob" extension=".php" loader="wobload.php"/>
+       <PHPServerOutput sourceDir="www" subDir="inc/wob" extension=".php" loader="wobload.php" clean="yes"/>
        
        <!-- load and parse class definitions -->
        <Include file="basics.wolf"/>
index 027a336..12bee92 100644 (file)
@@ -1,3 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Order MagicSmoke WOLF
+  - Tables and Comm Objects for Orders, Tickets, Vouchers, etc.
+  -
+  - (c) Konrad Rosenbaum, 2009
+  - this file is protected under the GNU AGPLv3 or at your option any newer
+  - see COPYING.AGPL for details
+  -->
 <Wolf>
        <Table name="order" backup="yes">
                <Column name="orderid" type="seq32" primarykey="yes"/>
index e1e68d1..d01ac53 100644 (file)
@@ -1,3 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- User MagicSmoke WOLF
+  - hmm, should this be merged with basics?
+  -
+  - (c) Konrad Rosenbaum, 2009
+  - this file is protected under the GNU AGPLv3 or at your option any newer
+  - see COPYING.AGPL for details
+  -->
 <Wolf>
        <Class name="User">
                <Property name="name" column="uname" type="astring"/>
index e911c0d..c8b2150 100644 (file)
 
 #include "phpout.h"
 
-WocPHPServerOut::WocPHPServerOut(QString srcDir,QString subDir,QString ext,QString loader){}
-void WocPHPServerOut::finalize(){}
+#include <QDir>
+
+static const QByteArray PHPSTART("<?\n//THIS IS AN AUTOGENERATED FILE, DONT CHANGE!\n\n");
+static const QByteArray PHPEND("\n//END OF AUTOGENERATED FILE\n?>");
+
+static const QByteArray SCHEMASTART("class WobSchema extends WobSchemaBase\n{\nfunction __construct(){\n");
+static const QByteArray SCHEMAEND("}};\n");
+
+WocPHPServerOut::WocPHPServerOut(QString srcDir,QString subDir,QString ext,bool clean)
+{
+       qDebug("Info: creating PHP Server Output Generator.");
+       m_basedir=WocProcessor::instance()->baseDir()+"/"+srcDir;
+       m_subdir=subDir;
+       m_fileext=ext;
+       //cleanup directory (remove normal files, assume remainder is harmless)
+       QDir d(m_basedir+"/"+m_subdir);
+       if(d.exists() && clean){
+               QStringList ent=d.entryList(QDir::Files);
+               for(int i=0;i<ent.size();i++)
+                       d.remove(ent[i]);
+       }
+       //get/create directory
+       if(!d.exists())QDir(".").mkpath(m_basedir+"/"+m_subdir);
+       //create loader
+       m_loader.setFileName(m_basedir+"/"+m_subdir+"/autoload"+m_fileext);
+       if(!m_loader.open(QIODevice::ReadWrite|QIODevice::Truncate)){
+               qDebug("Error: PHP Server Generator - cannot create loader file, deactivating output.");
+               return;
+       }
+       m_loader.write(PHPSTART);
+       //create schema file
+       m_schema.setFileName(m_basedir+"/"+m_subdir+"/schema"+m_fileext);
+       if(!m_schema.open(QIODevice::ReadWrite|QIODevice::Truncate)){
+               qDebug("Error: PHP Server Generator - cannot create DB schema file.");
+               return;
+       }
+       m_schema.write(PHPSTART);
+       m_schema.write(SCHEMASTART);
+       addLoad("WobSchema","schema");
+}
+
+void WocPHPServerOut::finalize()
+{
+       if(m_loader.isOpen()){
+               m_loader.write(PHPEND);
+               m_loader.close();
+       }
+       if(m_schema.isOpen()){
+               m_schema.write(SCHEMAEND);
+               m_schema.write(PHPEND);
+               m_schema.close();
+       }
+}
+
 void WocPHPServerOut::newClass(const WocClass&){}
+
+void WocPHPServerOut::newTable(const WocTable&tbl)
+{
+       if(!m_loader.isOpen())return;
+       //create table file
+       QString fn=m_subdir+"/wt_"+tbl.name()+m_fileext;
+       QFile tf(m_basedir+"/"+fn);
+       if(!tf.open(QIODevice::ReadWrite|QIODevice::Truncate)){
+               qDebug("Error: cannot create PHP table file %s.",fn.toAscii().data());
+               return;
+       }
+       tf.write(PHPSTART);
+       QString code="class WT"+tbl.name()+" extends WobTable\n{\n";
+       //initializer
+       code+="protected function __construct(array $data,$isfromdb){parent::__construct($data,$isfromdb,\""+tbl.name()+"\");}\n";
+       //static get instance
+       code+="public static function getFromDB(...){global $db...;}\n";
+       //automatic resolution of internal foreign keys
+       //reverse resolution of configured foreign keys
+       //write table class
+       code+="};\n";
+       tf.write(code.toAscii());
+       tf.write(PHPEND);
+       tf.close();
+       //extend schema file
+       //create autoloading
+       addLoad("WT"+tbl.name(),"wt_"+tbl.name());
+}
+
+void WocPHPServerOut::addLoad(QString cn,QString fn)
+{
+       QString ld="$AUTOCLASS[\""+cn+"\"]=\""+m_subdir+"/"+fn+m_fileext+"\";\n";
+       m_loader.write(ld.toAscii());
+}
index 8054961..ac7e8eb 100644 (file)
 #ifndef WOC_PHPOUT_H
 #define WOC_PHPOUT_H
 
+#include <QFile>
+
 #include "processor.h"
 
 class WocPHPServerOut:public WocOutput
 {
        public:
-               WocPHPServerOut(QString srcDir,QString subDir,QString ext,QString loader);
+               WocPHPServerOut(QString srcDir,QString subDir,QString ext,bool clean);
        protected:
                virtual void finalize();
                virtual void newClass(const WocClass&);
+               virtual void newTable(const WocTable&);
+       private:
+               QString m_basedir,m_subdir,m_fileext;
+               QFile m_loader,m_schema;
+               
+               void addLoad(QString,QString);
 };
 
 #endif
index c1caa05..c21bbb0 100644 (file)
 #include <QDomElement>
 #include <QProcess>
 
+
+static inline bool str2bool(QString s)
+{
+       bool b;
+       int i=s.toInt(&b,0);
+       if(b)return i?true:false;
+       s=s.toLower();
+       if(s=="yes"||s=="y"||s=="on"||s=="true"||s=="t")return true;
+       return false;
+}
+
 WocProcessor* WocProcessor::inst=0;
 
 WocProcessor::WocProcessor()
@@ -72,9 +83,18 @@ bool WocProcessor::processFile(QString fn)
                QString tn=el.tagName();
                if(tn=="Class"){
                        WocClass cls(el);
-                       if(cls.isValid())
+                       if(cls.isValid()){
+                               m_classes.append(cls);
                                emit newClass(cls);
-                       else
+                       }else
+                               return false;
+               }else
+               if(tn=="Table"){
+                       WocTable tbl(el);
+                       if(tbl.isValid()){
+                               m_tables.append(tbl);
+                               emit newTable(tbl);
+                       }else
                                return false;
                }else
                if(tn=="Project"){
@@ -97,7 +117,7 @@ bool WocProcessor::processFile(QString fn)
                        new WocQtClientOut(el.attribute("sourceDir","."), el.attribute("subDir","qtwob"), el.attribute("priInclude","qtwob.pri"));
                }else
                if(tn=="PHPServerOutput"){
-                       new WocPHPServerOut(el.attribute("sourceDir","."), el.attribute("subDir","phpwob"), el.attribute("extension",".inc"), el.attribute("loader",""));
+                       new WocPHPServerOut(el.attribute("sourceDir","."), el.attribute("subDir","phpwob"), el.attribute("extension",".inc"), str2bool(el.attribute("clean","0")));
                }else
                if(tn=="Version"){
                        if(el.hasAttribute("comm"))
@@ -106,16 +126,11 @@ bool WocProcessor::processFile(QString fn)
                                m_verNeedComm=el.attribute("needcomm");
                        if(el.hasAttribute("humanReadable"))
                                m_verHR=el.attribute("humanReadable");
-                       QDomNodeList nl2=el.elementsByTagName("Svn");
-                       for(int j=0;j<nl2.size();j++){
-                               QDomElement el2=nl2.at(j).toElement();
-                               if(el2.isNull())continue;
-                               if(el2.hasAttribute("target"))
-                                       m_svnTarget=el2.attribute("target");
-                               if(el2.hasAttribute("exe"))
-                                       m_svnExe=el2.attribute("exe");
-                       }
-                       if(nl2.size()>0)callSvn();
+                       if(el.hasAttribute("svnTarget"))
+                               m_svnTarget=el.attribute("target");
+                       if(el.hasAttribute("svnExe"))
+                               m_svnExe=el.attribute("exe");
+                       callSvn();
                }
                else{
                        qDebug("Warning: file %s has unknown element '%s' at line %i column %i", fn.toLocal8Bit().data(), tn.toLocal8Bit().data(), el.lineNumber(), el.columnNumber());
@@ -196,6 +211,7 @@ WocOutput::WocOutput()
 {
        connect(WocProcessor::instance(),SIGNAL(sfinalize()),this,SLOT(finalize()));
        connect(WocProcessor::instance(),SIGNAL(newClass(const WocClass&)),this,SLOT(newClass(const WocClass&)));
+       connect(WocProcessor::instance(),SIGNAL(newTable(const WocTable&)),this,SLOT(newTable(const WocTable&)));
 }
 
 WocOutput::~WocOutput(){}
@@ -206,3 +222,66 @@ WocClass::WocClass(const QDomElement&cls)
        qDebug("not really parsing class %s",cls.attribute("name").toAscii().data());
        
 }
+
+WocTable::WocTable(const QDomElement&tbl)
+{
+       m_valid=true;
+       //parse XML
+       m_name=tbl.attribute("name");
+       //TODO: check name syntax, check it does not exist yet
+       m_backup=str2bool(tbl.attribute("backup","0"));
+       qDebug("Info: parsing table %s",m_name.toAscii().data());
+       QDomNodeList nl=tbl.elementsByTagName("Column");
+       //Columns
+       for(int i=0;i<nl.size();i++){
+               QDomElement el=nl.at(i).toElement();
+               if(el.isNull())continue;
+               s_col cl;
+               cl.name=el.attribute("name");
+               //TODO: check name syntax, check it is not doubled
+               cl.isprime=str2bool(el.attribute("primarykey","0"));
+               if(el.hasAttribute("null"))
+                       cl.isnull=str2bool(el.attribute("null"));
+               else
+                       cl.isnull=!str2bool(el.attribute("notnull","0"));
+               cl.type=el.attribute("type");
+               //TODO: validate type
+               cl.foreign=el.attribute("foreignkey");
+               //TODO: check foreign key exists
+               cl.defaultval=el.attribute("default");
+               //TODO: validate default against type
+               QDomNodeList nl2=el.elementsByTagName("Value");
+               int nxval=0;
+               //enum values
+               for(int j=0;j<nl2.size();j++){
+                       QDomElement el2=nl2.at(j).toElement();
+                       if(el2.isNull())continue;
+                       QString n=el2.attribute("name");
+                       if(n==""){
+                               qDebug("Warning: anonymous enum value in table %s column %s. Ignoring it.",m_name.toAscii().data(),cl.name.toAscii().data());
+                               continue;
+                       }
+                       nxval=el2.attribute("value",QString::number(nxval)).toInt();
+                       cl.enumvals.append(QPair<QString,int>(n,nxval));
+                       nxval++;
+               }
+               m_columns.append(cl);
+       }
+       //Foreign getter methods
+       nl=tbl.elementsByTagName("Foreign");
+       for(int i=0;i<nl.size();i++){
+               QDomElement el=nl.at(i).toElement();
+               if(el.isNull())continue;
+               m_foreign.append(QPair<QString,QString>(el.attribute("method"),el.attribute("via")));
+               //TODO: validate foreign getter
+       }
+       
+       //sanity checks
+       //check we have any columns at all
+       if(m_columns.size()==0){
+               qDebug("Error: table %s does not have any columns.",m_name.toAscii().data());
+               m_valid=false;
+               return;
+       }
+       //TODO: check that we have a primary key
+}
index 4ac09a3..55ca722 100644 (file)
@@ -13,7 +13,9 @@
 #ifndef WOC_PROCESSOR_H
 #define WOC_PROCESSOR_H
 
+#include <QList>
 #include <QObject>
+#include <QPair>
 
 class QDomElement;
 
@@ -27,6 +29,27 @@ class WocClass
                bool m_valid;
 };
 
+class WocTable
+{
+       public:
+               WocTable(const QDomElement&);
+               
+               bool isValid()const{return m_valid;}
+               
+               QString name()const{return m_name;}
+               bool inBackup()const{return m_backup;}
+       private:
+               bool m_valid,m_backup;
+               QString m_name;
+               struct s_col {
+                       QString name,type,foreign,defaultval;
+                       bool isnull,isprime;
+                       QList<QPair<QString,int> >enumvals;
+               };
+               QList<s_col>m_columns;
+               QList<QPair<QString,QString> >m_foreign;
+};
+
 class WocOutput:public QObject
 {
        Q_OBJECT
@@ -37,6 +60,7 @@ class WocOutput:public QObject
        protected slots:
                virtual void finalize()=0;
                virtual void newClass(const WocClass&)=0;
+               virtual void newTable(const WocTable&)=0;
 };
 
 class WocProcessor:public QObject
@@ -60,11 +84,15 @@ class WocProcessor:public QObject
        signals:
                void sfinalize();
                void newClass(const WocClass&);
+               void newTable(const WocTable&);
                
        private:
                QString m_baseDir,m_wobDir,m_verComm,m_verNeedComm,m_verHR;
                QString m_svnTarget,m_svnRev,m_svnExe,m_dbInst,m_dbScheme;
                
+               QList<WocTable> m_tables;
+               QList<WocClass> m_classes;
+               
                static WocProcessor*inst;
                
                void callSvn();
index 151848c..31fd52b 100644 (file)
@@ -15,3 +15,4 @@
 WocQtClientOut::WocQtClientOut(QString srcDir,QString subDir,QString prifile){}
 void WocQtClientOut::finalize(){}
 void WocQtClientOut::newClass(const WocClass&){}
+void WocQtClientOut::newTable(const WocTable&){}
\ No newline at end of file
index ced1e88..1a50ef4 100644 (file)
@@ -22,6 +22,7 @@ class WocQtClientOut:public WocOutput
        protected:
                virtual void finalize();
                virtual void newClass(const WocClass&);
+               virtual void newTable(const WocTable&);
 };
 
 #endif
index daa9778..ba642c7 100644 (file)
@@ -9,13 +9,13 @@
 // +----------------------------------------------------------------------
 //
 
-$AUTOCLASS["WobTable"]="wbase/table.php";
+$AUTOCLASS["WobTable"]="inc/wbase/table.php";
 
 function __autoload($cname)
 {
        global $AUTOCLASS;
        if(isset($AUTOCLASS[$cname]))
-               require_once 'inc/'.$AUTOCLASS[$cname];
+               require_once $AUTOCLASS[$cname];
 }
 
 ?>
index b339c4e..afa6ef5 100644 (file)
@@ -40,12 +40,12 @@ class WobTable
        
        public function __isset($name)
        {
-               //verify name and return true on existence
+               //verify name and return true on existence AND notnull
        }
        
        public function __unset($name)
        {
-               //ignore those fools!
+               //reset to null
        }
        
        /**insert the object under a new primary key value into the DB (implicitly calls newKey)*/