Explorar o código

updated reinstall object structure

Piotr Labudda %!s(int64=9) %!d(string=hai) anos
pai
achega
02f324f764

+ 38 - 56
SE/schema/ant-object/default_db.TEST_PERMS/TestPermsAnt/TestPermsAnt.xsd

@@ -1,8 +1,10 @@
 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml"
     xmlns:p5="https://biuro.biall-net.pl/wfs"
     xmlns:default_db="https://biuro.biall-net.pl/wfs/default_db"
+    xmlns:default_db__x3A__TEST_PERMS="https://biuro.biall-net.pl/wfs/default_db/TEST_PERMS/TestPermsAnt"
     xmlns:default_objects="https://biuro.biall-net.pl/wfs/default_objects"
-    elementFormDefault="qualified" targetNamespace="https://biuro.biall-net.pl/wfs/default_objects"
+    elementFormDefault="qualified"
+    targetNamespace="https://biuro.biall-net.pl/wfs/default_db/TEST_PERMS/TestPermsAnt"
     version="1.0.0">
     <xsd:import namespace="http://www.opengis.net/gml"
         schemaLocation="https://biuro.biall-net.pl/dev-pl/se-master/schema/gml/2.1.2/feature.xsd"/>
@@ -10,55 +12,39 @@
         <xsd:complexContent>
             <xsd:extension base="gml:AbstractFeatureType">
                 <xsd:sequence>
-                    <xsd:element minOccurs="1" maxOccurs="1" name="ID" type="xsd:integer"
-                        nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="L_APPOITMENT_USER"
-                        type="xsd:string" nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="KATALOG_LINK" type="p5:www_link"
-                        nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="WWW" type="p5:www_link"
-                        nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="ADM_ADMIN_LEVEL"
-                        type="xsd:string" nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="ADM_PASSWD" type="xsd:string"
-                        nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="A_STATUS" type="xsd:string"
-                        nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="EMAIL" type="xsd:string"
-                        nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="ADM_NAME" type="xsd:string"
-                        nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="PARENT_ID" type="xsd:integer"
-                        nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="OPIS" type="xsd:string"
-                        nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="the_geom"
-                        type="gml:PolygonPropertyType" nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="A_ADM_COMPANY" type="xsd:string"
-                        nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="A_CLASSIFIED" type="xsd:string"
-                        nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="A_RECORD_CREATE_AUTHOR"
-                        type="xsd:string" nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="A_RECORD_CREATE_DATE"
-                        type="xsd:string" nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="A_RECORD_UPDATE_AUTHOR"
-                        type="xsd:string" nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="A_RECORD_UPDATE_DATE"
-                        type="xsd:string" nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="test_date" type="xsd:date"
-                        nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="test_datetime"
-                        type="xsd:dateTime" nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="test_price" type="p5:price"
-                        nillable="true"/>
-                    <xsd:element minOccurs="0" maxOccurs="1" name="test_time" type="xsd:string"
-                        nillable="true"/>
+                    <xsd:element minOccurs="1" maxOccurs="1" name="ID" type="xsd:integer" nillable="true"/>
+                    <xsd:element name="L_APPOITMENT_USER" minOccurs="0" maxOccurs="1" nillable="true">
+                        <xsd:simpleType>
+                            <xsd:restriction base="xsd:string">
+                                <xsd:maxLength value="20"/>
+                            </xsd:restriction>
+                        </xsd:simpleType>
+                    </xsd:element>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="KATALOG_LINK" type="p5:www_link" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="WWW" type="p5:www_link" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="ADM_ADMIN_LEVEL" type="xsd:string" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="ADM_PASSWD" type="xsd:string" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="A_STATUS" type="xsd:string" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="EMAIL" type="xsd:string" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="ADM_ANAME" type="xsd:string" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="PARENT_ID" type="xsd:integer" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="OPIS" type="xsd:string" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="the_geom" type="gml:PolygonPropertyType" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="A_ADM_COMPANY" type="xsd:string" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="A_CLASSIFIED" type="xsd:string" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="A_RECORD_CREATE_AUTHOR" type="xsd:string" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="A_RECORD_CREATE_DATE" type="xsd:string" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="A_RECORD_UPDATE_AUTHOR" type="xsd:string" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="A_RECORD_UPDATE_DATE" type="xsd:string" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="test_date" type="xsd:date" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="test_year" type="xsd:gYear" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="test_datetime" type="xsd:dateTime" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="test_price" type="p5:price" nillable="true"/>
+                    <xsd:element minOccurs="0" maxOccurs="1" name="test_time" type="xsd:string" nillable="true"/>
                     <xsd:element minOccurs="0" maxOccurs="unbounded" name="__instance">
                         <xsd:complexType>
                             <xsd:sequence>
-                                <xsd:element name="instance_name"
-                                    type="default_objects:TestPerms__instanceType"/>
+                                <xsd:element name="instance_name" type="default_db__x3A__TEST_PERMS:TestPerms__instanceType"/>
                                 <xsd:element name="instance_type" type="xsd:string"/>
                                 <!-- 'instance', 'waiting', 'derived', 'matching' -->
                                 <xsd:element name="create_author" type="xsd:string"/>
@@ -72,22 +58,18 @@
                     <xsd:element minOccurs="0" maxOccurs="1" name="__backRef">
                         <xsd:complexType>
                             <xsd:sequence>
-                                <xsd:element name="default_db__x3A__CRM_PROCES"
-                                    type="default_objects:TestPerms__backRefType"/>
-                                <xsd:element name="default_db__x3A__CRM_WSKAZNIK"
-                                    type="default_objects:TestPerms__backRefType"/>
-                                <xsd:element name="default_db__x3A__BUILDINGS"
-                                    type="default_objects:TestPerms__backRefType"/>
+                                <xsd:element name="default_db__x3A__CRM_PROCES" type="default_db__x3A__TEST_PERMS:TestPerms__backRefType"/>
+                                <xsd:element name="default_db__x3A__CRM_WSKAZNIK" type="default_db__x3A__TEST_PERMS:TestPerms__backRefType"/>
+                                <xsd:element name="default_db__x3A__BUILDINGS" type="default_db__x3A__TEST_PERMS:TestPerms__backRefType"/>
                             </xsd:sequence>
                         </xsd:complexType>
                     </xsd:element>
                 </xsd:sequence>
-                <xsd:attribute name="instance" type="default_objects:TestPerms__instanceType"/>
+                <!-- <xsd:attribute name="instance" type="default_objects:TestPerms__instanceType"/> -->
             </xsd:extension>
         </xsd:complexContent>
     </xsd:complexType>
-    <xsd:element name="TestPermsAnt" type="default_objects:TestPermsAntType"
-        substitutionGroup="gml:_Feature"/>
+    <xsd:element name="TestPermsAnt" type="default_db__x3A__TEST_PERMS:TestPermsAntType" substitutionGroup="gml:_Feature"/>
     <xsd:simpleType name="TestPerms__instanceType">
         <xsd:restriction base="xsd:string">
             <xsd:enumeration value="TestPerms"/>

+ 4 - 0
SE/schema/p5/.htaccess

@@ -0,0 +1,4 @@
+#<FilesMatch "2.1.2/feature.xsd$">
+	Order Allow,Deny
+	Allow from all
+#</FilesMatch>

+ 35 - 0
SE/schema/p5/types.xsd

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+  targetNamespace="https://biuro.biall-net.pl/wfs">
+
+  <xsd:simpleType name="string">
+    <xsd:restriction base="xsd:string">
+      <xsd:maxLength value="255"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+  <xsd:simpleType name="longString">
+    <xsd:restriction base="xsd:string">
+      <xsd:maxLength value="1000"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name="p5:enum">
+    <xsd:restriction base="xsd:string" />
+  </xsd:simpleType>
+
+  <xsd:simpleType name="p5:www_link">
+    <xsd:restriction base="xsd:string" />
+  </xsd:simpleType>
+
+  <xsd:simpleType name="p5:alias">
+    <xsd:restriction base="xsd:string" />
+  </xsd:simpleType>
+
+  <xsd:simpleType name="price">
+    <xsd:restriction base="xsd:decimal">
+      <xsd:totalDigits value="12"/>
+      <xsd:fractionDigits value="2"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+</xsd:schema>

+ 4 - 121
SE/se-lib/Route/Storage.php

@@ -1680,13 +1680,11 @@ jQuery(document).on('p5UIBtnAjax:Storage:checkObjectInstallAjax:ajaxLoaded', fun
 		try {
 			$namespace = V::get('namespace', '', $_GET);
 			if (empty($namespace)) throw new Exception("Missing param namespace");
-			$item = $this->getObjectAclRow($namespace);
-			DBG::log($item, 'array', '$item');
 
-			switch ($item['_type']) {
-				case 'AntAcl': $this->reinstallAntAcl($item); break;
-				default: throw new Exception("TODO: Not Implemented type '{$item['_type']}'");
-			}
+			Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
+			$objFieldAcl = new Schema_SystemObjectFieldStorageAcl();
+			$objFieldAcl->updateCache($namespace);
+
 		} catch (Exception $e) {
 			UI::alert('danger', "Error #" . $e->getCode() .  "|" . $e->getLine() .  ": " . $e->getMessage());
 			DBG::log($e);
@@ -1695,119 +1693,4 @@ jQuery(document).on('p5UIBtnAjax:Storage:checkObjectInstallAjax:ajaxLoaded', fun
 		UI::dol();
 	}
 
-	public function reinstallAntAcl($item) {
-		Lib::loadClass('AntAclBase');
-		$antAclPath = APP_PATH_SCHEMA . DS . 'ant-object' . DS . str_replace(['__x3A__', ':'], ['.', '/'], $item['typeName']);
-		if (!file_exists("{$antAclPath}/build.xml")) throw new Exception("Ant build file not exists");
-
-		if (file_exists("{$antAclPath}/{$item['name']}.xsd")) {
-			DBG::log("{$antAclPath}/{$item['name']}.xsd", 'string', 'xsd file exists');
-			$outputType = 'XML';
-			$antOutput = file_get_contents("{$antAclPath}/{$item['name']}.xsd");
-		} else {
-			DBG::log($antAclPath, 'string', '$antAclPath');
-			$antBin = APP_PATH_WWW . DS . 'stuff' . DS . 'dita-ot-2.3.3' . DS . 'bin' . DS . 'ant';
-			$cmd = "cd {$antAclPath} && {$antBin} DescribeFeatureType 2>&1";
-			V::exec($cmd, $out, $ret);
-			DBG::log($out, 'array', "DescribeFeatureType ret({$ret})");
-			$outputType = 'XML';
-			$antOutput = []; $startRead = false;
-			foreach ($out as $line) {
-				// $line = "     [echo] OUTPUT__TYPE__XML"
-				if ('[echo]' == substr(trim($line), 0, 6)) {
-					$line = trim(substr(trim($line), 7));
-				}
-
-				if (!$startRead) {
-					if ('OUTPUT__TYPE__XML' == $line) $outputType = 'XML';
-					if ('OUTPUT__TYPE__HTML' == $line) $outputType = 'HTML';
-					if ('OUTPUT__START' == $line) {
-						$startRead = true;
-						continue;
-					}
-				} else {
-					if ('<!DOCTYPE' == substr($line, 0, strlen('<!DOCTYPE'))) continue;
-					if ('OUTPUT__END' == $line) {
-						break;
-					}
-					$antOutput[]= $line;
-				}
-			}
-			if (!empty($antOutput)) $antOutput = implode("\n", $antOutput);
-		}
-		if (empty($antOutput)) UI::alert('danger', "Empty output!");
-		else {
-			echo UI::h('p', [], "Ant Schema:");
-			if ('XML' == $outputType) {
-				echo UI::h('pre', ['style' => 'max-height:400px; overflow:scroll'], htmlspecialchars($antOutput));
-			} else if ('HTML' == $outputType) {
-				echo UI::h('div', ['class'=>"container", 'style'=>"padding:12px; border:1px solid #ddd"], $antOutput);
-			}
-		}
-
-		Lib::loadClass('XML');
-		$schema = XML::readXmlFileToArray("{$antAclPath}/{$item['name']}.xsd");
-		if (empty($schema)) throw new Exception("Missing schema");
-		$xsdType = [ // find xsd:element with @name = $item['name']
-			'nsPrefix' => null,
-			'name' => null,
-			'nsUri' => null,
-			'targetNsUri' => V::get('targetNamespace', '', $schema[1])
-		];
-		if (!$xsdType['targetNsUri']) throw new Exception("Missing schema target namespace declaration '{$item['name']}'");
-		foreach ($schema[2] as $n) {
-			if ('xsd:element' != $n[0]) continue;
-			if ($item['name'] != V::get('name', '', $n[1])) continue;
-			list($xsdType['nsPrefix'], $xsdType['name']) = explode(':', V::get('type', '', $n[1]));
-		}
-		if (!$xsdType['nsPrefix'] || !$xsdType['name']) throw new Exception("Missing schema root element name = '{$item['name']}'");
-
-		$xsdType['nsUri'] = V::get("xmlns:{$xsdType['nsPrefix']}", '', $schema[1]);// find xmlns:default_objects = "https://biuro.biall-net.pl/wfs/default_objects"
-		if (!$xsdType['nsUri']) throw new Exception("Missing schema root element namespace declaration = '{$item['name']}'");
-		if ($xsdType['nsUri'] != $xsdType['targetNsUri']) throw new Exception("TODO: type ns is not the same as targetNamespace '{$item['name']}'");// TODO
-
-		foreach ($schema[2] as $n) {
-			if ('xsd:complexType' != $n[0]) continue;
-			if ($xsdType['name'] != V::get('name', '', $n[1])) continue;
-			DBG::nicePrint($n, 'TODO: parse complexType');
-			// complexType/complexContent/extension[base=...]/sequence/element
-			if ($n[2][0][0] != 'xsd:complexContent') throw new Exception("Error Parsing Schema - expected 'complexType/complexContent'");
-			if ($n[2][0][2][0][0] != 'xsd:extension') throw new Exception("Error Parsing Schema - expected 'complexType/complexContent/extension'");
-			$xsdType['extensionBase'] = V::get('base', '', $n[2][0][2][0][1]);
-			if ($n[2][0][2][0][2][0][0] != 'xsd:sequence') throw new Exception("Error Parsing Schema - expected 'complexType/complexContent/extension/sequence'");
-			foreach ($n[2][0][2][0][2][0][2] as $f) {
-				if ($f[0] !== 'xsd:element') {
-					DBG::log($n, 'array', "Schema xsd parse error - Not implemented node type '{$f[0]}'");
-					continue;
-				}
-				$fieldName = V::get('name', '', $f[1]);
-				if (!$fieldName) throw new Exception("Error Parsing Schema - expected 'element[@name]'");
-				$xsdType['struct'][$fieldName] = [
-					'type' => V::get('type', '', $f[1]),
-					'ref' => V::get('ref', '', $f[1]),
-					'minOccurs' => V::get('minOccurs', 0, $f[1], 'int'),
-					'maxOccurs' => V::get('maxOccurs', '1', $f[1]),
-				];
-			}
-		}
-
-		DBG::nicePrint($xsdType, '$xsdType');
-		// TODO: insert fields $xsdType['struct'] by 'SystemObjectField'
-		// getStorage('SystemObjectField')->update(['isActive' => 0], ['#refFrom' => ['ns' => 'SystemObject', 'pk' => $item['namespace']]]) // TODO: update pk in SysObj schema
-		// getStorage('SystemObjectField')->insertOrUpdate([ 'isActive' => 1, ... , '@insert' => [], '@update' => [] ])
-
-		{
-			DBG::nicePrint($schema, '$schema');
-			Lib::loadClass('Core_XmlWriter');
-			ob_start();
-			$xmlWriter = new Core_XmlWriter();
-			$xmlWriter->openUri('php://output');
-			$xmlWriter->setIndent(true);
-			$xmlWriter->startDocument('1.0','UTF-8');
-			$xmlWriter->h($schema[0], $schema[1], $schema[2]);
-			$xmlWriter->endDocument();
-			echo UI::h('pre', ['style' => 'max-height:400px; overflow:scroll'], htmlspecialchars(ob_get_clean()));
-		}
-	}
-
 }

+ 348 - 23
SE/se-lib/Schema/SystemObjectFieldStorageAcl.php

@@ -8,46 +8,368 @@ class Schema_SystemObjectFieldStorageAcl extends Core_AclSimpleSchemaBase {
 
   public $_simpleSchema = [
     'root' => [
-      '@namespace' => 'default_objects/SystemObject',
-      '@primaryKey' => 'idZasob',
+      '@namespace' => 'default_objects/SystemObjectField',
+      '@primaryKey' => 'fieldNamespace',
       'idZasob' => [ '@type' => 'xsd:integer' ],
       'idDatabase' => [ '@type' => 'xsd:integer' ],
-      'namespace' => [ '@type' => 'xsd:string' ],
       '_rootTableName' => [ '@type' => 'xsd:string' ],
-      '_type' => [ '@type' => 'xsd:string' ],
+      'objectNamespace' => [ '@type' => 'xsd:string' ],
+      'fieldNamespace' => [ '@type' => 'xsd:string' ],
+      'xsdType' => [ '@type' => 'xsd:string' ],
+      'xsdRestrictions' => [ '@type' => 'xsd:string' ],
+      'minOccurs' => [ '@type' => 'xsd:string' ],
+      'maxOccurs' => [ '@type' => 'xsd:string' ], //  '0..unbounded',
       'isActive' => [ '@type' => 'xsd:integer' ], // installed
       'description' => [ '@type' => 'xsd:string' ],
-      'name' => [ '@type' => 'p5:string' ],
-      'typeName' => [ '@type' => 'p5:string' ],
-      'reinstallLink' => [ '@type' => 'p5:www_link' ],
       // 'A_RECORD_CREATE_AUTHOR' => [ '@type' => 'xsd:string' , '@label' => 'autor' ],
       // 'A_RECORD_CREATE_DATE' => [ '@type' => 'xsd:date' , '@label' => 'utworzono' ],
       // 'A_RECORD_UPDATE_AUTHOR' => [ '@type' => 'xsd:string' , '@label' => 'zaktualizował' ],
       // 'A_RECORD_UPDATE_DATE' => [ '@type' => 'xsd:date', '@label' => 'zaktualizowano' ],
-      '@key' => 'namespace'
     ]
   ];
   // public $_rootTableName = 'CRM_LISTA_ZASOBOW';
   public $_rootTableName = 'CRM_#CACHE_ACL_OBJECT_FIELD';
   public $_version = '1';
 
+  public function updateCache($namespace = null) {
+    DBG::simpleLog('schema', "SystemObjectField::updateCache({$namespace})...");
+    // DB::getPDO()->execSql(" drop table if exists `{$this->_rootTableName}` "); // TODO: DBG
+    DB::getPDO()->execSql("
+      create table if not exists `{$this->_rootTableName}` (
+        `fieldNamespace` varchar(255) DEFAULT '',
+        `idZasob` int(11) DEFAULT NULL,
+        `idDatabase` int(11) NOT NULL,
+        `_rootTableName` varchar(255) DEFAULT '',
+        `objectNamespace` varchar(255) DEFAULT '',
+        `xsdType` varchar(255) DEFAULT '',
+        `xsdRestrictions` varchar(1000) DEFAULT '',
+        `minOccurs` int(11) DEFAULT '0',
+        `maxOccurs` varchar(11) DEFAULT '1' COMMENT '0..unbounded',
+        `isActive` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'installed',
+        `description` varchar(255) DEFAULT '',
+        UNIQUE KEY `idZasob` (idZasob),
+        UNIQUE KEY `namespace` (objectNamespace, fieldNamespace),
+        KEY `isActive` (isActive)
+      ) ENGINE=MyISAM  DEFAULT CHARSET=latin2
+    ");
+    DB::getPDO()->update($this->_rootTableName, 'objectNamespace', $namespace, ['isActive' => 0]);
+    $sysObjectStorage = SchemaFactory::loadDefaultObject('SystemObject');
+    if (!$namespace) throw new Exception("Missing namespace '{$namespace}'");
+    $objectItem = $sysObjectStorage->getItem($namespace);
+    DBG::nicePrint($objectItem, '$objectItem');
+    DBG::log($objectItem, 'array', '$objectItem');
+
+    switch ($objectItem['_type']) {
+      case 'AntAcl': $this->updateCacheAntAcl($objectItem); break;
+      case 'TableAcl': $this->updateCacheTableAcl($objectItem); break;
+      default: throw new Exception("TODO: Not Implemented type '{$objectItem['_type']}'");
+    }
+    // TODO: mv from methods: SchemaFactory::loadDefaultObject('SystemObject')->updateItem([
+    //   'namespace' => $item['namespace'],
+    //   'isStructInstalled' => 1
+    // ]);
+  }
+
+  public function updateCacheAntAcl($item) {
+		Lib::loadClass('AntAclBase');
+		$antAclPath = APP_PATH_SCHEMA . DS . 'ant-object' . DS . str_replace(['__x3A__', ':'], ['.', '/'], $item['typeName']);
+		if (!file_exists("{$antAclPath}/build.xml")) throw new Exception("Ant build file not exists");
+
+		// if (file_exists("{$antAclPath}/{$item['name']}.xsd")) {
+		// 	DBG::log("{$antAclPath}/{$item['name']}.xsd", 'string', 'xsd file exists');
+		// 	$outputType = 'XML';
+		// 	$antOutput = file_get_contents("{$antAclPath}/{$item['name']}.xsd");
+		// } else {
+		// 	DBG::log($antAclPath, 'string', '$antAclPath');
+		// 	$antBin = APP_PATH_WWW . DS . 'stuff' . DS . 'dita-ot-2.3.3' . DS . 'bin' . DS . 'ant';
+		// 	$cmd = "cd {$antAclPath} && {$antBin} DescribeFeatureType 2>&1";
+		// 	V::exec($cmd, $out, $ret);
+		// 	DBG::log($out, 'array', "DescribeFeatureType ret({$ret})");
+		// 	$outputType = 'XML';
+		// 	$antOutput = []; $startRead = false;
+		// 	foreach ($out as $line) {
+		// 		// $line = "     [echo] OUTPUT__TYPE__XML"
+		// 		if ('[echo]' == substr(trim($line), 0, 6)) {
+		// 			$line = trim(substr(trim($line), 7));
+		// 		}
+    //
+		// 		if (!$startRead) {
+		// 			if ('OUTPUT__TYPE__XML' == $line) $outputType = 'XML';
+		// 			if ('OUTPUT__TYPE__HTML' == $line) $outputType = 'HTML';
+		// 			if ('OUTPUT__START' == $line) {
+		// 				$startRead = true;
+		// 				continue;
+		// 			}
+		// 		} else {
+		// 			if ('<!DOCTYPE' == substr($line, 0, strlen('<!DOCTYPE'))) continue;
+		// 			if ('OUTPUT__END' == $line) {
+		// 				break;
+		// 			}
+		// 			$antOutput[]= $line;
+		// 		}
+		// 	}
+		// 	if (!empty($antOutput)) $antOutput = implode("\n", $antOutput);
+		// }
+		// if (empty($antOutput)) UI::alert('danger', "Empty output!");
+		// else {
+		// 	echo UI::h('p', [], "Ant Schema:");
+		// 	if ('XML' == $outputType) {
+		// 		echo UI::h('pre', ['style' => 'max-height:400px; overflow:scroll'], htmlspecialchars($antOutput));
+		// 	} else if ('HTML' == $outputType) {
+		// 		echo UI::h('div', ['class'=>"container", 'style'=>"padding:12px; border:1px solid #ddd"], $antOutput);
+		// 	}
+		// }
+
+		Lib::loadClass('XML');
+		$schema = XML::readXmlFileToArray("{$antAclPath}/{$item['name']}.xsd");
+		if (empty($schema)) throw new Exception("Missing schema file for '{$item['namespace']}'");
+		$xsdType = [ // find xsd:element with @name = $item['name']
+			'nsPrefix' => null,
+			'name' => null,
+			'nsUri' => null,
+			'targetNsUri' => V::get('targetNamespace', '', $schema[1])
+		];
+		if (!$xsdType['targetNsUri']) throw new Exception("Missing schema target namespace declaration '{$item['name']}'");
+		foreach ($schema[2] as $n) {
+			if ('xsd:element' != $n[0]) continue;
+			if ($item['name'] != V::get('name', '', $n[1])) continue;
+			list($xsdType['nsPrefix'], $xsdType['name']) = explode(':', V::get('type', '', $n[1]));
+		}
+		if (!$xsdType['nsPrefix'] || !$xsdType['name']) throw new Exception("Missing schema root element name = '{$item['name']}'");
+
+		$xsdType['nsUri'] = V::get("xmlns:{$xsdType['nsPrefix']}", '', $schema[1]);// find xmlns:default_objects = "https://biuro.biall-net.pl/wfs/default_objects"
+		if (!$xsdType['nsUri']) throw new Exception("Missing schema root element namespace declaration = '{$item['name']}'");
+		if ($xsdType['nsUri'] != $xsdType['targetNsUri']) throw new Exception("TODO: type ns is not the same as targetNamespace '{$item['name']}'");// TODO
+
+		foreach ($schema[2] as $n) {
+			if ('xsd:complexType' != $n[0]) continue;
+			if ($xsdType['name'] != V::get('name', '', $n[1])) continue;
+			DBG::nicePrint($n, 'TODO: parse complexType');
+			// complexType/complexContent/extension[base=...]/sequence/element
+			if ($n[2][0][0] != 'xsd:complexContent') throw new Exception("Error Parsing Schema - expected 'complexType/complexContent'");
+			if ($n[2][0][2][0][0] != 'xsd:extension') throw new Exception("Error Parsing Schema - expected 'complexType/complexContent/extension'");
+			$xsdType['extensionBase'] = V::get('base', '', $n[2][0][2][0][1]);
+			if ($n[2][0][2][0][2][0][0] != 'xsd:sequence') throw new Exception("Error Parsing Schema - expected 'complexType/complexContent/extension/sequence'");
+			foreach ($n[2][0][2][0][2][0][2] as $f) {
+				if ($f[0] !== 'xsd:element') {
+					DBG::log($n, 'array', "Schema xsd parse error - Not implemented node type '{$f[0]}'");
+					continue;
+				}
+				$fieldName = V::get('name', '', $f[1]);
+				if (!$fieldName) throw new Exception("Error Parsing Schema - expected 'element[@name]'");
+				if ('__' === substr($fieldName, 0, 2)) continue;
+				if (!V::get('type', '', $f[1]) && !V::get('ref', '', $f[1]) && empty($f[2])) {
+					UI::alert('danger', "Skipping not implemented field structure '{$fieldName}'");
+					continue;
+				}
+				$xsdType['struct'][$fieldName] = [
+					'type' => V::get('type', '', $f[1]),
+					'ref' => V::get('ref', '', $f[1]),
+					'minOccurs' => V::get('minOccurs', 0, $f[1], 'int'),
+					'maxOccurs' => V::get('maxOccurs', '1', $f[1]),
+          'restrictions' => [],
+				];
+        if (!empty($f[1]['nillable']) && 'true' === $f[1]['nillable']) $xsdType['struct'][$fieldName]['restrictions']['nillable'] = true;
+        if (!empty($f[2])) {
+          if (empty($f[2][0][0]) || 'xsd:simpleType' != $f[2][0][0]) throw new Exception("Missing 'xsd:simpleType' for field '{$fieldName}'");
+          if (empty($f[2][0][2][0]) || 'xsd:restriction' != $f[2][0][2][0][0]) throw new Exception("Missing 'xsd:restriction' for field '{$fieldName}'");
+          if (empty($f[2][0][2][0][1]['base'])) throw new Exception("Missing 'xsd:restriction/@base' for field '{$fieldName}'");
+          // [2] => Array:
+          //    [0] => Array:
+          //             [0] => xsd:simpleType
+          //             [1] => Array:
+          //             [2] => Array:
+          //                 [0] => Array:
+          //                     [0] => xsd:restriction
+          //                     [1] => Array:
+          //                         [base] => xsd:string
+          //                     [2] => Array:
+          foreach ($f[2][0][2][0][2] as $tagRestriction) {
+            //                         [0] => Array:
+            //                             [0] => xsd:maxLength
+            //                             [1] => Array:
+            //                                 [value] => 20
+            //                             [2] =>
+            $val = $tagRestriction[1]['value'];
+            if ('xsd:enumeration' == $tagRestriction[0]) {
+              $restrictions['enumeration'][$val] = $val;
+            } else {
+              $restrictions[substr($tagRestriction[0], 4)] = $val;
+            }
+          }
+          DBG::nicePrint(['f'=>$f, '$restr'=>$restrictions], 'TODO: field childrens f[2]');
+          if (!empty($restrictions)) $xsdType['struct'][$fieldName]['restrictions'] = $restrictions;
+        }
+			}
+		}
+
+		DBG::nicePrint($xsdType, '$xsdType');
+    if (empty($xsdType['struct'])) throw new Exception("Field list not found for '{$item['namespace']}'");
+    foreach ($xsdType['struct'] as $fieldName => $x) {
+      DB::getPDO()->insertOrUpdate($this->_rootTableName, [
+        'objectNamespace' => $item['namespace'],
+        'idDatabase' => $item['idDatabase'],
+        '_rootTableName' => $item['_rootTableName'],
+        'fieldNamespace' => $fieldName,
+        'xsdType' => (!empty($x['type'])) ? $x['type'] : "ref:{$x['ref']}",
+        'xsdRestrictions' => json_encode($x['restrictions']),
+        'minOccurs' => $x['minOccurs'],
+        'maxOccurs' => $x['maxOccurs'],
+        'isActive' => 1
+      ]);
+    }
+    DB::getPDO()->execSql("
+      update `{$this->_rootTableName}` t
+        join CRM_LISTA_ZASOBOW zp on(zp.PARENT_ID = {$item['idDatabase']} and zp.`DESC` = '{$item['_rootTableName']}')
+        join CRM_LISTA_ZASOBOW z on(z.PARENT_ID = zp.ID and z.`DESC` = t.fieldNamespace)
+      set t.idZasob = z.ID
+      where t.objectNamespace = '{$item['namespace']}'
+    ");
+
+		{// TODO: DBG
+			DBG::nicePrint($schema, '$schema');
+			Lib::loadClass('Core_XmlWriter');
+			ob_start();
+			$xmlWriter = new Core_XmlWriter();
+			$xmlWriter->openUri('php://output');
+			$xmlWriter->setIndent(true);
+			$xmlWriter->startDocument('1.0','UTF-8');
+			$xmlWriter->h($schema[0], $schema[1], $schema[2]);
+			$xmlWriter->endDocument();
+			echo UI::h('pre', ['style' => 'max-height:400px; overflow:scroll'], htmlspecialchars(ob_get_clean()));
+		}
+	}
+  public function updateCacheTableAcl($item) {
+    // TODO: xsdType - convert mysql type to xsdType, xsdRestrictions
+    $xsdInfo = [];
+    Lib::loadClass('SchemaHelper');
+    $dbName = DB::getPDO()->getDatabaseName();
+    $mysqlTypes = DB::getPDO()->fetchAll("
+      select c.COLUMN_NAME, c.COLUMN_TYPE, c.DATA_TYPE, c.IS_NULLABLE, c.CHARACTER_MAXIMUM_LENGTH, c.NUMERIC_PRECISION, c.NUMERIC_SCALE
+      from `information_schema`.`COLUMNS` c
+      where c.TABLE_SCHEMA = '{$dbName}'
+        and c.TABLE_NAME = '{$item['_rootTableName']}'
+    ");
+    foreach ($mysqlTypes as $mysqlType) {
+      $xsdInfo[ $mysqlType['COLUMN_NAME'] ] = SchemaHelper::convertMysqlTypeToSchemaXsd($mysqlType);
+    }
+    DBG::nicePrint($xsdInfo, '$xsdInfo');
+
+    foreach ($xsdInfo as $fieldName => $x) {
+      DB::getPDO()->insertOrUpdate($this->_rootTableName, [
+        'fieldNamespace' => $fieldName,
+        'isActive' => 1,
+        'idDatabase' => $item['idDatabase'],
+        '_rootTableName' => $item['_rootTableName'],
+        'objectNamespace' => $item['namespace'],
+        'xsdType' => $x['type'],
+        'xsdRestrictions' => json_encode($x['restrictions']),
+      ]);
+    }
+    SchemaFactory::loadDefaultObject('SystemObject')->updateItem([
+      'namespace' => $item['namespace'],
+      'isStructInstalled' => 1
+    ]);
+
+    $struct = $this->getItems([
+      '__backRef' => [
+        'namespace' => 'default_objects/SystemObject',
+        'primaryKey' => $item['namespace']
+      ]
+    ]);
+    DBG::nicePrint($struct, '$struct');
+
+    {// TODO: DBG
+      $schema = ['xsd:schema', [
+        'xmlns:xsd' => "http://www.w3.org/2001/XMLSchema",
+        'xmlns:gml' => "http://www.opengis.net/gml",
+        'xmlns:p5' => "https://biuro.biall-net.pl/wfs",
+        'xmlns:default_db' => "https://biuro.biall-net.pl/wfs/default_db",
+        'xmlns:default_objects' => "https://biuro.biall-net.pl/wfs/default_objects",
+        'elementFormDefault' => "qualified",
+        'version' => "1.0.0",
+      ], []];
+      Lib::loadClass('Api_WfsNs');
+      $tnsUri = Api_WfsNs::getNsUri($item['nsPrefix']);
+      $schema[1]['xmlns:' . Api_WfsNs::getNsPrefix($tnsUri)] = $tnsUri;
+      $schema[1]['targetNamespace'] = $tnsUri;
+      $schema[2][] = ['xsd:import', ['namespace'=>"http://www.opengis.net/gml", 'schemaLocation'=>"https://biuro.biall-net.pl/dev-pl/se-master/schema/gml/2.1.2/feature.xsd"], null];
+      $schema[2][] = ['xsd:complexType', [ 'name'=> $item['name'] . "Type" ], [
+        [ 'xsd:complexContent', [], [
+          [ 'xsd:extension', ['base'=>"gml:AbstractFeatureType"], [
+            [ 'xsd:sequence', [], array_map(function ($field) {
+              $attrs = [
+                'name' => $field['fieldNamespace'],
+                // <xsd:element minOccurs="1" maxOccurs="1" name="ID" type="xsd:integer" nillable="true"/>
+                'minOccurs' => $field['minOccurs'],
+                'maxOccurs' => $field['maxOccurs'],
+              ];
+              $childrens = null;
+              $restrictions = [];
+              foreach ($this->getXsdRestrictionsValue($field) as $k => $v) {
+                if ('enumeration' == $k) {
+                  foreach ($v as $enumValue) {
+                    $restrictions[] = [ 'xsd:enumeration', [ 'value' => $enumValue ], null ];
+                  }
+                } else if ('maxLength' == $k) {
+                  $restrictions[] = [ 'xsd:maxLength', [ 'value' => $v ], null ];
+                } else if ('totalDigits' == $k) {
+                  $restrictions[] = [ 'xsd:totalDigits', [ 'value' => $v ], null ];
+                } else if ('fractionDigits' == $k) {
+                  $restrictions[] = [ 'xsd:fractionDigits', [ 'value' => $v ], null ];
+                } else if ('nillable' == $k) {
+                  if ($v) $attrs['nillable'] = "true";
+                } else {
+                  DBG::log(['TODO' => $k, $v]);
+                }
+              }
+              if (!empty($restrictions)) {
+                $childrens = [
+                  [ 'xsd:simpleType', [], [
+                    [ 'xsd:restriction', [ 'base' => $field['xsdType'] ], $restrictions ]
+                  ]]
+                ];
+              } else {
+                $attrs['type'] = $field['xsdType'];
+              }
+              return [ 'xsd:element', $attrs, $childrens ];
+            }, $struct)]
+          ]]
+        ]]
+      ]];
+      $schema[2][] = ['xsd:element', [ 'name' => $item['name'], 'type' => "{$item['nsPrefix']}:{$item['name']}Type", 'substitutionGroup' => "gml:_Feature" ], null];
+
+			DBG::nicePrint($schema, '$schema');
+			Lib::loadClass('Core_XmlWriter');
+			ob_start();
+			$xmlWriter = new Core_XmlWriter();
+			$xmlWriter->openUri('php://output');
+			$xmlWriter->setIndent(true);
+			$xmlWriter->startDocument('1.0','UTF-8');
+			$xmlWriter->h($schema[0], $schema[1], $schema[2]);
+			$xmlWriter->endDocument();
+			echo UI::h('pre', ['style' => 'max-height:400px; overflow:scroll'], htmlspecialchars(ob_get_clean()));
+		}
+  }
+
   public function _parseWhere($params = []) {
     $sqlWhere = [];
     DBG::log($params, 'array', "SystemObject::_parseWhere");
-    if (!empty($params['#refFrom'])) {
-      // '#refFrom' => [
-      //   'namespace' => 'default_objects/SystemSource',
-      //   'primaryKey' => $sourceItem['idZasob']
-      // ]
-      if (empty($params['#refFrom']['namespace'])) throw new Exception("Missing refFrom/namespace");
-      if (empty($params['#refFrom']['primaryKey'])) throw new Exception("Missing refFrom/primaryKey");
-
-      if ('default_objects/SystemSource' != $params['#refFrom']['namespace']) throw new Exception("Unsupported refFrom/namespace '{$params['#refFrom']['namespace']}'");
-      $sqlWhere[] = "t.idDatabase = " . DB::getPDO()->quote($params['#refFrom']['primaryKey'], PDO::PARAM_INT);
+    if (!empty($params['__backRef'])) {
+      // '__backRef' => [
+      //     'namespace' => 'default_objects/SystemObject',
+      //     'primaryKey' => 'default_db/TEST_PERMS',
+      //  ),
+      if (empty($params['__backRef']['namespace'])) throw new Exception("Missing refFrom/namespace");
+      if (empty($params['__backRef']['primaryKey'])) throw new Exception("Missing refFrom/primaryKey");
+
+      if ('default_objects/SystemObject' != $params['__backRef']['namespace']) throw new Exception("Unsupported refFrom/namespace '{$params['__backRef']['namespace']}'");
+      $sqlWhere[] = "t.objectNamespace = " . DB::getPDO()->quote($params['__backRef']['primaryKey'], PDO::PARAM_INT);
     }
     {
       $filterParams = [];
       $xsdFields = $this->getXsdTypes();
+      DBG::log($xsdFields);
       foreach ($params as $k => $v) {
         if ('f_' != substr($k, 0, 2)) continue;
         $fieldName = substr($k, 2);
@@ -55,7 +377,7 @@ class Schema_SystemObjectFieldStorageAcl extends Core_AclSimpleSchemaBase {
           // TODO: check query by xpath or use different param prefix
           throw new Exception("Field '{$fieldName}' not found in '{$this->_namespace}'");
         }
-        if ('p5:' == substr($xsdFields[$fieldName], 0, 3)) {
+        if ('p5:' == substr($xsdFields[$fieldName]['xsdType'], 0, 3)) {
           continue;
         }
         $filterParams[$fieldName] = $v;
@@ -118,11 +440,14 @@ class Schema_SystemObjectFieldStorageAcl extends Core_AclSimpleSchemaBase {
     "));
   }
 
+  public function getXsdRestrictionsValue($item) {
+    $xsdRestrictions = @json_decode($item['xsdRestrictions'], $assoc = true);
+    if (empty($xsdRestrictions)) $xsdRestrictions = [];
+    if (array_key_exists('__DBG__', $xsdRestrictions)) unset($xsdRestrictions['__DBG__']);
+    return $xsdRestrictions;
+  }
+
   public function buildFeatureFromSqlRow($item) {
-    $exNs = explode('/', $item['namespace']);
-    $item['name'] = array_pop($exNs);
-    $item['typeName'] = implode('__x3A__', $exNs) . ':' . $item['name'];
-    $item['reinstallLink'] = Router::getRoute('Storage')->getLink('objectReinstall', [ 'namespace' => $item['namespace'] ]);
     return $item;
   }
 

+ 33 - 2
SE/se-lib/Schema/SystemObjectStorageAcl.php

@@ -9,16 +9,18 @@ class Schema_SystemObjectStorageAcl extends Core_AclSimpleSchemaBase {
   public $_simpleSchema = [
     'root' => [
       '@namespace' => 'default_objects/SystemObject',
-      '@primaryKey' => 'idZasob', // TODO: namespace
+      '@primaryKey' => 'namespace',
       'idZasob' => [ '@type' => 'xsd:integer' ],
       'idDatabase' => [ '@type' => 'xsd:integer' ],
       'namespace' => [ '@type' => 'xsd:string' ],
       '_rootTableName' => [ '@type' => 'xsd:string' ],
       '_type' => [ '@type' => 'xsd:string' ],
-      'isActive' => [ '@type' => 'xsd:integer' ], // installed
+      'isActive' => [ '@type' => 'xsd:integer' ], // 0 - removed, old
+      'isStructInstalled' => [ '@type' => 'xsd:integer' ], // installed
       'description' => [ '@type' => 'xsd:string' ],
       'name' => [ '@type' => 'p5:string' ],
       'typeName' => [ '@type' => 'p5:string' ],
+      'nsPrefix' => [ '@type' => 'p5:string' ],
       'reinstallLink' => [ '@type' => 'p5:www_link' ],
       // 'A_RECORD_CREATE_AUTHOR' => [ '@type' => 'xsd:string' , '@label' => 'autor' ],
       // 'A_RECORD_CREATE_DATE' => [ '@type' => 'xsd:date' , '@label' => 'utworzono' ],
@@ -285,6 +287,20 @@ class Schema_SystemObjectStorageAcl extends Core_AclSimpleSchemaBase {
     ");
   }
 
+  public function getItem($pk, $params = []) {
+    if (!$pk) throw new Exception("Missing primary key '{$this->_namespace}'");
+    $pkField = $this->getSqlPrimaryKeyField();
+    if (!$pkField) throw new Exception("Missing primary key field defined in '{$this->_namespace}'");
+    $sqlPk = DB::getPDO()->quote($pk, PDO::PARAM_STR);
+    $item = DB::getPDO()->fetchFirst("
+      select t.*
+      from `{$this->_rootTableName}` t
+      where t.`{$pkField}` = {$sqlPk}
+    ");
+    if (!$item) throw new Exception("Item '{$pk}' not exists - type '{$this->_namespace}'");
+    return $this->buildFeatureFromSqlRow($item);
+  }
+
   public function getItems($params = []) {
     $sqlWhere = $this->_parseWhere($params);
 
@@ -317,9 +333,24 @@ class Schema_SystemObjectStorageAcl extends Core_AclSimpleSchemaBase {
   public function buildFeatureFromSqlRow($item) {
     $exNs = explode('/', $item['namespace']);
     $item['name'] = array_pop($exNs);
+    $item['nsPrefix'] = implode('__x3A__', $exNs);
     $item['typeName'] = implode('__x3A__', $exNs) . ':' . $item['name'];
     $item['reinstallLink'] = Router::getRoute('Storage')->getLink('objectReinstall', [ 'namespace' => $item['namespace'] ]);
     return $item;
   }
 
+  public function updateItem($itemPatch) {
+    $pkField = $this->getPrimaryKeyField();
+    $pk = V::get($pkField, null, $itemPatch);
+    if (null === $pk) throw new Exception("BUG missing primary key field for '{$this->_namespace}' updateItem");
+    DBG::log(['TODO: updateItem', $itemPatch]);
+    unset($itemPatch[$pkField]);
+    if (empty($itemPatch)) return 0;
+    foreach ($itemPatch as $fieldName => $value) {
+      if ('isStructInstalled' == $fieldName) continue;
+      throw new Exception("Update field '{$fieldName}' not allowed for '{$this->_namespace}'");
+    }
+    return DB::getPDO()->update($this->_rootTableName, $pkField, $pk, $itemPatch);
+  }
+
 }

+ 216 - 0
SE/se-lib/SchemaHelper.php

@@ -0,0 +1,216 @@
+<?php
+
+// SE/schema/p5/types.xsd
+
+class SchemaHelper {
+
+  /**
+   * @param array $mysqlSchema - from infomration_schema.columns
+   * @param required array $mysqlSchema['DATA_TYPE']
+   * @param required array $mysqlSchema['NUMERIC_PRECISION']
+   * @param required array $mysqlSchema['NUMERIC_SCALE']
+   * @param required array $mysqlSchema['COLUMN_TYPE']
+   * @param required array $mysqlSchema['IS_NULLABLE']
+   */
+  public static function convertMysqlTypeToSchemaXsd($mysqlSchema, $fieldName = '') {
+    $restrictions = [];
+    switch ($mysqlSchema['DATA_TYPE']) {
+      case 'char':
+      case 'varchar': {
+        if (!empty($mysqlSchema['CHARACTER_MAXIMUM_LENGTH'])) $restrictions['maxLength'] = $mysqlSchema['CHARACTER_MAXIMUM_LENGTH'];
+        $xsdType = 'xsd:string';
+      } break;
+      case 'tinyint':
+      case 'smallint':
+      case 'mediumint':
+      case 'bigint':
+      case 'int': {
+        if (!empty($mysqlSchema['NUMERIC_PRECISION'])) $restrictions['totalDigits'] = $mysqlSchema['NUMERIC_PRECISION'];
+        $xsdType = 'xsd:integer';
+      } break;
+      case 'numeric':
+      case 'double':
+      case 'float':
+      case 'real':
+      case 'decimal': {
+        if (!empty($mysqlSchema['NUMERIC_PRECISION'])) $restrictions['totalDigits'] = $mysqlSchema['NUMERIC_PRECISION'];
+        if (!empty($mysqlSchema['NUMERIC_SCALE'])) $restrictions['fractionDigits'] = $mysqlSchema['NUMERIC_SCALE'];
+        $xsdType = 'xsd:decimal';
+      } break;
+      case 'datetime': $xsdType = 'xsd:dateTime'; break;
+      case 'year': $xsdType = 'xsd:gYear'; break;
+      case 'todo__year_month': $xsdType = 'xsd:gYearMonth'; break;
+      case 'time': $xsdType = 'xsd:time'; break;
+      case 'date': $xsdType = 'xsd:date'; break;
+      case 'polygon': $xsdType = 'xsd:PolygonPropertyType'; break;
+      case 'linestring': $xsdType = 'xsd:LineStringPropertyType'; break;
+      case 'point': $xsdType = 'xsd:PointPropertyType'; break;
+      case 'geometry': $xsdType = 'xsd:GeometryPropertyType'; break;
+      case 'enum': {
+        $xsdType = 'p5:enum';
+        $restrictions['enumeration'] = [];
+        $values = explode(',', str_replace(["'",'"'], '', substr($mysqlSchema['COLUMN_TYPE'], 5, -1)));
+    		foreach ($values as $val) {
+    			$restrictions['enumeration'][$val] = $val;
+    		}
+      } break;
+      case 'tinyblob': $xsdType = 'xsd:base64Binary'; break;
+      case 'mediumblob': $xsdType = 'xsd:base64Binary'; break;
+      case 'longblob': $xsdType = 'xsd:base64Binary'; break;
+      case 'blob': $xsdType = 'xsd:base64Binary'; break;
+      default: throw new Exception("Not implemented mysql schema '" . json_encode($mysqlSchema) . "'");
+    }
+
+    if ('YES' === $mysqlSchema['IS_NULLABLE']) $restrictions['nillable'] = true;
+
+    // TODO: convert to p5/types.xsd
+    switch ($xsdType) {
+      case 'xsd:decimal': {
+        if (12 == $restrictions['totalDigits'] && 2 == $restrictions['fractionDigits']) {
+          // <xsd:simpleType name="price">
+          //   <xsd:restriction base="xsd:decimal">
+          //     <xsd:totalDigits value="12"/>
+          //     <xsd:fractionDigits value="2"/>
+          unset($restrictions['totalDigits']);
+          unset($restrictions['fractionDigits']);
+          $xsdType = 'p5:price';
+        }
+      } break;
+      case 'xsd:string': {
+        if (255 == $restrictions['maxLength']) {
+          unset($restrictions['maxLength']);
+          $xsdType = 'p5:string';
+        } else if (1000 == $restrictions['maxLength']) {
+          unset($restrictions['maxLength']);
+          $xsdType = 'p5:longString';
+        }
+      } break;
+    }
+
+    return [
+      'type' => $xsdType,
+      'restrictions' => $restrictions,
+      '__DBG__' => [ 'COLUMN_TYPE' => $mysqlSchema['COLUMN_TYPE'] ],
+    ];
+  }
+
+  public static function convertMysqlSchemaToXsdRestrictions($mysqlType, $fieldName = '') {
+    $restrictions = [];
+    // enumeration	Defines a list of acceptable values
+    // fractionDigits	Specifies the maximum number of decimal places allowed. Must be equal to or greater than zero
+    // length	Specifies the exact number of characters or list items allowed. Must be equal to or greater than zero
+    // maxExclusive	Specifies the upper bounds for numeric values (the value must be less than this value)
+    // maxInclusive	Specifies the upper bounds for numeric values (the value must be less than or equal to this value)
+    // maxLength	Specifies the maximum number of characters or list items allowed. Must be equal to or greater than zero
+    // minExclusive	Specifies the lower bounds for numeric values (the value must be greater than this value)
+    // minInclusive	Specifies the lower bounds for numeric values (the value must be greater than or equal to this value)
+    // minLength	Specifies the minimum number of characters or list items allowed. Must be equal to or greater than zero
+    // pattern	Defines the exact sequence of characters that are acceptable
+    // totalDigits	Specifies the exact number of digits allowed. Must be greater than zero
+    // whiteSpace	Specifies how white space (line feeds, tabs, spaces, and carriage returns) is handled
+    if (!empty($mysqlType['CHARACTER_MAXIMUM_LENGTH'])) $restrictions['maxLength'] = $mysqlType['CHARACTER_MAXIMUM_LENGTH'];
+    if (!empty($mysqlType['NUMERIC_PRECISION'])) $restrictions['totalDigits'] = $mysqlType['NUMERIC_PRECISION'];
+    if (!empty($mysqlType['NUMERIC_SCALE'])) $restrictions['fractionDigits'] = $mysqlType['NUMERIC_SCALE'];
+    // date	Defines a date value
+    // dateTime	Defines a date and time value
+    // duration	Defines a time interval
+    // gDay	Defines a part of a date - the day (DD)
+    // gMonth	Defines a part of a date - the month (MM)
+    // gMonthDay	Defines a part of a date - the month and day (MM-DD)
+    // gYear	Defines a part of a date - the year (YYYY)
+    // gYearMonth	Defines a part of a date - the year and month (YYYY-MM)
+    // time	Defines a time value
+    if ('YES' === $mysqlType['IS_NULLABLE']) $restrictions['nillable'] = true;
+    if (self::mysqlTypeIsEnum($mysqlType) && !empty($mysqlType['COLUMN_TYPE'])) {
+      $restrictions['enumeration'] = [];
+      $values = explode(',', str_replace(["'",'"'], '', substr($mysqlType['COLUMN_TYPE'], 5, -1)));
+  		foreach ($values as $val) {
+  			$restrictions['enumeration'][$val] = $val;
+  		}
+    }
+    $restrictions['__DBG__']['COLUMN_TYPE'] = $mysqlType['COLUMN_TYPE'];
+    return $restrictions;
+  }
+  /**
+   * @param mixed $mysqlType - string or array from INFORMATION_SCHEMA.COLUMNS
+   */
+  public static function convertMysqlTypeToXsd($mysqlType, $fieldName = '') {
+    // TODO: check schemaClass
+    // Lib::loadClass('Schema_TableFactory')
+    // $srvName = $_SERVER['SERVER_NAME'];
+		// $this->_schemaClass = Schema_TableFactory::build($this->_name, $this->_db, $srvName);
+
+    // if ($this->_schemaClass) {
+		// 	$schemaType = $this->_schemaClass->getType($fieldName);
+		// 	if ($schemaType) return $schemaType;
+		// }
+		$fldType = 'xsd:string';
+		if ('A_RECORD_UPDATE_DATE' == $fieldName) $fldType = 'xsd:string';// TODO: fix date format
+		if ('A_RECORD_CREATE_DATE' == $fieldName) $fldType = 'xsd:string';// TODO: fix date format
+		if (self::mysqlTypeIsInteger($mysqlType)) $fldType = 'xsd:integer';
+		else if (self::mysqlTypeIsDecimal($mysqlType)) $fldType = 'xsd:decimal';
+		else if (self::mysqlTypeIsDateTime($mysqlType)) $fldType = 'xsd:dateTime';
+		else if (self::mysqlTypeIsDateYear($mysqlType)) $fldType = 'xsd:gYear';
+		else if (self::mysqlTypeIsDateYearMonth($mysqlType)) $fldType = 'xsd:gYearMonth';
+		else if (self::mysqlTypeIsTime($mysqlType)) $fldType = 'xsd:time';
+		else if (self::mysqlTypeIsDate($mysqlType)) $fldType = 'xsd:date';
+    else if (self::mysqlTypeIsGeometryPolygon($mysqlType)) $fldType = 'gml:PolygonPropertyType';
+		else if (self::mysqlTypeIsGeometryLine($mysqlType)) $fldType = 'gml:LineStringPropertyType';
+		else if (self::mysqlTypeIsGeometryPoint($mysqlType)) $fldType = 'gml:PointPropertyType';
+    else if (self::mysqlTypeIsGeometry($mysqlType)) $fldType = 'xsd:GeometryPropertyType';
+		else if (self::mysqlTypeIsEnum($mysqlType)) $fldType = 'p5:enum';
+		else if (self::mysqlTypeIsBinary($mysqlType)) $fldType = 'xsd:base64Binary';
+    DBG::log(['convertMysqlTypeToXsd', '$mysqlType' => $mysqlType, 'getMysqlType' => self::getMysqlType($mysqlType), 'return' => $fldType]);
+		return $fldType;
+  }
+  /**
+   * @param mixed $mysqlType - string or array from INFORMATION_SCHEMA.COLUMNS
+   */
+  public static function getMysqlType($mysqlType) {
+    if (is_array($mysqlType)) {
+      return $mysqlType['DATA_TYPE'];
+    }
+    if (false !== ($pos = strpos($mysqlType, '('))) return substr($mysqlType, 0, $pos);
+    return $mysqlType;
+  }
+  public static function mysqlTypeIsInteger($mysqlType) {
+    return (in_array(self::getMysqlType($mysqlType), ['int', 'tinyint', 'smallint', 'mediumint', 'bigint']));
+  }
+  public static function mysqlTypeIsDecimal($mysqlType) {
+    return (in_array(self::getMysqlType($mysqlType), ['decimal', 'numeric', 'double', 'float', 'real']));
+  }
+  public static function mysqlTypeIsDateTime($mysqlType) {
+    return (in_array(self::getMysqlType($mysqlType), ['datetime']));
+  }
+  public static function mysqlTypeIsDateYear($mysqlType) {
+    return (in_array(self::getMysqlType($mysqlType), ['year']));
+  }
+  public static function mysqlTypeIsDateYearMonth($mysqlType) {
+    return (in_array(self::getMysqlType($mysqlType), ['todo__year_month']));
+  }
+  public static function mysqlTypeIsTime($mysqlType) {
+    return (in_array(self::getMysqlType($mysqlType), ['time']));
+  }
+  public static function mysqlTypeIsDate($mysqlType) {
+    return (in_array(self::getMysqlType($mysqlType), ['date', 'datetime']));
+  }
+  public static function mysqlTypeIsGeometryLine($mysqlType) {
+    return (in_array(self::getMysqlType($mysqlType), ['linestring']));
+  }
+  public static function mysqlTypeIsGeometryPolygon($mysqlType) {
+    return (in_array(self::getMysqlType($mysqlType), ['polygon']));
+  }
+  public static function mysqlTypeIsGeometryPoint($mysqlType) {
+    return (in_array(self::getMysqlType($mysqlType), ['point']));
+  }
+  public static function mysqlTypeIsGeometry($mysqlType) {
+    return (in_array(self::getMysqlType($mysqlType), ['geometry', 'polygon', 'linestring', 'point']));
+  }
+  public static function mysqlTypeIsEnum($mysqlType) {
+    return (in_array(self::getMysqlType($mysqlType), ['enum']));
+  }
+  public static function mysqlTypeIsBinary($mysqlType) {
+    return (in_array(self::getMysqlType($mysqlType), ['blob', 'tinyblob', 'mediumblob', 'longblob']));
+  }
+
+}

+ 1 - 1
SE/se-lib/TableAcl.php

@@ -1861,8 +1861,8 @@ class TableAcl extends Core_AclBase {
 		if ('A_RECORD_CREATE_DATE' == $fieldName) return 'xsd:string';
 		if ($this->isIntegerField($fieldName)) return 'xsd:integer';
 		else if ($this->isDecimalField($fieldName)) return 'xsd:decimal';
-		else if ($this->isDateField($fieldName)) return 'xsd:date';
 		else if ($this->isDateTimeField($fieldName)) return 'xsd:dateTime';
+		else if ($this->isDateField($fieldName)) return 'xsd:date';
 		else if ($this->isGeomField($fieldName)) {
 			//$fldType = 'gml:GeometryPropertyType';
 			$geomType = $this->getGeomFieldType($fieldName);