Переглянути джерело

+ create table, add missing fields from xsd in Storage/reinstallAcl

Piotr Labudda 7 роки тому
батько
коміт
ddc695b868

+ 3 - 3
SE/se-lib/Core/AclSimpleSchemaBase.php

@@ -14,7 +14,7 @@ class Core_AclSimpleSchemaBase extends Core_AclBase {
 
     $simpleSchema = [
       'root' => [
-        '@namespace' => 'default_db/ZALICZKA/Zaliczka',
+        '@namespace' => 'default_db/{$table_name}/{$object_name}',
         '@primaryKey' => 'ID',
 
         'ID' => 'xsd:integer', // short syntax - define only simpleType
@@ -31,11 +31,11 @@ class Core_AclSimpleSchemaBase extends Core_AclBase {
         ]
       ],
       'Worker' => [
-        '@namespace' => 'default_objects/AccessOwner',
+        '@namespace' => $remote_ns, // eg: 'default_objects/AccessOwner' or 'default_db/{$table_name}/{$object_name}'
         ...
       ],
       'ZaliczkaPozycja' => [
-        '@namespace' => 'default_db/ZALICZKA_POZYCJA/ZaliczkaPozycja',
+        '@namespace' => $remote_ns
         ...
       ]
 

+ 171 - 62
SE/se-lib/Route/Storage/AclReinstall.php

@@ -7,6 +7,7 @@ Lib::loadClass('UI');
 Lib::loadClass('SchemaFactory');
 Lib::loadClass('RefConfig');
 Lib::loadClass('Type_Field');
+Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
 
 class Route_Storage_AclReinstall extends RouteBase {
 
@@ -75,7 +76,6 @@ class Route_Storage_AclReinstall extends RouteBase {
 		}
 	}
 	public function printReinstallAntAclPreview($item) {
-		Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
 		$antAclPath = Schema_SystemObjectFieldStorageAcl::getAntAclXsdBasePath($item['typeName']);
 		if (!file_exists("{$antAclPath}/build.xml")) throw new Exception("Ant build file not exists " . str_replace(APP_PATH_ROOT, 'SE', $antAclPath));
 
@@ -259,7 +259,6 @@ class Route_Storage_AclReinstall extends RouteBase {
 		if (empty($objectItem)) throw new Exception("Missing objectItem in viewXsdSource");
 		DBG::log($objectItem, "viewXsdSource \$objectItem");
 
-		Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
 		$antAclPath = Schema_SystemObjectFieldStorageAcl::getAntAclXsdBasePath($objectItem['typeName']);
 		if (!file_exists("{$antAclPath}/build.xml")) throw new Exception("Ant build file not exists");
 		DBG::log(str_replace(APP_PATH_ROOT, '~', $antAclPath), "viewXsdSource \$antAclPath");
@@ -282,7 +281,6 @@ class Route_Storage_AclReinstall extends RouteBase {
 			UI::alert('danger', $e->getMessage());
 		}
 
-		Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
 		$objFieldAcl = new Schema_SystemObjectFieldStorageAcl();
 		$objFieldAcl->updateCache($namespace);
 
@@ -369,19 +367,19 @@ class Route_Storage_AclReinstall extends RouteBase {
 
 	function _createOrUpdateTableStructure($namespace) {
 		$item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
-		DBG::nicePrint($item, 'DBG:_createOrUpdateTableStructure:$item');
-		$storagePdo = DB::getStorage($item['idDatabase']);
-		$tblStruct = [];
+		DBG::log($item, 'array', 'DBG:_createOrUpdateTableStructure:$item');
+		$currentStruct = [];
 		try {
-			$tblStruct = $storagePdo->getTableStruct($item['_rootTableName']);
+			$currentStruct = DB::getStorage($item['idDatabase'])->getTableStruct($item['_rootTableName']);
 		} catch (Exception $e) {
+			DBG::log($e);
 		}
-		DBG::nicePrint($tblStruct, 'DBG:_createOrUpdateTableStructure:$tblStruct');
+		DBG::log($currentStruct, 'array', 'DBG:_createOrUpdateTableStructure:$currentStruct');
 
 		if (DB::getPDO()->getZasobId() != $item['idDatabase']) throw new Exception("Not imeplemented Create/Update table structure in non default database");
 
-		if (empty($tblStruct)) $this->_createTableStructure($item);
-		else $this->_updateTableStructure($item, $tblStruct);
+		if (empty($currentStruct)) $this->_createTableStructure($item);
+		else $this->_updateTableStructure($item, $currentStruct);
 	}
 	// $item['idDatabase'] => int idDatabase
 	// $item['_rootTableName'] => string tableName
@@ -423,67 +421,178 @@ class Route_Storage_AclReinstall extends RouteBase {
 		// xsd:token
 	// ]
 	function _createTableStructure($item) {
-		$tryConvertFields = array_map(function ($fieldInfo) {
-			if ('ref:' === substr($fieldInfo['xsdType'], 0, 4)) return "Skipped create ref field '{$fieldInfo['xsdType']}'";
-			switch ($fieldInfo['xsdType']) {
-				case 'xsd:integer':
-				case 'p5Type:integer':
-				case 'xsd:positiveInteger':
-				case 'xsd:int': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "int(11)" ];
-				case 'xsd:float': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "float" ];
-				case 'xsd:double': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "double" ];
-				case 'xsd:date': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "date" ];
-				case 'xsd:datetime': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "datetime" ];
-				case 'xsd:string':
-				case 'p5Type:string': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "varchar(255)" ];
-				// TODO: implement more xsd types:
-				// case 'p5Type:decimal':
-				// case 'xsd:decimal': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "decimal" ];
-				// default_db__x3A__BADANIA_W_TERENIE:A_STATUS_Type
-				// default_db__x3A__CRM_PROCES:TYPE_Simple
-				// gml:AbstractFeatureType
-				// gml:PolygonPropertyType
-				// p5:enum
-				// p5:price
-				// p5:www_link
-				// p5Type:date
-				// p5Type:dateTime
-				// p5Type:decimal
-				// p5Type:lineString
-				// p5Type:point
-				// p5Type:polygon
-				// p5Type:text
-				// xsd:decimal
-				// xsd:gYear
-				// xsd:hexBinary
-				// xsd:long
-				// xsd:short
-				// xsd:time
-				// xsd:token
-				default: return "Not implemented type '{$fieldInfo['xsdType']}'";
-			}
-		}, $item['field']);
-		DBG::nicePrint($tryConvertFields, "DBG:create table struct:\$tryConvertFields");
-		$toCreateFields = array_filter($tryConvertFields, function ($fieldInfo) { return is_array($fieldInfo); });
-		DBG::nicePrint($toCreateFields, "DBG:create table struct:\$toCreateFields");
+		$expectedStruct = $this->_makeTableStructure($item);
+		DB::getStorage($item['idDatabase'])->createTableStructure([
+			'tableName' => $item['_rootTableName'],
+			'fields' => $expectedStruct,
+			'primaryKey' => $item['primaryKey'],
+			'keys' => [],
+		]);
+	}
+	function _updateTableStructure($item, $currentStruct) {
+		DBG::log($item, 'array', "DBG:update table struct:\$item");
+		DBG::log($currentStruct, 'array', "DBG:update table struct:\$currentStruct");
+		$expectedStruct = $this->_makeTableStructure($item);
+		DBG::log($expectedStruct, 'array', "DBG:update table struct:\$expectedStruct");
+
+		// $expectedStruct: [ fieldName => shortStruct ]
+		// 	shortStruct:
+		// 		'name' => 'ID',
+		// 		'raw_storage_type' => 'int(11)',
+		// 		'extra' => 'auto_increment',
+
+		// $currentStruct: [ fieldName => fullStruct ]
+		// 	fullStruct:
+		// 		'name' => 'ID',
+		// 		'type' => 'int',
+		// 		'is_nullable' => '0',
+		// 		'default_value' => NULL,
+		// 		'default_is_null' => '1',
+		// 		'max_length' => NULL,
+		// 		'num_precision' => '10',
+		// 		'num_scale' => '0',
+		// 		'char_encoding' => NULL,
+		// 		'char_collation' => NULL,
+		// 		'extra' => 'auto_increment',
+		// 		'raw_storage_type' => 'int(11)',
+
+		$expectedFieldList = array_keys($expectedStruct);
+		$currentFieldList = array_keys($currentStruct);
+
+		// array_diff([ 'a', 'b', 'c' ], [ 'b', 'c', 'd' ]) => [ 'a' ]
+		// array_diff([ 'b', 'c', 'd' ], [ 'a', 'b', 'c' ]) => [ 'd' ]
+		// $toRemoveFieldFromStruct = array_diff($currentFieldList, $expectedFieldList); // TODO: not used, fields defined in base object
+		$toAddFieldToStruct = array_diff($expectedFieldList, $currentFieldList);
+		DBG::log($toRemoveFieldFromStruct, 'array', "DBG:update table struct:\$toRemoveFieldFromStruct");
+		DBG::log($toAddFieldToStruct, 'array', "DBG:update table struct:\$toAddFieldToStruct");
+		if (!empty($toAddFieldToStruct)) {
+			$rootTableName = $item['_rootTableName'];
+			array_map(function ($fieldName) use ($rootTableName, $expectedStruct) {
+				$expectedField = $expectedStruct[$fieldName];
+				$sqlNotNull = ""; // TODO: "NOT NULL" if field can not be null
+				$sqlDefault = ""; // TODO: "DEFAULT {$value}"
+				DB::getPDO()->execSql(" ALTER TABLE {$rootTableName} ADD {$fieldName} {$expectedField['raw_storage_type']} {$sqlNotNull} {$sqlDefault}");
+			}, $toAddFieldToStruct);
+		}
+		$maybeToUpdateFields = array_intersect($currentFieldList, $expectedFieldList);
+		DBG::log($maybeToUpdateFields, 'array', "DBG:update table struct:\$maybeToUpdateFields");
+		if (empty($maybeToUpdateFields)) {
+			UI::alert('info', "No fields to compare");
+			return;
+		}
+		$diffNotes = array_map(function ($fieldName) use ($currentStruct, $expectedStruct) {
+			$currentField = $currentStruct[$fieldName];
+			$expectedField = $expectedStruct[$fieldName];
+			return [
+				'fieldName' => $fieldName,
+				'current_raw_type' => $currentField['raw_storage_type'],
+				'expected_raw_type' => $expectedField['raw_storage_type'],
+				'diff' => ($currentField['raw_storage_type'] === $expectedField['raw_storage_type']) ? "same" : "diff",
+			];
+		}, $maybeToUpdateFields);
+		UI::table([ 'caption' => "Fields types diff:", 'rows' => $diffNotes ]);
+
+		$diffFields = array_filter($diffNotes, function ($item) { return ("diff" === $item['diff']); });
+		if (empty($diffFields)) {
+			UI::alert('info', "Struct is ok");
+			return;
+		}
+		DBG::log($diffFields, 'array', "TODO: update table struct by \$diffFields");
+		throw new Exception("TODO: Not imeplemented Update table structure (Update existing fields)");
+	}
+	function _makeTableStructure($item) {
+		$tryConvertFields = array_map([ $this, '_makeFieldStructure' ], $item['field']);
+
+		DBG::log($tryConvertFields, 'array', "DBG:make table struct:\$tryConvertFields");
+		$toCreateFields = array_filter($tryConvertFields, function ($fieldInfo) { return null !== $fieldInfo; });
+		DBG::log($toCreateFields, 'array', "DBG:make table struct:\$toCreateFields");
 
 		$tblStruct = array_combine(
 			array_map(V::makePick('name'), $toCreateFields),
 			array_values($toCreateFields)
 		);
-		DBG::nicePrint($tblStruct, "DBG:create table struct:\$tblStruct");
+		DBG::log($tblStruct, 'array', "DBG:make table struct:\$tblStruct");
 		if (!array_key_exists($item['primaryKey'], $tblStruct)) throw new Exception("BUG: primaryKey field definition not exists");
 		$tblStruct[$item['primaryKey']]['extra'] = "auto_increment";
 
-		DB::getStorage($item['idDatabase'])->createTableStructure([
-			'tableName' => $item['_rootTableName'],
-			'fields' => $tblStruct,
-			'primaryKey' => $item['primaryKey'],
-			'keys' => [],
-		]);
+		return $tblStruct;
 	}
-	function _updateTableStructure($item, $tblStruct) {
-		throw new Exception("Not imeplemented Update table structure in non default database");
+	function _makeFieldStructure($fieldInfo) {
+		// select distinct xsdType from `CRM_#CACHE_ACL_OBJECT_FIELD` where xsdType not like 'ref:%' order by xsdType;
+		if ('ref:' === substr($fieldInfo['xsdType'], 0, 4)) {
+			DBG::log("Skipped create ref field '{$fieldInfo['xsdType']}'");
+			return null;
+		}
+
+		$fieldName = $fieldInfo['fieldNamespace'];
+		if (!preg_match('/^[a-z_]+$/i', $fieldName)) {
+			DBG::log("Skipped create: not allowed field name '{$fieldName}'");
+			return null;
+		}
+
+		switch ($fieldInfo['xsdType']) {
+			// number
+			case 'xsd:integer':
+			case 'p5Type:integer':
+			case 'xsd:positiveInteger':
+			case 'xsd:int': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "int(11)" ];
+			case 'xsd:short': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "int(11)" ];
+			case 'xsd:long': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "int(11)" ];
+			case 'xsd:float': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "float" ];
+			case 'xsd:double': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "double" ];
+			case 'xsd:decimal': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "decimal(12,2)" ];
+			case 'p5Type:decimal':
+			case 'p5:price': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "decimal(12,2)" ];
+			// time
+			case 'p5Type:date':
+			case 'xsd:date': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "date" ];
+			case 'p5Type:dateTime':
+			case 'xsd:datetime': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "datetime" ];
+			case 'xsd:time': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "time" ];
+			// string
+			case 'xsd:string':
+			case 'p5Type:string': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "varchar(255)" ];
+			case 'xsd:token': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "varchar(255)" ];
+			case 'p5Type:text': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "text" ];
+			// geom
+			case 'p5Type:polygon': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "polygon", 'default' => "NULL" ];
+			case 'p5Type:lineString': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "linestring", 'default' => "NULL" ];
+			case 'p5Type:point': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "point", 'default' => "NULL" ];
+			case 'gml:AbstractFeatureType': return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "polygon", 'default' => "NULL" ];
+			// TODO: ???: 'gml:PolygonPropertyType'
+
+			case 'p5:enum': {
+				// [A_STATUS] => Array:
+				// 	[type] => p5:enum
+				// 	[minOccurs] => 0
+				// 	[maxOccurs] => 1
+				// 	[restrictions] => Array:
+				// 		[enumeration] => Array:
+				// 			[NORMAL] => NORMAL
+				// 			[WAITING] => WAITING
+				// 			[MONITOR] => MONITOR
+				// 			[DELETED] => DELETED
+				// 			[WARNING] => WARNING
+				// 			[OFF_SOFT] => OFF_SOFT
+				// 			[OFF_HARD] => OFF_HARD
+				$xsdRestrictions = Schema_SystemObjectFieldStorageAcl::getXsdRestrictionsValue($fieldInfo);
+				DBG::log($xsdRestrictions, 'array', "DBG: p5:enum xsdRestrictions for field('{$fieldInfo['fieldNamespace']}')");
+				return [ 'name' => $fieldInfo['fieldNamespace'], 'raw_storage_type' => "enum(" .
+					implode(",", array_map(function ($value) { return "'{$value}'"; }, array_keys($xsdRestrictions['enumeration']))) .
+				")" ];
+			}
+
+			// TODO: implement more xsd types:
+			// case 'default_db__x3A__BADANIA_W_TERENIE:A_STATUS_Type':
+			// case 'default_db__x3A__CRM_PROCES:TYPE_Simple':
+			// case 'p5:www_link':
+			// case 'xsd:gYear':
+			// case 'xsd:hexBinary':
+			default: {
+				DBG::log($fieldInfo, 'array', "TODO: _makeFieldStructure '{$fieldInfo['xsdType']}' (SystemObject/fieldInfo)"); // $fieldInfo = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ])['field'];
+				throw new Exception("Not implemented type '{$fieldInfo['xsdType']}'");
+			}
+		}
 	}
 
 }

+ 3 - 3
SE/se-lib/Schema/SystemObjectFieldStorageAcl.php

@@ -339,7 +339,7 @@ class Schema_SystemObjectFieldStorageAcl extends Core_AclSimpleSchemaBase {
 							];
 							$childrens = null;
 							$restrictions = [];
-							foreach ($this->getXsdRestrictionsValue($field) as $k => $v) {
+							foreach (self::getXsdRestrictionsValue($field) as $k => $v) {
 								if ('enumeration' == $k) {
 									foreach ($v as $enumValue) {
 										$restrictions[] = [ 'xsd:enumeration', [ 'value' => $enumValue ], null ];
@@ -487,8 +487,8 @@ class Schema_SystemObjectFieldStorageAcl extends Core_AclSimpleSchemaBase {
 		"));
 	}
 
-	public function getXsdRestrictionsValue($item) {
-		$xsdRestrictions = @json_decode($item['xsdRestrictions'], $assoc = true);
+	static function getXsdRestrictionsValue($fieldInfo) {
+		$xsdRestrictions = @json_decode($fieldInfo['xsdRestrictions'], $assoc = true);
 		if (empty($xsdRestrictions)) $xsdRestrictions = [];
 		if (array_key_exists('__DBG__', $xsdRestrictions)) unset($xsdRestrictions['__DBG__']);
 		return $xsdRestrictions;