فهرست منبع

fixed code style in AclHelper

Piotr Labudda 8 سال پیش
والد
کامیت
47fda18faf
1فایلهای تغییر یافته به همراه425 افزوده شده و 425 حذف شده
  1. 425 425
      SE/se-lib/Core/AclHelper.php

+ 425 - 425
SE/se-lib/Core/AclHelper.php

@@ -7,80 +7,80 @@ Lib::loadClass('Route_UrlAction');
 
 class Core_AclHelper {// Helper class for Acl
 
-  public static function hasCreatePerms($acl) {
-    foreach ($acl->getFieldListByIdZasob() as $fieldName) {// TODO: use getFieldList
-      // echo"<p>\$acl->canCreateField({$fieldName}): (".$acl->canCreateField($fieldName).")</p>";
+	public static function hasCreatePerms($acl) {
+		foreach ($acl->getFieldListByIdZasob() as $fieldName) {// TODO: use getFieldList
+			// echo"<p>\$acl->canCreateField({$fieldName}): (".$acl->canCreateField($fieldName).")</p>";
 			DBG::log($acl->canCreateField($fieldName), 'array', "\$acl->canCreateField({$fieldName})");
-      if ($acl->canCreateField($fieldName)) return true;
-    }
-    return false;
-  }
-
-  public static function hasGeomFields($acl) {
-    foreach ($acl->getFieldListByIdZasob() as $fieldName) {
-      // echo"<p>\$acl->isGeomField({$fieldName}): (".$acl->isGeomField($fieldName).") \$acl->canReadField({$fieldName}): (".$acl->canReadField($fieldName).")</p>";
-      if ($acl->isGeomField($fieldName) && $acl->canReadField($fieldName)) return true;
-    }
-    return false;
-  }
-
-  // @returns array [ field => string(perms like 'RWX') ]
-  public static function getFieldPerms($acl) {// TODO: fetch perms for given Acl by namespace
-    // TODO:? cache session or only current request (static)
-    $fieldPerms = array();
-    foreach ($acl->getFields() as $idField => $field) {
-      $fieldPerms[ $field['name'] ] = $field['perms'];
-    }
-    return $fieldPerms;
-  }
-
-  public static function getExportFieldList($acl) {
-    $exportFields = array();
+			if ($acl->canCreateField($fieldName)) return true;
+		}
+		return false;
+	}
+
+	public static function hasGeomFields($acl) {
+		foreach ($acl->getFieldListByIdZasob() as $fieldName) {
+			// echo"<p>\$acl->isGeomField({$fieldName}): (".$acl->isGeomField($fieldName).") \$acl->canReadField({$fieldName}): (".$acl->canReadField($fieldName).")</p>";
+			if ($acl->isGeomField($fieldName) && $acl->canReadField($fieldName)) return true;
+		}
+		return false;
+	}
+
+	// @returns array [ field => string(perms like 'RWX') ]
+	public static function getFieldPerms($acl) {// TODO: fetch perms for given Acl by namespace
+		// TODO:? cache session or only current request (static)
+		$fieldPerms = array();
+		foreach ($acl->getFields() as $idField => $field) {
+			$fieldPerms[ $field['name'] ] = $field['perms'];
+		}
+		return $fieldPerms;
+	}
+
+	public static function getExportFieldList($acl) {
+		$exportFields = array();
 		foreach (self::getFieldPerms($acl) as $fieldName => $perms) {
-      if (false !== strpos($perms, 'E')) {
+			if (false !== strpos($perms, 'E')) {
 				$exportFields[] = $fieldName;
 			}
 		}
 		return $exportFields;
-  }
+	}
 
-  public static function getAclByTypeName($typeName, $forceTblAclInit = false) {// TODO: replace getAclFromTypeName in WFS
-    return self::getAclByNamespace(str_replace(':', '/', $typeName), $forceTblAclInit);
+	public static function getAclByTypeName($typeName, $forceTblAclInit = false) {// TODO: replace getAclFromTypeName in WFS
+		return self::getAclByNamespace(str_replace(':', '/', $typeName), $forceTblAclInit);
 	}
-  public static function getAclByNamespace($namespace, $forceTblAclInit = false, $objItem = null) { // TODO: mv to ACL
-    try {
-      if (!$objItem) {
-        Lib::loadClass('SchemaFactory');
-        $objItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem(str_replace('__x3A__', '/', $namespace), ['propertyName'=>"*,field"]);
-      }
-      DBG::log($objItem, 'array', "DBG objItem({$namespace})");
-      if (!$objItem['idZasob']) throw new Exception("Missing idZasob for namespace '{$namespace}'");
-      if (!in_array($objItem['_type'], [
-        // 'TableAcl', // TODO: TEST - to replace TableAcl by AntAcl or use object with namespace + '/tableName'?
-        'AntAcl',
-      ])) throw new Exception("Not Implemented acl type '{$objItem['_type']}'");
-      if (!$objItem['isObjectActive']) {
-        if (!$objItem['hasStruct']) throw new Exception("namespace has no structure '{$namespace}'");
-        if (!$objItem['isStructInstalled']) throw new Exception("namespace structure not installed '{$namespace}'");
-        throw new Exception("namespace is not activated '{$namespace}'");
-      }
-
-      Lib::loadClass('AntAclBase');
-      $acl = AntAclBase::buildInstance($objItem['idZasob'], $objItem);
-      return $acl;
-    } catch (Exception $e) {
-      DBG::log($e);
-    }
-
-    $ns = self::parseNamespaceUrl($namespace);
-
-    DBG::log($ns, 'array', "parseNamespaceUrl({$namespace})");
-    $acl = User::getAcl()->getObjectAcl($ns['prefix'], $ns['name']);
-    $acl->init($forceTblAclInit);
-    return $acl;
+	public static function getAclByNamespace($namespace, $forceTblAclInit = false, $objItem = null) { // TODO: mv to ACL
+		try {
+			if (!$objItem) {
+				Lib::loadClass('SchemaFactory');
+				$objItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem(str_replace('__x3A__', '/', $namespace), ['propertyName'=>"*,field"]);
+			}
+			DBG::log($objItem, 'array', "DBG objItem({$namespace})");
+			if (!$objItem['idZasob']) throw new Exception("Missing idZasob for namespace '{$namespace}'");
+			if (!in_array($objItem['_type'], [
+				// 'TableAcl', // TODO: TEST - to replace TableAcl by AntAcl or use object with namespace + '/tableName'?
+				'AntAcl',
+			])) throw new Exception("Not Implemented acl type '{$objItem['_type']}'");
+			if (!$objItem['isObjectActive']) {
+				if (!$objItem['hasStruct']) throw new Exception("namespace has no structure '{$namespace}'");
+				if (!$objItem['isStructInstalled']) throw new Exception("namespace structure not installed '{$namespace}'");
+				throw new Exception("namespace is not activated '{$namespace}'");
+			}
+
+			Lib::loadClass('AntAclBase');
+			$acl = AntAclBase::buildInstance($objItem['idZasob'], $objItem);
+			return $acl;
+		} catch (Exception $e) {
+			DBG::log($e);
+		}
+
+		$ns = self::parseNamespaceUrl($namespace);
+
+		DBG::log($ns, 'array', "parseNamespaceUrl({$namespace})");
+		$acl = User::getAcl()->getObjectAcl($ns['prefix'], $ns['name']);
+		$acl->init($forceTblAclInit);
+		return $acl;
 	}
 
-  public static function getMoreFunctionsCell($acl, $args) {
+	public static function getMoreFunctionsCell($acl, $args) {
 		$id = V::get('primary_key', 0, $args, 'int');
 		if ($id <= 0) throw new HttpException("404", 404);
 		$record = V::get('record', null, $args);
@@ -203,369 +203,369 @@ class Core_AclHelper {// Helper class for Acl
 			}
 		}
 
-    if (1) {// Druki
-      $parsedNs = self::parseNamespaceUrl($acl->getNamespace());
-      // array (
-      //   'name' => 'TEST_PERMS',
-      //   'prefix' => 'default_db',
-      //   'url' => 'https://biuro.biall-net.pl/wfs/default_db',
-      //   'sourceName' => 'default_db',
-      // ),
-      $typeName = "{$parsedNs['prefix']}:{$parsedNs['name']}";
-      DBG::log([
-        'msg' => "getMoreFunctionsCell Druki",
-        'namespace' => $acl->getNamespace(),
-        'typeName' => $typeName,
-        'primaryKey' => $id,
-        'parseNamespace' => $parsedNs,
-      ]);
-      $rowFunList[] = [
-        'href' => Request::getPathUri() . "index.php?_route=UrlAction_Ant&typeName={$typeName}&primaryKey={$id}",
-        'ico' => 'glyphicon glyphicon-file',
-        'label' => "Druki",
-        'title' => "Druki"
-      ];
-    }
-    DBG::log(['msg'=>"\$rowFunList", '$rowFunList'=>$rowFunList]);
+		if (1) {// Druki
+			$parsedNs = self::parseNamespaceUrl($acl->getNamespace());
+			// array (
+			//	 'name' => 'TEST_PERMS',
+			//	 'prefix' => 'default_db',
+			//	 'url' => 'https://biuro.biall-net.pl/wfs/default_db',
+			//	 'sourceName' => 'default_db',
+			// ),
+			$typeName = "{$parsedNs['prefix']}:{$parsedNs['name']}";
+			DBG::log([
+				'msg' => "getMoreFunctionsCell Druki",
+				'namespace' => $acl->getNamespace(),
+				'typeName' => $typeName,
+				'primaryKey' => $id,
+				'parseNamespace' => $parsedNs,
+			]);
+			$rowFunList[] = [
+				'href' => Request::getPathUri() . "index.php?_route=UrlAction_Ant&typeName={$typeName}&primaryKey={$id}",
+				'ico' => 'glyphicon glyphicon-file',
+				'label' => "Druki",
+				'title' => "Druki"
+			];
+		}
+		DBG::log(['msg'=>"\$rowFunList", '$rowFunList'=>$rowFunList]);
 		return $rowFunList;
 	}
 
-  public static function getAclList() { return self::getCustomAclList(); } // TODO: RMME renamed to getCustomAclList
-  public static function getCustomAclList() {// @usage Core_AclHelper::getCustomAclList();// @returns array [ $typeName , ... ]
-    $aclList = array();
-    // Schema_AccessGroupStorageAcl, load by User::getAcl()->getObjectAcl('default_objects', $objName);
-    //    $objClassName = "Schema_{$objName}StorageAcl";
-    //    if (!Lib::tryLoadClass($objClassName)) throw new HttpException("Not implemented", 501);
-    // $ grep -r 'class ' SE/se-lib/Schema/*Acl.php
-    // SE/se-lib/Schema/AccessGroupStorageAcl.php:class Schema_AccessGroupStorageAcl extends Core_AclBase
-    // SE/se-lib/Schema/AccessOwnerStorageAcl.php:class Schema_AccessOwnerStorageAcl extends Core_AclBase
-    // SE/se-lib/Schema/FileStorageAcl.php:class Schema_FileStorageAcl extends Core_AclBase
-    // SE/se-lib/Schema/KorespondencjaStorageAcl.php:class Schema_KorespondencjaStorageAcl extends Core_AclBase
-    // SE/se-lib/Schema/TestPermsStorageAcl.php:class Schema_TestPermsStorageAcl extends Core_AclBase
-    $aclList[] = 'default_objects:AccessGroupRead';
-    $aclList[] = 'default_objects:AccessGroupWrite';
-    $aclList[] = 'default_objects:AccessOwner';
-    $aclList[] = 'default_objects:SystemObject';// tabele i obiekty możliwe do podłączenia do procesu (default_db/*, default_objects/*)
-    $aclList[] = 'default_objects:SystemFunction';// funkcje możliwe do podłączenia do procesu UrlAction
-    // $aclList[] = 'default_objects:UserFunction';// TODO: funkcje możliwe do uruchomienia przez usera
-    // $aclList[] = 'default_objects:UserObject';// TODO: tabele i obiekty widoczne dla aktualnego usera
-    $aclList[] = 'default_objects:SystemProcess';// wszystkie proces init
-    $aclList[] = 'default_objects:UserProcess';// proces init przypisane do aktualnego usera
-    $aclList[] = 'default_objects:UserTestStats';// TODO: testy stats by user proces init
-    $aclList[] = 'default_objects:File';
-    $aclList[] = 'default_objects:Korespondencja';
-    $aclList[] = 'default_objects:TestPerms';
-
-    // TODO: read from Database
-    // $aclList[] = 'default_db__x3A__TEST_PERMS:TEST_PERMS';// uproszczona wersja: default_db:TEST_PERMS
-
-    $cleanHostName = str_replace(array(".", "-"), '_', $_SERVER['SERVER_NAME']);
-    if (file_exists(APP_PATH_SCHEMA . "/gui/company/{$cleanHostName}/get_object_list.php")) {
-      $objList = include APP_PATH_SCHEMA . "/gui/company/{$cleanHostName}/get_object_list.php";
-      if (!empty($objList) && is_array($objList)) {
-        foreach ($objList as $objectName) {
-          if (!in_array($objectName, $aclList)) $aclList[] = $objectName;
-        }
-      }
-    }
-
-    return $aclList;
-  }
-
-  public static function parseTypeName($typeName) {
-    return self::parseNamespaceUrl(str_replace(':', '/', $typeName));
-  }
-  /**
-   * Parse namespace url into parts.
-   *
-   * @param $namespace - absolute or relative url
-   * @return array:
-   *   name: element name
-   *   url: url wihtout name
-   *   prefix: xml prefix
-   *   sourceName: used by engine - maybe to remove (used by Core_AclHelper::getAclByNamespace($namespace))
-   *
-   * @example - create xmlns attribute:
-   *    xmlns:{$ns['prefix']}="{$ns['url']}"
-   *
-   * @example - wfs typeName:
-   *    typeName = "{$ns['prefix']}:{$ns['name']}"
-   *
-   * @example 'default_db/TEST_PERMS' => Array:
-   *    [name] => TEST_PERMS
-   *    [prefix] => default_db
-   *    [url] => https://biuro.biall-net.pl/wfs/default_db
-   *    [sourceName] => default_db
-   *
-   * @example 'default_objects/AccessOwner' => Array:
-   *    [name] => AccessOwner
-   *    [prefix] => default_objects
-   *    [url] => https://biuro.biall-net.pl/wfs/default_objects
-   *    [sourceName] => default_objects
-   *
-   * @example 'default_db/ZALICZKA/Zaliczka' => Array:
-   *    [name] => Zaliczka
-   *    [prefix] => default_db__x3A__Zaliczka
-   *    [url] => https://biuro.biall-net.pl/wfs/default_db/ZALICZKA
-   *    [sourceName] => table_objects
-   *
-   */
-  public static function parseNamespaceUrl($namespace) {// returns assoc array: [ 'name', 'url', 'prefix', 'sourceName' ]
-    // TODO: the same algo like getAclByNamespace($namespace)
-    $baseNsUri = Api_WfsNs::getBaseWfsUri();
-    if ('http' != substr($namespace, 0, 4)) $namespace = "{$baseNsUri}/{$namespace}";//Request::getHostUri() . '/' . $namespace;
-
-    $nsUrl = $baseNsUri . '/' . '';
-    if ("{$baseNsUri}/" != substr($namespace, 0, strlen($baseNsUri) + 1)) throw new HttpException("Zasoby zewnętrzenj systemu nie są jeszcze zaimplementowane", 501);
-
-  	$relativeNsUrl = substr($namespace, strlen($baseNsUri) + 1);
-    // convert '__x3A__' to '/' in url
-  	$nsEx = explode('/', str_replace('__x3A__', '/', $relativeNsUrl));// "http://biuro.biall-net.pl/wfs/  default_db/{$nazwa_tabeli}/{$nazwa_obj}
-    // default_db__x3A__ZALICZKA/Zaliczka => default_db/ZALICZKA/Zaliczka
-    $sourceName = array_shift($nsEx);// remove first element - source name
-    $objName = array_pop($nsEx);// name is always last part from url
-
-    if ('default_db' == $sourceName || 'p5_default_db' == $sourceName) {
-      if (count($nsEx) > 1) throw new Exception("Nieznany namespace default_db: '{$relativeNsUrl}'", 501);
-
-    	$sourceName = 'default_db';
-      $nsPrefix = $sourceName;
-    	if (1 == count($nsEx)) {
-        $sourceName = 'table_objects';// TODO: another source name to read from simpleSchema @see Core_AclSimpleSchemaBase
-        $nsPrefix = 'default_db__x3A__' . $nsEx[0];
-      }
-      // $objName = $nsEx[1];// 'default_db/ZALICZKA:Zaliczka' => ('objects', 'Zaliczka') - possible name conflicts
-      $nsUrl = trim($baseNsUri . '/default_db/' . implode("/", $nsEx), '/');
-      return [ 'name' => $objName, 'prefix' => $nsPrefix, 'url' => $nsUrl, 'sourceName' => $sourceName ];
-    }
-    else if ('default_objects' == $sourceName || 'SystemObjects' == $sourceName) {
-      if (count($nsEx) > 1) throw new Exception("Nieznany namespace SystemObjects: '{$relativeNsUrl}'", 501);
-
-      $sourceName = 'default_objects';
-      $nsUrl = trim($baseNsUri . '/default_objects/' . implode("/", $nsEx), '/');
-      $nsPrefix = 'default_objects';
-  		return [ 'name' => $objName, 'prefix' => $nsPrefix, 'url' => $nsUrl, 'sourceName' => $sourceName ];
-    }
-    else if ('p5_objects' == $sourceName || 'objects' == $sourceName) {
-      if (count($nsEx) > 1) throw new Exception("Nieznany namespace SystemObjects: '{$relativeNsUrl}'", 501);
-
-      $sourceName = 'default_objects';
-      $nsUrl = trim($baseNsUri . '/default_objects/' . implode("/", $nsEx), '/');
-      $nsPrefix = 'default_objects';
-  		return [ 'name' => $objName, 'prefix' => $nsPrefix, 'url' => $nsUrl, 'sourceName' => $sourceName ];
-    }
-    else if ('zasob_' == substr($sourceName, 0, 6)) {
-      $dbName = substr($sourceName, 6);// database id
-      $remotePdo = DB::getPDO($dbName);
-      DBG::log($remotePdo, 'array', '$remotePdo');
-      if (!$remotePdo || $remotePdo->getZasobId() <= 0) throw new Exception("Database [{$dbName}] not exists - namespace '{$relativeNsUrl}'", 501);
-      if (count($nsEx) > 0) throw new Exception("Nieznany namespace {$sourceName}: '{$relativeNsUrl}'", 501);
-      return [ 'name' => $objName, 'prefix' => $sourceName, 'url' => implode('/', [$baseNsUri, $sourceName, $objName]), 'sourceName' => $sourceName ];
-    }
-    else throw new Exception("Nieznany namespace '{$relativeNsUrl}'", 501);
-  }
-  public static function getIdDatabaseFromNamespace($namespace) {
-    $ns = self::parseNamespaceUrl($namespace);
-    if ('default_db' == substr($ns['sourceName'], 0, strlen('default_db'))) {
-      return DB::getPDO()->getZasobId();
-    } else if ('default_objects' == substr($ns['sourceName'], 0, strlen('default_objects'))) {
-      return DB::getPDO()->getZasobId();
-    } else if ('table_objects' == $ns['sourceName']) {
-      if ('default_db' == substr($ns['prefix'], 0, strlen('default_db'))) {
-        return DB::getPDO()->getZasobId();
-      }
-    } else if ('zasob_' == substr($ns['sourceName'], 0, strlen('zasob_'))) {
-      // 'zasob_931', 'zasob_931__x3A__...'
-      $idDatabase = substr($ns['sourceName'], strlen('zasob_'));
-      if (false !== strpos($idDatabase, '_')) $idDatabase = substr($idDatabase, 0, strpos($idDatabase, '_'));
-      if (!$idDatabase || !is_numeric($idDatabase)) throw new Exception("Not implemented idDatabase({$idDatabase})");
-      return $idDatabase;
-    }
-    throw new Exception("Not implemented idDatabase for namespace({$namespace})");
-  }
-
-  public static function insertRef($objectName, $pk, $childName, $childPk) {// TODO: $idTransaction
-    $refTable = self::getRefTable($objectName, $childName);
-    $sqlPk = DB::getPDO()->quote($pk, PDO::PARAM_STR);
-    $sqlChildPk = DB::getPDO()->quote($childPk, PDO::PARAM_STR);
-    DB::getPDO()->exec("
-      insert into `{$refTable}` (`PRIMARY_KEY`, `REMOTE_PRIMARY_KEY`)
-      values ({$sqlPk}, {$sqlChildPk})
-    ");
-  }
-
-  public static function cleanRefs($objectName, $pk, $childName) {// TODO: $idTransaction
-    $refTable = self::getRefTable($objectName, $childName);
-    $sqlPk = DB::getPDO()->quote($pk, PDO::PARAM_STR);
-    DB::getPDO()->exec("
-      update `{$refTable}` set `A_STATUS` = 'DELETED'
-      where `PRIMARY_KEY` = {$sqlPk}
-    ");
-  }
-
-  public static function getRefTable($objectName, $childName) {// TODO: wrong - add prefix to avoid name collisions or generate unique hash
-    static $cacheRefTables = array();
-    $refTable = "{$objectName}__#REF__{$childName}";
-    if (in_array($refTable, $cacheRefTables)) return $refTable;
-    DB::getPDO()->exec("
-      CREATE TABLE IF NOT EXISTS `{$refTable}` (
-        `PRIMARY_KEY` int(11) NOT NULL,
-        `REMOTE_PRIMARY_KEY` int(11) NOT NULL,
-        `REMOTE_TYPENAME` varchar(255) NOT NULL DEFAULT '',
-        `A_STATUS` enum('WAITING', 'NORMAL', 'DELETED') NOT NULL DEFAULT 'WAITING',
-        `A_RECORD_UPDATE_DATE` timestamp ON UPDATE CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-        -- TODO `TRANACTION_ID` int(11) NOT NULL
-        KEY `PRIMARY_KEY` (`PRIMARY_KEY`),
-        KEY `REMOTE_PRIMARY_KEY` (`REMOTE_PRIMARY_KEY`)
-      ) ENGINE=MyISAM DEFAULT CHARSET=latin2;
-    ");
-    try {
-      DB::getPDO()->exec(" ALTER TABLE `{$refTable}` ADD `A_STATUS` enum('WAITING', 'NORMAL', 'DELETED') NOT NULL DEFAULT 'WAITING' ");
-    } catch (Exception $e) {
-      // echo 'C.'.get_class($this).' L.' . __LINE__ . " Error:";print_r($e->getMessage());echo "\n";
-    }
-    try {
-      DB::getPDO()->exec(" ALTER TABLE `{$refTable}` ADD `A_RECORD_UPDATE_DATE` timestamp ON UPDATE CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ");
-    } catch (Exception $e) {
-      // echo 'C.'.get_class($this).' L.' . __LINE__ . " Error:";print_r($e->getMessage());echo "\n";
-    }
-    try {
-      DB::getPDO()->exec(" ALTER TABLE `{$refTable}` ADD `REMOTE_TYPENAME` varchar(255) NOT NULL DEFAULT '' ");
-    } catch (Exception $e) {
-      // echo 'C.'.get_class($this).' L.' . __LINE__ . " Error:";print_r($e->getMessage());echo "\n";
-    }
-    $cacheRefTables[] = $refTable;
-    return $refTable;
-  }
-
-  public static function getInstanceTable($rootTableName) {
-    static $cacheInstanceTables = array();
-    $instanceTable = "{$rootTableName}__#INSTANCE";
-    if (in_array($instanceTable, $cacheInstanceTables)) return $instanceTable;
-    DB::getPDO()->execSql("
-      CREATE TABLE IF NOT EXISTS `{$instanceTable}` (
-        `PRIMARY_KEY` int(11) NOT NULL,
-        `A_RECORD_UPDATE_DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-        `INSTANCE_NAME` varchar(255) NOT NULL,
-        UNIQUE KEY `PRIMARY_KEY` (`PRIMARY_KEY`),
-        KEY `INSTANCE_NAME` (`INSTANCE_NAME`)
-        -- TODO `A_TRANACTION_ID` int(11) NOT NULL DEFAULT 0
-      ) ENGINE=MyISAM DEFAULT CHARSET=latin2;
-    ");
-    DB::getPDO()->execSql("
-      CREATE TABLE IF NOT EXISTS `{$instanceTable}_HIST` (
-        `ID` int(11) NOT NULL AUTO_INCREMENT,
-        `PRIMARY_KEY` int(11) NOT NULL,
-        `A_TRANACTION_ID` int(11) NOT NULL DEFAULT 0,
-        `A_RECORD_UPDATE_DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-        `INSTANCE_NAME` varchar(255) NOT NULL,
-        PRIMARY KEY (`ID`),
-        KEY `PRIMARY_KEY` (`PRIMARY_KEY`)
-      ) ENGINE=MyISAM DEFAULT CHARSET=latin2;
-    ");
-    $cacheInstanceTables[] = $instanceTable;
-    return $instanceTable;
-  }
-  public static function setInstance($rootTableName, $pk, $instanceName, $idTransaction = 0) {
-    $instanceTable = self::getInstanceTable($rootTableName);
-    $pk = intval($pk);
-    // TODO: if $pk < 0 throw new Exception("...");
-    $sql = [
-      'instanceName' => DB::getPDO()->quote($instanceName, PDO::PARAM_STR),
-      'idTransaction' => intval($idTransaction)
-    ];
-    DB::getPDO()->exec("
-      insert into `{$instanceTable}_HIST` (`PRIMARY_KEY`, `INSTANCE_NAME`, `A_TRANACTION_ID`)
-        values({$pk}, {$sql['instanceName']}, {$idTransaction})
-    ");
-  }
-
-  public static function getChildHistTable($rootTableName, $childName, $schema) {
-    // $childName(id) => Array:
-    //     [@type] => xsd:integer
-    // $childName(created) => Array:
-    //     [@type] => xsd:date
-    // $childName(worker) => Array:
-    //     [@ref] => default_objects/AccessOwner
-    // $childName(kwota) => Array:
-    //     [@type] => xsd:decimal
-    //     [@totalDigits] => 16
-    //     [@fractionDigits] => 2
-    // $childName(nierozliczona_kwota) => Array:
-    //     [@type] => xsd:decimal
-    //     [@totalDigits] => 16
-    //     [@fractionDigits] => 2
-    // $childName(pozycja) => Array:
-    //     [@ref] => ZaliczkaPozycja
-    //     [@maxOccurs] => unbounded
-    static $cacheHistTables = array();
-    $histTable = "{$rootTableName}__#HIST__{$childName}";
-    if (in_array($histTable, $cacheHistTables)) return $histTable;
-    $sqlType = '';
-    switch ($schema['@type']) {
-      case 'xsd:integer': $sqlType = "int(11) NOT NULL DEFAULT 0"; break;
-      case 'xsd:date': $sqlType = "date DEFAULT NULL"; break;
-      case 'xsd:decimal': $sqlType = "decimal(" . V::get('@totalDigits', 16, $schema) . ", " . V::get('@fractionDigits', 2, $schema) . ") NOT NULL DEFAULT 0"; break;
-      case 'xsd:string': $sqlType = "varchar(255) NOT NULL DEFAULT ''"; break;
-      // TODO: type alias like enum fields: @type => "{$prefix}:{$field_name}Type"
-    }
-    if (!$sqlType && !empty($schema['@ref'])) $sqlType = "int(11) NOT NULL DEFAULT 0";// TODO: type from ref instance @primaryKey - mostly int
-    if (!$sqlType) throw new Exception("Unimplemented schema to sql for '{$rootTableName}/{$childName}' schema(".json_encode($schema).")");
-    DB::getPDO()->exec("
-      CREATE TABLE IF NOT EXISTS `{$histTable}` (
-        `ID` int(11) NOT NULL AUTO_INCREMENT,
-        `VALUE` {$sqlType},
-        `A_TRANSACTION_ID` int(11) NOT NULL DEFAULT 0,
-        PRIMARY KEY (`ID`)
-      ) ENGINE=MyISAM DEFAULT CHARSET=latin2;
-    ");
-    $cacheHistTables[] = $histTable;
-    return $histTable;
-  }
-
-  public static function getTransactionTable($rootTableName) {
-    static $cacheTransactionTables = array();
-    $transactionTable = "{$rootTableName}__#TRANSACTION";
-    if (in_array($transactionTable, $cacheTransactionTables)) return $transactionTable;
-    DB::getPDO()->exec("
-      CREATE TABLE IF NOT EXISTS `{$transactionTable}` (
-        `ID` int(11) NOT NULL AUTO_INCREMENT,
-        `A_ACTION_ID_USER` int(11) DEFAULT NULL, -- NULL for scripts
-        `A_ACTION_AUTHOR` varchar(255) NOT NULL DEFAULT '',
-        `A_ACTION_DATE` timestamp ON UPDATE CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-        `A_STATUS` enum('WAITING', 'NORMAL', 'DELETED') NOT NULL DEFAULT 'WAITING',
-        `A_CONTEXT_TRANSACTION` varchar(255) NOT NULL DEFAULT '',
-        PRIMARY KEY (`ID`)
-      ) ENGINE=MyISAM DEFAULT CHARSET=latin2;
-    ");
-    $cacheTransactionTables[] = $transactionTable;
-    return $transactionTable;
-  }
-
-  public static function startTransaction($rootTableName, $idUser, $author = '') {
-    $refTable = self::getTransactionTable($rootTableName);
-    $sqlIdUser = ((int)$idUser > 0) ? DB::getPDO()->quote($idUser, PDO::PARAM_INT) : 'NULL';
-    $sqlAuthor = DB::getPDO()->quote($author, PDO::PARAM_STR);
-    DB::getPDO()->exec("
-      insert into `{$refTable}` (`A_ACTION_ID_USER`, `A_ACTION_AUTHOR`)
-      values ({$sqlIdUser}, {$sqlAuthor})
-    ");
-    return DB::getPDO()->lastInsertId();
-  }
-
-  public static function rollbackTransaction($rootTableName, $idTransaction) {
-    // TODO: ROLLBACK - do nothing
-  }
-
-  public static function commitTransaction($idTransaction, $simpleSchema_or_acl) {
-    // TODO: COMMIT
-    // TODO: save changes to rootTableName and every childrens - recurence
-  }
-
-  public static function commitContextTransaction($rootTableName, $rootIdTransaction, $simpleSchema_or_acl_for_child) {
-    // TODO: COMMIT - changes for childrens
-    // TODO: find transaction with context transaction like "{$rootTableName}.{$rootIdTransaction}" = A_CONTEXT_TRANSACTION
-    // TODO: save changes to rootTableName and every childrens - recurence
-  }
+	public static function getAclList() { return self::getCustomAclList(); } // TODO: RMME renamed to getCustomAclList
+	public static function getCustomAclList() {// @usage Core_AclHelper::getCustomAclList();// @returns array [ $typeName , ... ]
+		$aclList = array();
+		// Schema_AccessGroupStorageAcl, load by User::getAcl()->getObjectAcl('default_objects', $objName);
+		//		$objClassName = "Schema_{$objName}StorageAcl";
+		//		if (!Lib::tryLoadClass($objClassName)) throw new HttpException("Not implemented", 501);
+		// $ grep -r 'class ' SE/se-lib/Schema/*Acl.php
+		// SE/se-lib/Schema/AccessGroupStorageAcl.php:class Schema_AccessGroupStorageAcl extends Core_AclBase
+		// SE/se-lib/Schema/AccessOwnerStorageAcl.php:class Schema_AccessOwnerStorageAcl extends Core_AclBase
+		// SE/se-lib/Schema/FileStorageAcl.php:class Schema_FileStorageAcl extends Core_AclBase
+		// SE/se-lib/Schema/KorespondencjaStorageAcl.php:class Schema_KorespondencjaStorageAcl extends Core_AclBase
+		// SE/se-lib/Schema/TestPermsStorageAcl.php:class Schema_TestPermsStorageAcl extends Core_AclBase
+		$aclList[] = 'default_objects:AccessGroupRead';
+		$aclList[] = 'default_objects:AccessGroupWrite';
+		$aclList[] = 'default_objects:AccessOwner';
+		$aclList[] = 'default_objects:SystemObject';// tabele i obiekty możliwe do podłączenia do procesu (default_db/*, default_objects/*)
+		$aclList[] = 'default_objects:SystemFunction';// funkcje możliwe do podłączenia do procesu UrlAction
+		// $aclList[] = 'default_objects:UserFunction';// TODO: funkcje możliwe do uruchomienia przez usera
+		// $aclList[] = 'default_objects:UserObject';// TODO: tabele i obiekty widoczne dla aktualnego usera
+		$aclList[] = 'default_objects:SystemProcess';// wszystkie proces init
+		$aclList[] = 'default_objects:UserProcess';// proces init przypisane do aktualnego usera
+		$aclList[] = 'default_objects:UserTestStats';// TODO: testy stats by user proces init
+		$aclList[] = 'default_objects:File';
+		$aclList[] = 'default_objects:Korespondencja';
+		$aclList[] = 'default_objects:TestPerms';
+
+		// TODO: read from Database
+		// $aclList[] = 'default_db__x3A__TEST_PERMS:TEST_PERMS';// uproszczona wersja: default_db:TEST_PERMS
+
+		$cleanHostName = str_replace(array(".", "-"), '_', $_SERVER['SERVER_NAME']);
+		if (file_exists(APP_PATH_SCHEMA . "/gui/company/{$cleanHostName}/get_object_list.php")) {
+			$objList = include APP_PATH_SCHEMA . "/gui/company/{$cleanHostName}/get_object_list.php";
+			if (!empty($objList) && is_array($objList)) {
+				foreach ($objList as $objectName) {
+					if (!in_array($objectName, $aclList)) $aclList[] = $objectName;
+				}
+			}
+		}
+
+		return $aclList;
+	}
+
+	public static function parseTypeName($typeName) {
+		return self::parseNamespaceUrl(str_replace(':', '/', $typeName));
+	}
+	/**
+	 * Parse namespace url into parts.
+	 *
+	 * @param $namespace - absolute or relative url
+	 * @return array:
+	 *	 name: element name
+	 *	 url: url wihtout name
+	 *	 prefix: xml prefix
+	 *	 sourceName: used by engine - maybe to remove (used by Core_AclHelper::getAclByNamespace($namespace))
+	 *
+	 * @example - create xmlns attribute:
+	 *		xmlns:{$ns['prefix']}="{$ns['url']}"
+	 *
+	 * @example - wfs typeName:
+	 *		typeName = "{$ns['prefix']}:{$ns['name']}"
+	 *
+	 * @example 'default_db/TEST_PERMS' => Array:
+	 *		[name] => TEST_PERMS
+	 *		[prefix] => default_db
+	 *		[url] => https://biuro.biall-net.pl/wfs/default_db
+	 *		[sourceName] => default_db
+	 *
+	 * @example 'default_objects/AccessOwner' => Array:
+	 *		[name] => AccessOwner
+	 *		[prefix] => default_objects
+	 *		[url] => https://biuro.biall-net.pl/wfs/default_objects
+	 *		[sourceName] => default_objects
+	 *
+	 * @example 'default_db/ZALICZKA/Zaliczka' => Array:
+	 *		[name] => Zaliczka
+	 *		[prefix] => default_db__x3A__Zaliczka
+	 *		[url] => https://biuro.biall-net.pl/wfs/default_db/ZALICZKA
+	 *		[sourceName] => table_objects
+	 *
+	 */
+	public static function parseNamespaceUrl($namespace) {// returns assoc array: [ 'name', 'url', 'prefix', 'sourceName' ]
+		// TODO: the same algo like getAclByNamespace($namespace)
+		$baseNsUri = Api_WfsNs::getBaseWfsUri();
+		if ('http' != substr($namespace, 0, 4)) $namespace = "{$baseNsUri}/{$namespace}";//Request::getHostUri() . '/' . $namespace;
+
+		$nsUrl = $baseNsUri . '/' . '';
+		if ("{$baseNsUri}/" != substr($namespace, 0, strlen($baseNsUri) + 1)) throw new HttpException("Zasoby zewnętrzenj systemu nie są jeszcze zaimplementowane", 501);
+
+		$relativeNsUrl = substr($namespace, strlen($baseNsUri) + 1);
+		// convert '__x3A__' to '/' in url
+		$nsEx = explode('/', str_replace('__x3A__', '/', $relativeNsUrl));// "http://biuro.biall-net.pl/wfs/	default_db/{$nazwa_tabeli}/{$nazwa_obj}
+		// default_db__x3A__ZALICZKA/Zaliczka => default_db/ZALICZKA/Zaliczka
+		$sourceName = array_shift($nsEx);// remove first element - source name
+		$objName = array_pop($nsEx);// name is always last part from url
+
+		if ('default_db' == $sourceName || 'p5_default_db' == $sourceName) {
+			if (count($nsEx) > 1) throw new Exception("Nieznany namespace default_db: '{$relativeNsUrl}'", 501);
+
+			$sourceName = 'default_db';
+			$nsPrefix = $sourceName;
+			if (1 == count($nsEx)) {
+				$sourceName = 'table_objects';// TODO: another source name to read from simpleSchema @see Core_AclSimpleSchemaBase
+				$nsPrefix = 'default_db__x3A__' . $nsEx[0];
+			}
+			// $objName = $nsEx[1];// 'default_db/ZALICZKA:Zaliczka' => ('objects', 'Zaliczka') - possible name conflicts
+			$nsUrl = trim($baseNsUri . '/default_db/' . implode("/", $nsEx), '/');
+			return [ 'name' => $objName, 'prefix' => $nsPrefix, 'url' => $nsUrl, 'sourceName' => $sourceName ];
+		}
+		else if ('default_objects' == $sourceName || 'SystemObjects' == $sourceName) {
+			if (count($nsEx) > 1) throw new Exception("Nieznany namespace SystemObjects: '{$relativeNsUrl}'", 501);
+
+			$sourceName = 'default_objects';
+			$nsUrl = trim($baseNsUri . '/default_objects/' . implode("/", $nsEx), '/');
+			$nsPrefix = 'default_objects';
+			return [ 'name' => $objName, 'prefix' => $nsPrefix, 'url' => $nsUrl, 'sourceName' => $sourceName ];
+		}
+		else if ('p5_objects' == $sourceName || 'objects' == $sourceName) {
+			if (count($nsEx) > 1) throw new Exception("Nieznany namespace SystemObjects: '{$relativeNsUrl}'", 501);
+
+			$sourceName = 'default_objects';
+			$nsUrl = trim($baseNsUri . '/default_objects/' . implode("/", $nsEx), '/');
+			$nsPrefix = 'default_objects';
+			return [ 'name' => $objName, 'prefix' => $nsPrefix, 'url' => $nsUrl, 'sourceName' => $sourceName ];
+		}
+		else if ('zasob_' == substr($sourceName, 0, 6)) {
+			$dbName = substr($sourceName, 6);// database id
+			$remotePdo = DB::getPDO($dbName);
+			DBG::log($remotePdo, 'array', '$remotePdo');
+			if (!$remotePdo || $remotePdo->getZasobId() <= 0) throw new Exception("Database [{$dbName}] not exists - namespace '{$relativeNsUrl}'", 501);
+			if (count($nsEx) > 0) throw new Exception("Nieznany namespace {$sourceName}: '{$relativeNsUrl}'", 501);
+			return [ 'name' => $objName, 'prefix' => $sourceName, 'url' => implode('/', [$baseNsUri, $sourceName, $objName]), 'sourceName' => $sourceName ];
+		}
+		else throw new Exception("Nieznany namespace '{$relativeNsUrl}'", 501);
+	}
+	public static function getIdDatabaseFromNamespace($namespace) {
+		$ns = self::parseNamespaceUrl($namespace);
+		if ('default_db' == substr($ns['sourceName'], 0, strlen('default_db'))) {
+			return DB::getPDO()->getZasobId();
+		} else if ('default_objects' == substr($ns['sourceName'], 0, strlen('default_objects'))) {
+			return DB::getPDO()->getZasobId();
+		} else if ('table_objects' == $ns['sourceName']) {
+			if ('default_db' == substr($ns['prefix'], 0, strlen('default_db'))) {
+				return DB::getPDO()->getZasobId();
+			}
+		} else if ('zasob_' == substr($ns['sourceName'], 0, strlen('zasob_'))) {
+			// 'zasob_931', 'zasob_931__x3A__...'
+			$idDatabase = substr($ns['sourceName'], strlen('zasob_'));
+			if (false !== strpos($idDatabase, '_')) $idDatabase = substr($idDatabase, 0, strpos($idDatabase, '_'));
+			if (!$idDatabase || !is_numeric($idDatabase)) throw new Exception("Not implemented idDatabase({$idDatabase})");
+			return $idDatabase;
+		}
+		throw new Exception("Not implemented idDatabase for namespace({$namespace})");
+	}
+
+	public static function insertRef($objectName, $pk, $childName, $childPk) {// TODO: $idTransaction
+		$refTable = self::getRefTable($objectName, $childName);
+		$sqlPk = DB::getPDO()->quote($pk, PDO::PARAM_STR);
+		$sqlChildPk = DB::getPDO()->quote($childPk, PDO::PARAM_STR);
+		DB::getPDO()->exec("
+			insert into `{$refTable}` (`PRIMARY_KEY`, `REMOTE_PRIMARY_KEY`)
+			values ({$sqlPk}, {$sqlChildPk})
+		");
+	}
+
+	public static function cleanRefs($objectName, $pk, $childName) {// TODO: $idTransaction
+		$refTable = self::getRefTable($objectName, $childName);
+		$sqlPk = DB::getPDO()->quote($pk, PDO::PARAM_STR);
+		DB::getPDO()->exec("
+			update `{$refTable}` set `A_STATUS` = 'DELETED'
+			where `PRIMARY_KEY` = {$sqlPk}
+		");
+	}
+
+	public static function getRefTable($objectName, $childName) {// TODO: wrong - add prefix to avoid name collisions or generate unique hash
+		static $cacheRefTables = array();
+		$refTable = "{$objectName}__#REF__{$childName}";
+		if (in_array($refTable, $cacheRefTables)) return $refTable;
+		DB::getPDO()->exec("
+			CREATE TABLE IF NOT EXISTS `{$refTable}` (
+				`PRIMARY_KEY` int(11) NOT NULL,
+				`REMOTE_PRIMARY_KEY` int(11) NOT NULL,
+				`REMOTE_TYPENAME` varchar(255) NOT NULL DEFAULT '',
+				`A_STATUS` enum('WAITING', 'NORMAL', 'DELETED') NOT NULL DEFAULT 'WAITING',
+				`A_RECORD_UPDATE_DATE` timestamp ON UPDATE CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+				-- TODO `TRANACTION_ID` int(11) NOT NULL
+				KEY `PRIMARY_KEY` (`PRIMARY_KEY`),
+				KEY `REMOTE_PRIMARY_KEY` (`REMOTE_PRIMARY_KEY`)
+			) ENGINE=MyISAM DEFAULT CHARSET=latin2;
+		");
+		try {
+			DB::getPDO()->exec(" ALTER TABLE `{$refTable}` ADD `A_STATUS` enum('WAITING', 'NORMAL', 'DELETED') NOT NULL DEFAULT 'WAITING' ");
+		} catch (Exception $e) {
+			// echo 'C.'.get_class($this).' L.' . __LINE__ . " Error:";print_r($e->getMessage());echo "\n";
+		}
+		try {
+			DB::getPDO()->exec(" ALTER TABLE `{$refTable}` ADD `A_RECORD_UPDATE_DATE` timestamp ON UPDATE CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ");
+		} catch (Exception $e) {
+			// echo 'C.'.get_class($this).' L.' . __LINE__ . " Error:";print_r($e->getMessage());echo "\n";
+		}
+		try {
+			DB::getPDO()->exec(" ALTER TABLE `{$refTable}` ADD `REMOTE_TYPENAME` varchar(255) NOT NULL DEFAULT '' ");
+		} catch (Exception $e) {
+			// echo 'C.'.get_class($this).' L.' . __LINE__ . " Error:";print_r($e->getMessage());echo "\n";
+		}
+		$cacheRefTables[] = $refTable;
+		return $refTable;
+	}
+
+	public static function getInstanceTable($rootTableName) {
+		static $cacheInstanceTables = array();
+		$instanceTable = "{$rootTableName}__#INSTANCE";
+		if (in_array($instanceTable, $cacheInstanceTables)) return $instanceTable;
+		DB::getPDO()->execSql("
+			CREATE TABLE IF NOT EXISTS `{$instanceTable}` (
+				`PRIMARY_KEY` int(11) NOT NULL,
+				`A_RECORD_UPDATE_DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+				`INSTANCE_NAME` varchar(255) NOT NULL,
+				UNIQUE KEY `PRIMARY_KEY` (`PRIMARY_KEY`),
+				KEY `INSTANCE_NAME` (`INSTANCE_NAME`)
+				-- TODO `A_TRANACTION_ID` int(11) NOT NULL DEFAULT 0
+			) ENGINE=MyISAM DEFAULT CHARSET=latin2;
+		");
+		DB::getPDO()->execSql("
+			CREATE TABLE IF NOT EXISTS `{$instanceTable}_HIST` (
+				`ID` int(11) NOT NULL AUTO_INCREMENT,
+				`PRIMARY_KEY` int(11) NOT NULL,
+				`A_TRANACTION_ID` int(11) NOT NULL DEFAULT 0,
+				`A_RECORD_UPDATE_DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+				`INSTANCE_NAME` varchar(255) NOT NULL,
+				PRIMARY KEY (`ID`),
+				KEY `PRIMARY_KEY` (`PRIMARY_KEY`)
+			) ENGINE=MyISAM DEFAULT CHARSET=latin2;
+		");
+		$cacheInstanceTables[] = $instanceTable;
+		return $instanceTable;
+	}
+	public static function setInstance($rootTableName, $pk, $instanceName, $idTransaction = 0) {
+		$instanceTable = self::getInstanceTable($rootTableName);
+		$pk = intval($pk);
+		// TODO: if $pk < 0 throw new Exception("...");
+		$sql = [
+			'instanceName' => DB::getPDO()->quote($instanceName, PDO::PARAM_STR),
+			'idTransaction' => intval($idTransaction)
+		];
+		DB::getPDO()->exec("
+			insert into `{$instanceTable}_HIST` (`PRIMARY_KEY`, `INSTANCE_NAME`, `A_TRANACTION_ID`)
+				values({$pk}, {$sql['instanceName']}, {$idTransaction})
+		");
+	}
+
+	public static function getChildHistTable($rootTableName, $childName, $schema) {
+		// $childName(id) => Array:
+		//		 [@type] => xsd:integer
+		// $childName(created) => Array:
+		//		 [@type] => xsd:date
+		// $childName(worker) => Array:
+		//		 [@ref] => default_objects/AccessOwner
+		// $childName(kwota) => Array:
+		//		 [@type] => xsd:decimal
+		//		 [@totalDigits] => 16
+		//		 [@fractionDigits] => 2
+		// $childName(nierozliczona_kwota) => Array:
+		//		 [@type] => xsd:decimal
+		//		 [@totalDigits] => 16
+		//		 [@fractionDigits] => 2
+		// $childName(pozycja) => Array:
+		//		 [@ref] => ZaliczkaPozycja
+		//		 [@maxOccurs] => unbounded
+		static $cacheHistTables = array();
+		$histTable = "{$rootTableName}__#HIST__{$childName}";
+		if (in_array($histTable, $cacheHistTables)) return $histTable;
+		$sqlType = '';
+		switch ($schema['@type']) {
+			case 'xsd:integer': $sqlType = "int(11) NOT NULL DEFAULT 0"; break;
+			case 'xsd:date': $sqlType = "date DEFAULT NULL"; break;
+			case 'xsd:decimal': $sqlType = "decimal(" . V::get('@totalDigits', 16, $schema) . ", " . V::get('@fractionDigits', 2, $schema) . ") NOT NULL DEFAULT 0"; break;
+			case 'xsd:string': $sqlType = "varchar(255) NOT NULL DEFAULT ''"; break;
+			// TODO: type alias like enum fields: @type => "{$prefix}:{$field_name}Type"
+		}
+		if (!$sqlType && !empty($schema['@ref'])) $sqlType = "int(11) NOT NULL DEFAULT 0";// TODO: type from ref instance @primaryKey - mostly int
+		if (!$sqlType) throw new Exception("Unimplemented schema to sql for '{$rootTableName}/{$childName}' schema(".json_encode($schema).")");
+		DB::getPDO()->exec("
+			CREATE TABLE IF NOT EXISTS `{$histTable}` (
+				`ID` int(11) NOT NULL AUTO_INCREMENT,
+				`VALUE` {$sqlType},
+				`A_TRANSACTION_ID` int(11) NOT NULL DEFAULT 0,
+				PRIMARY KEY (`ID`)
+			) ENGINE=MyISAM DEFAULT CHARSET=latin2;
+		");
+		$cacheHistTables[] = $histTable;
+		return $histTable;
+	}
+
+	public static function getTransactionTable($rootTableName) {
+		static $cacheTransactionTables = array();
+		$transactionTable = "{$rootTableName}__#TRANSACTION";
+		if (in_array($transactionTable, $cacheTransactionTables)) return $transactionTable;
+		DB::getPDO()->exec("
+			CREATE TABLE IF NOT EXISTS `{$transactionTable}` (
+				`ID` int(11) NOT NULL AUTO_INCREMENT,
+				`A_ACTION_ID_USER` int(11) DEFAULT NULL, -- NULL for scripts
+				`A_ACTION_AUTHOR` varchar(255) NOT NULL DEFAULT '',
+				`A_ACTION_DATE` timestamp ON UPDATE CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+				`A_STATUS` enum('WAITING', 'NORMAL', 'DELETED') NOT NULL DEFAULT 'WAITING',
+				`A_CONTEXT_TRANSACTION` varchar(255) NOT NULL DEFAULT '',
+				PRIMARY KEY (`ID`)
+			) ENGINE=MyISAM DEFAULT CHARSET=latin2;
+		");
+		$cacheTransactionTables[] = $transactionTable;
+		return $transactionTable;
+	}
+
+	public static function startTransaction($rootTableName, $idUser, $author = '') {
+		$refTable = self::getTransactionTable($rootTableName);
+		$sqlIdUser = ((int)$idUser > 0) ? DB::getPDO()->quote($idUser, PDO::PARAM_INT) : 'NULL';
+		$sqlAuthor = DB::getPDO()->quote($author, PDO::PARAM_STR);
+		DB::getPDO()->exec("
+			insert into `{$refTable}` (`A_ACTION_ID_USER`, `A_ACTION_AUTHOR`)
+			values ({$sqlIdUser}, {$sqlAuthor})
+		");
+		return DB::getPDO()->lastInsertId();
+	}
+
+	public static function rollbackTransaction($rootTableName, $idTransaction) {
+		// TODO: ROLLBACK - do nothing
+	}
+
+	public static function commitTransaction($idTransaction, $simpleSchema_or_acl) {
+		// TODO: COMMIT
+		// TODO: save changes to rootTableName and every childrens - recurence
+	}
+
+	public static function commitContextTransaction($rootTableName, $rootIdTransaction, $simpleSchema_or_acl_for_child) {
+		// TODO: COMMIT - changes for childrens
+		// TODO: find transaction with context transaction like "{$rootTableName}.{$rootIdTransaction}" = A_CONTEXT_TRANSACTION
+		// TODO: save changes to rootTableName and every childrens - recurence
+	}
 
 }