implemented wob properties
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Wed, 18 Feb 2009 17:54:03 +0000 (17:54 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Wed, 18 Feb 2009 17:54:03 +0000 (17:54 +0000)
git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@272 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

wob/cart.wolf
wob/order.wolf
woc/phpout.cpp
woc/processor.cpp
woc/processor.h

index 2e2a190..4c8ee2e 100644 (file)
@@ -63,7 +63,7 @@
                </Enum>
                <Property name="value" type="int"/>
                <Property name="price" type="int" optional="1"/>
-               <Property name="status" type="Enum:ValidationState" optional="1"/>
+               <Property name="status" type="ValidationState" optional="1"/>
        </Class>
        
        <Class name="CartOrder">
@@ -73,7 +73,7 @@
                        <Value name="OrderOnly"/>
                        <Value name="Invalid"/>
                </Enum>
-               <Property name="status" type="Enum:ValidationState" optional="1"/>
+               <Property name="status" type="ValidationState" optional="1"/>
                <Property name="customerid" type="int"/>
                <Property name="tickets" type="List:CartTicket"/>
                <Property name="vouchers" type="List:CartVoucher"/>
index cfed4b6..aaa244b 100644 (file)
                <Property name="voucherid" type="astring" id="yes"/>
                <Property name="value" type="int"/>
                <Property name="price" type="int" optional="1"/>
-               <Property name="status" type="Enum:ValidationState" optional="1"/>
+               <Property name="status" type="VoucherState" optional="1"/>
        </Class>
        
        <Class name="Order" abstract="yes">
                <Property name="tickets" type="List:Ticket"/>
                <Property name="vouchers" type="List:Voucher"/>
                <Property name="amountpaid" type="int"/>
-               <Property name="state" type="Enum:OrderState"/>
+               <Property name="state" type="OrderState"/>
                
                <Property name="amountdue" type="int" abstract="yes"/>
                <!-- etc.pp. -->
index 9ac9ae5..52832c5 100644 (file)
@@ -242,18 +242,185 @@ void WocPHPServerOut::newClass(const WocClass&cls)
        }
        
        //implement properties
+       k=cls.propertyNames();
+       for(int i=0;i<k.size();i++){
+               code+="\nprotected $prop_"+k[i]+";\n";
+               //generate validator
+               code+="static public function validate"+k[i]+"($value){\n";
+               if(cls.propertyIsEnum(k[i])){
+                       QList<QPair<QString,int> >ev=cls.enumValues(cls.propertyPlainType(k[i]));
+                       code+="\tif(is_numeric($value)){\n\t\t$value=$value+0;\n";
+                       for(int j=0;j<ev.size();j++){
+                               code+="\t\tif($value=="+QString::number(ev[j].second)+")return true;\n";
+                       }
+                       code+="\t\treturn false;\n\t}else{\n";
+                       for(int j=0;j<ev.size();j++){
+                               code+="\t\tif($value==\""+ev[j].first+"\")return true;\n";
+                       }
+                       code+="\t\treturn false;\n\t}\n";
+               }else
+               if(cls.propertyIsInt(k[i]))
+                       code+="\treturn is_numeric($value);\n";
+               else
+               if(cls.propertyIsString(k[i]))
+                       code+="\treturn true;\n";//TODO: special handling for astring
+               else
+               if(cls.propertyIsObject(k[i]))
+                       code+="\treturn is_a($value,\"WO"+cls.propertyPlainType(k[i])+"\");\n";
+               else{
+                       qDebug("Warning: unable to generate validator for class %s property %s: unknown type.",cls.name().toAscii().data(),k[i].toAscii().data());
+                       code+="\treturn false;\n";
+               }
+               code+="}\n";
+               //generic getter
+               code+="public function get_"+k[i]+"(){return $this->prop_"+k[i]+";}\n";
+               if(cls.propertyIsList(k[i])){
+                       //lists...
+                       //getters
+                       if(cls.propertyIsString(k[i]))code+="public function getstrlist_"+k[i]+"(){return $this->prop_"+k[i]+";}\n";
+                       else
+                       if(cls.propertyIsInt(k[i])){
+                               code+="public function getstrlist_"+k[i]+"(){\n";
+                               code+="\t$ret=array();\n\tforeach($this->prop_"+k[i]+" as $p)$ret[]=\"\".$p;\n";
+                               code+="\treturn $ret;\n}\n";
+                       }else
+                       if(cls.propertyIsEnum(k[i])){
+                               code+="public function getstrlist_"+k[i]+"(){\n";
+                               code+="\t$ret=array();\n";
+                               code+="\tforeach($this->prop_"+k[i]+" as $p)switch($p){\n";
+                               QList<QPair<QString,int> > ev=cls.enumValues(cls.propertyPlainType(k[i]));
+                               for(int j=0;j<ev.size();j++){
+                                       code+="\t\tcase "+QString::number(ev[j].second)+":$ret[]=\""+ev[j].first+"\";break;\n";
+                               }
+                               code+="\t\tdefault:$ret[]=null;break;\n\t}\n\treturn $ret;\n}\n";
+                       }
+                       //setters
+                       code+="public function clear_"+k[i]+"(){$this->prop_"+k[i]+"=array();}\n";
+                       QString acode;//body of add_ function, see below
+                       code+="public function set_"+k[i]+"(array $values){\n";
+                       if(cls.propertyIsEnum(k[i])){
+                               QList<QPair<QString,int> >ev=cls.enumValues(cls.propertyPlainType(k[i]));
+                               code+="\t$prop=array();\n";
+                               code+="\tforeach($values as $value){\n";
+                               code+="\t\tif(is_numeric($value)){\n\t\t\t$value=$value+0;\n";
+                               acode+="\tif(is_numeric($value)){\n\t\t$value=$value+0;\n";
+                               for(int j=0;j<ev.size();j++){
+                                       code+="\t\t\tif($value=="+QString::number(ev[j].second)+"){\n";
+                                       code+="\t\t\t\t$prop[]="+QString::number(ev[j].second)+";\n";
+                                       code+="\t\t\t}else\n";
+                                       acode+="\t\tif($value=="+QString::number(ev[j].second)+"){\n";
+                                       acode+="\t\t\t$this->prop_"+k[i]+"[]="+QString::number(ev[j].second)+";\n";
+                                       acode+="\t\t\treturn true;\n\t\t}\n";
+                               }
+                               code+="\t\t\treturn false;\n\t\t}else{\n";
+                               acode+="\t\treturn false;\n\t}else{\n";
+                               for(int j=0;j<ev.size();j++){
+                                       code+="\t\t\tif($value==\""+ev[j].first+"\"){\n";
+                                       code+="\t\t\t\t$prop[]="+QString::number(ev[j].second)+";\n";
+                                       code+="\n\t\t\t}else\n";
+                                       acode+="\t\tif($value==\""+ev[j].first+"\"){\n";
+                                       acode+="\t\t\t$this->prop_"+k[i]+"[]="+QString::number(ev[j].second)+";\n";
+                                       acode+="\t\t\treturn true;\n\t\t}\n";
+                               }
+                               code+="\t\t\treturn false;\n\t\t}\n\t}\n";
+                               code+="\t$this->prop_"+k[i]+"=$prop;\n";
+                               code+="\treturn true;\n";
+                               acode+="\t\treturn false;\n\t}\n";
+                       }else
+                       if(cls.propertyIsInt(k[i])){
+                               code+="\t$prop=array();\n\tforeach($values as $value)\n";
+                               code+="\t\tif(is_numeric($value)){\n\t\t\t$prop=0+$value;\n\t\t}else return false;\n";
+                               code+="\t$this->prop_"+k[i]+"=$prop;\n\treturn true;\n";
+                               acode+="\tif(is_numeric($value)){\n";
+                               acode+="\t\t$this->prop_"+k[i]+"=0+$value;\n\t\treturn true;\n\t}else return false;\n";
+                       }else
+                       if(cls.propertyIsString(k[i])){
+                               code+="\t$prop=array();\n\tforeach($values as $value)$prop[]=\"\".$value;\n";
+                               code+="\t$this->prop_"+k[i]+"=$prop;\n\treturn true;\n";
+                               //TODO: special handling for astring
+                               acode+="\t$this->prop_"+k[i]+"[]=\"\".$value;\n\treturn true;\n";
+                       }else
+                       if(cls.propertyIsObject(k[i])){
+                               code+="\t$prop=array();\n\tforeach($values as $value)\n";
+                               code+="\t\tif(is_a($value,\"WO"+cls.propertyPlainType(k[i])+"\"))\n";
+                               code+="\t\t\t$prop[]=$value;\n";
+                               code+="\t\telse return false;\n";
+                               code+="\t$this->prop_"+k[i]+"=$prop;\n";
+                               code+="\treturn true;\n";
+                               acode+="\tif(is_a($value,\"WO"+cls.propertyPlainType(k[i])+"\")){\n";
+                               acode+="\t\t$this->prop_"+k[i]+"[]=$value;\n";
+                               acode+="\t\treturn true;\n";
+                               acode+="\t}else return false;\n";
+                       }else{
+                               qDebug("Warning: unable to generate setter for class %s property %s: unknown type.",cls.name().toAscii().data(),k[i].toAscii().data());
+                               code+="\treturn false;\n";
+                       }
+                       code+="}\n";
+                       code+="public function add_"+k[i]+"($value){\n"+acode+"}\n";
+               }else{
+                       //non-lists...
+                       //getters
+                       if(cls.propertyIsString(k[i]))code+="public function getstr_"+k[i]+"(){return $this->prop_"+k[i]+";}\n";
+                       else
+                       if(cls.propertyIsInt(k[i]))code+="public function getstr_"+k[i]+"(){return \"\".$this->prop_"+k[i]+";}\n";
+                       else
+                       if(cls.propertyIsEnum(k[i])){
+                               code+="public function getstr_"+k[i]+"(){\n\tswitch($this->prop_"+k[i]+"){\n";
+                               QList<QPair<QString,int> > ev=cls.enumValues(cls.propertyPlainType(k[i]));
+                               for(int j=0;j<ev.size();j++){
+                                       code+="\t\tcase "+QString::number(ev[j].second)+":return \""+ev[j].first+"\";\n";
+                               }
+                               code+="\t\tdefault:return null;\n\t}\n}\n";
+                       }
+                       //setter
+                       code+="public function set_"+k[i]+"($value){\n";
+                       if(cls.propertyIsEnum(k[i])){
+                               QList<QPair<QString,int> >ev=cls.enumValues(cls.propertyPlainType(k[i]));
+                               code+="\tif(is_numeric($value)){\n\t\t$value=$value+0;\n";
+                               for(int j=0;j<ev.size();j++){
+                                       code+="\t\tif($value=="+QString::number(ev[j].second)+"){\n";
+                                       code+="\t\t\t$this->prop_"+k[i]+"="+QString::number(ev[j].second)+";\n";
+                                       code+="\t\t\treturn true;\n\t\t}\n";
+                               }
+                               code+="\t\treturn false;\n\t}else{\n";
+                               for(int j=0;j<ev.size();j++){
+                                       code+="\t\tif($value==\""+ev[j].first+"\"){\n";
+                                       code+="\t\t\t$this->prop_"+k[i]+"="+QString::number(ev[j].second)+";\n";
+                                       code+="\t\t\treturn true;\n\t\t}\n";
+                               }
+                               code+="\t\treturn false;\n\t}\n";
+                       }else
+                       if(cls.propertyIsInt(k[i]))
+                               code+="\tif(is_numeric($value)){\n\t\t$this->prop_"+k[i]+"=0+$value;\n\t\treturn true;\n\t}else return false;\n";
+                       else
+                       if(cls.propertyIsString(k[i]))
+                               code+="\t$this->prop_"+k[i]+"=\"\".$value;\n\treturn true;\n";
+                               //TODO: special handling for astring
+                       else
+                       if(cls.propertyIsObject(k[i])){
+                               code+="\tif(is_a($value,\"WO"+cls.propertyPlainType(k[i])+"\")){\n";
+                               code+="\t\t$this->prop_"+k[i]+"=$value;\n";
+                               code+="\t\treturn true;\n";
+                       }else{
+                               qDebug("Warning: unable to generate setter for class %s property %s: unknown type.",cls.name().toAscii().data(),k[i].toAscii().data());
+                               code+="\treturn false;\n";
+                       }
+                       code+="}\n";
+               }
+       }
        
-       //implement mappings
+       //TODO: implement mappings
        
        //implement serializers
        k=cls.serializers();
        for(int i=0;i<k.size();i++){
                //toString function (wraps toXml)
-               code+="\nfunction toString"+k[i]+"(){\n\t$xml=new DomDocument;\n";
+               code+="\npublic function toString"+k[i]+"(){\n\t$xml=new DomDocument;\n";
                code+="\t$xml->appendChild($this->toXml"+k[i]+"($xml));\n\treturn $xml->saveXml();\n}\n";
                //toXml function:
-               code+="function toXml"+k[i]+"($xml){\n";
-               code+="\t$root=$xml->createElement(\""+cls.name()+k[i]+"\");\n";
+               code+="public function toXml"+k[i]+"($xml){\n";
+               code+="\t$root=$xml->createElement(\""+cls.name()+"\");\n";
+               code+="\t$root->setAttribute(\"serialization-mode\",\""+k[i]+"\");\n";
                //add properties
                QStringList p=cls.serializerProperties(k[i]);
                for(int j=0;j<p.size();j++)
@@ -263,11 +430,11 @@ void WocPHPServerOut::newClass(const WocClass&cls)
        }
        
        //implement de-serializer
-       code+="\nstatic function fromString($txt){\n\t$xml=new DomDocument;\n";
+       code+="\nstatic public function fromString($txt){\n\t$xml=new DomDocument;\n";
        code+="\tif(!$xml->loadXml(trim($txt)))";
        code+="\n\t\tthrow WobXmlException(\"Unable to deserialize object of type "+cn+".\");";
        code+="\n\treturn self::fromXml($xml,$xml->documentElement);\n}\n";
-       code+="static function fromXml($xml,$elem){\n\t$data=array();\n";
+       code+="static public function fromXml($xml,$elem){\n\t$data=array();\n";
        k=cls.propertyNames();
        for(int i=0;i<k.size();i++){
                //TODO: scan properties
@@ -284,7 +451,40 @@ void WocPHPServerOut::newClass(const WocClass&cls)
        tf.close();
 }
 
-QString WocPHPServerOut::propertyToXml(const WocClass&,QString){return "";}
+QString WocPHPServerOut::propertyToXml(const WocClass&cls,QString pt)
+{
+       QStringList sl=pt.split("/",QString::SkipEmptyParts);
+       if(sl.size()<1)return "";
+       QString prop=sl[0].trimmed();
+       QString var;
+       if(sl.size()>1)var=sl[1].trimmed();
+       //is it a list?
+       if(cls.propertyIsList(prop)){
+               //is it a class?
+               if(cls.propertyIsObject(prop)){
+                       QString code="\tforeach($this->get_"+prop+"() as $o)\n\t\t";
+                       code+="$root->appendChild($o->toXml"+var+"($xml));\n";
+                       return code;
+               }else{
+                       //there is no way to create lists of attributes, hence we always create elements
+                       QString code="\tforeach($this->getstrlist_"+prop+"() as $e)\n\t\t";
+                       code+="$root->appendChild($xml->createElement(\""+prop+"\",xq($e)));\n";
+                       return code;
+               }
+       }
+       //is it an attribute?
+       if(cls.propertyIsAttribute(prop))
+               return "\t$root->setAttribute(\""+prop+"\",$this->getstr_"+prop+"());\n";
+       //is it an element?
+       if(cls.propertyIsElement(prop))
+               return "\t$root->appendChild($xml->createElement(\""+prop+"\",xq($this->getstr_"+prop+"())));\n";
+       //is it a class?
+       if(cls.propertyIsObject(prop))
+               return "\t$root->appendChild($this->get_"+prop+"()->toXml"+var+"($xml));\n";
+       //anything else?
+       qDebug("Warning: end of WocPHPServerOut::propertyToXml - this code should not be reachable.");
+       return "//internal generator error!\n";
+}
 
 void WocPHPServerOut::newTransaction(const WocTransaction&)
 {
index f17fd0a..a1e8dec 100644 (file)
@@ -466,6 +466,59 @@ bool WocClass::isAbstract()const
        return m_abstract;
 }
 
+QString WocClass::propertyPlainType(QString p)const
+{
+       QString r=propertyType(p);
+       if(r.startsWith("List:"))return r.mid(5);
+       else return r;
+}
+
+const QStringList WocClass::attrtypes=QStringList()<<"astring"<<"int";
+bool WocClass::propertyIsAttribute(QString p)const
+{
+       QString t=propertyPlainType(p);
+       if(attrtypes.contains(t))return true;
+       if(hasEnumType(t))return true;
+       return false;
+}
+
+const QStringList WocClass::elemtypes=QStringList()<<"string";
+bool WocClass::propertyIsElement(QString p)const
+{
+       QString t=propertyPlainType(p);
+       if(elemtypes.contains(t))return true;
+       if(hasEnumType(t))return true;
+       return false;
+}
+
+bool WocClass::propertyIsObject(QString p)const
+{
+       QString t=propertyPlainType(p);
+       //default types take precedence over classes
+       if(attrtypes.contains(t))return false;
+       if(elemtypes.contains(t))return false;
+       //enums shadow classes
+       if(hasEnumType(t))return false;
+       //check that the class exists
+       return WocProcessor::instance()->hasClass(t);
+}
+
+bool WocClass::propertyIsEnum(QString p)const
+{
+       QString t=propertyPlainType(p);
+       //default types take precedence over enums
+       if(attrtypes.contains(t))return false;
+       if(elemtypes.contains(t))return false;
+       //enums
+       return hasEnumType(t);
+}
+
+bool WocClass::propertyIsList(QString p)const
+{
+       if(propertyType(p).startsWith("List:"))return true;
+       else return false;
+}
+
 
 /******************************************************************************
  * WocTable
index b7f92b4..f2e8d8b 100644 (file)
 
 class QDomElement;
 
+/**stores a communication class including serialization and deserialization information*/
 class WocClass
 {
        public:
+               /**parses XML to create itself*/
                WocClass(const QDomElement&);
                
+               /**returns whether parsing was successful and this instance represents a valid communication class*/
                bool isValid()const{return m_valid;}
                
+               /**returns the class name*/
                QString name()const{return m_name;}
+               /**returns the name of the class it is derived from (on the server side)*/
                QString baseClass()const{return m_base;}
                
+               /**returns true of it has a property with this name*/
                bool hasProperty(QString)const;
+               /**returns a list of all property names*/
                QStringList propertyNames()const;
+               /**returns the type string of the property, including "List:" if applicable*/
                QString propertyType(QString)const;
+               /**returns the plain type string of the property without "List:"*/
+               QString propertyPlainType(QString)const;
+               /**returns whether this property identifies the object instance*/
                bool propertyIsIdentity(QString)const;
+               /**returns whether this property is abstract*/
                bool propertyIsAbstract(QString)const;
-               
+               /**returns whether this property is serialized as XML attribute*/
+               bool propertyIsAttribute(QString)const;
+               /**returns whether this property is serialized as XML element*/
+               bool propertyIsElement(QString)const;
+               /**returns whether this property has an enum type*/
+               bool propertyIsEnum(QString)const;
+               /**returns whether the property is an object*/
+               bool propertyIsObject(QString)const;
+               /**returns whether the property is a list of values (false for scalars)*/
+               bool propertyIsList(QString)const;
+               /**returns whether the property type is integer*/
+               bool propertyIsInt(QString p)const{return propertyPlainType(p)=="int";}
+               /**returns whether the property type is string*/
+               bool propertyIsString(QString p)const{QString pt=propertyPlainType(p);return pt=="string"||pt=="astring";}
+               
+               /**returns whether the class is abstract (needs to be customized); it is automatically abstract if any property is abstract*/
                bool isAbstract()const;
                
+               /**returns the names of all enum types of this class*/
                QStringList enumTypes()const{return m_enumvals.keys();}
+               /**returns true if the given enum type exists in this class*/
                bool hasEnumType(QString t)const{return m_enumvals.contains(t);}
+               /**returns a list of enum values as name-value pairs*/
                QList<QPair<QString,int> > enumValues(QString t)const{return m_enumvals[t];}
                
+               /**returns the names of all serializer methods of this class*/
                QStringList serializers()const{return m_serial.keys();}
+               /**returns true if the given serializer is defined*/
                bool hasSerializer(QString s)const{return m_serial.contains(s);}
+               /**returns which properties are encoded by this serializer*/
                QStringList serializerProperties(QString s)const{return m_serial[s];}
                
+               /**returns true if the given mapping exists*/
                bool hasMapping(QString m)const{return m_maps.contains(m);}
                
        private:
+               //valid: parsing the WOLF succeeded
+               //abstract: the class is declared abstract (isAbstract may return true even if this is false)
                bool m_valid,m_abstract;
+               //name: class name
+               //base: name of parent class
                QString m_name,m_base;
+               //property info
                struct s_prop{
                        QString name,type;
                        bool isid,isabstract;
                };
                QList<s_prop> m_props;
+               //mappings: "table-name" => List of ("column-name","property-name")
                QMap<QString,QList<QPair<QString,QString> > >m_maps;
+               //enum types: "type-name" => List of ("constant-name",int-constant-value)
                QMap<QString,QList<QPair<QString,int> > >m_enumvals;
+               //serializers: "name" => List of properties (syntax Objects: "propertyname/Serializer"
                QMap<QString,QStringList> m_serial;
+               
+               //helper: contains predefined types sorted by serialization type
+               static const QStringList attrtypes,elemtypes;
 };
 
 class WocTable