-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
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.
</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.
+<?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"/>
+<?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"/>
+<?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"/>
+<?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"/>
#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());
+}
#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
#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()
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"){
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"))
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());
{
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(){}
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
+}
#ifndef WOC_PROCESSOR_H
#define WOC_PROCESSOR_H
+#include <QList>
#include <QObject>
+#include <QPair>
class QDomElement;
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
protected slots:
virtual void finalize()=0;
virtual void newClass(const WocClass&)=0;
+ virtual void newTable(const WocTable&)=0;
};
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();
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
protected:
virtual void finalize();
virtual void newClass(const WocClass&);
+ virtual void newTable(const WocTable&);
};
#endif
// +----------------------------------------------------------------------
//
-$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];
}
?>
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)*/