فهرست منبع

added source to ref config (use ref table or view)

Piotr Labudda 8 سال پیش
والد
کامیت
027f286321
1فایلهای تغییر یافته به همراه149 افزوده شده و 31 حذف شده
  1. 149 31
      SE/se-lib/ACL.php

+ 149 - 31
SE/se-lib/ACL.php

@@ -220,21 +220,160 @@ SQL;
 			default: throw new Exception("Expected ref type for field '{$childName}' in object '{$rootObjectNamespace}'");
 		}
 
+		$refInfo = self::getRefConfig($rootObjectNamespace, $childName, $childNamespace);
+
+		if ('view' === $refInfo['SOURCE']) {
+			$refTableName = "CRM__#REF_TABLE__{$refInfo['ID']}_VIEW"; // view created by ACL::generateRefSelectSqlByFlatRelationCache
+		} else {
+			$refTableName = "CRM__#REF_TABLE__{$refInfo['ID']}";
+			if ('WAITING' == $refInfo['A_STATUS']) {
+				DB::getPDO()->execSql("
+					CREATE TABLE IF NOT EXISTS `{$refTableName}` (
+						`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'
+						, `TRANSACTION_ID` int(11) NOT NULL
+						, `A_LAST_ACTION_DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+						, KEY `PRIMARY_KEY` (`PRIMARY_KEY`)
+						, KEY `REMOTE_PRIMARY_KEY` (`REMOTE_PRIMARY_KEY`)
+					) ENGINE=MyISAM DEFAULT CHARSET=latin2 COMMENT='{$rootObjectNamespace} #REF $childName ({$childNamespace})';
+				");
+				$refInfo['A_STATUS'] = "NORMAL";
+				$refInfo['VERSION'] = self::$REF_TABLE_VERSION;
+				$affected = DB::getPDO()->update("CRM_REF_CONFIG", 'ID', $refInfo['ID'], [
+					'A_STATUS' => $refInfo['A_STATUS'],
+					'VERSION' => $refInfo['VERSION']
+				]);
+			}
+		}
+
+		if ($refInfo['VERSION'] < self::$REF_TABLE_VERSION) throw new Exception("TODO: ref table {$refInfo['ID']} require upgrade - field '{$childName}' in object '{$rootObjectNamespace}'");
+
+		$cacheRefTables[$cacheKey] = $refTableName;
+		return $refTableName;
+	}
+	public static function getRefSource($rootObjectNamespace, $childName) { // CRM_REF_CONFIG
+		$refInfo = self::getRefConfig($rootObjectNamespace, $childName);
+		return V::get('SOURCE', 'table', $refInfo);
+	}
+	public static function generateRefSelectSqlByFlatRelationCache($rootObjectNamespace, $childName) { // CRM_REF_CONFIG
+		$appInfo = DB::getPDO()->fetchValue("
+			select f.appInfo
+			from `CRM_#CACHE_ACL_OBJECT_FIELD` f
+			where f.objectNamespace = '{$rootObjectNamespace}'
+				and f.fieldNamespace = '{$childName}'
+		");
+		if (!$appInfo) throw new Exception("Missing app:info for field '{$rootObjectNamespace}/{$childName}'");
+		$appInfo = @json_decode($appInfo, $assoc = true);
+		if (empty($appInfo)) throw new Exception("Empty app:info for field '{$rootObjectNamespace}/{$childName}'");
+
+		DBG::log(['$appInfo'=>$appInfo, '$rootObjectNamespace'=>$rootObjectNamespace, '$childName'=>$childName], 'array', "\$appInfo");
+		$rootAcl = self::getAclByNamespace($rootObjectNamespace);
+		$childXsdType = $rootAcl->getXsdFieldType($childName);
+		list($typePrefix, $childNamespace) = explode(':', $childXsdType, 2);
+		switch ($typePrefix) {
+			case 'ref_uri': $childAcl = self::getAclByNamespace($childNamespace); break;
+			case 'ref': $childAcl = self::getAclByTypeName($childNamespace); break;
+			default: throw new Exception("Expected ref type for field '{$childName}' in object '{$rootObjectNamespace}'");
+		}
+
+		$lastActionDateField = "NULL"; // , IF(l.A_RECORD_UPDATE_DATE > r.A_RECORD_UPDATE_DATE, l.A_RECORD_UPDATE_DATE, r.A_RECORD_UPDATE_DATE) as A_LAST_ACTION_DATE
+		$rootPrimaryKeyField = $rootAcl->getPrimaryKeyField();
+		$childPrimaryKeyField = $childAcl->getPrimaryKeyField();
+		$rootTableName = $rootAcl->getRootTableName();
+		$childTableName = $childAcl->getRootTableName();
+		//   '$appInfo' => [
+		//     'flat_relation_cache' => [
+		//       'source' => [
+		//         '@name' => 'ID',
+		//         '@xpath' => 'default_db__x3A__CRM_WSKAZNIK:CRM_WSKAZNIK/ID_PROCES',
+		//       ),
+		//     ),
+		//   ),
+		//   '$rootObjectNamespace' => 'default_db/CRM_PROCES/PROCES',
+		//   '$childName' => 'default_db__x3A__CRM_WSKAZNIK:CRM_WSKAZNIK',
+
+		//   '$appInfo' => [
+		//   'flat_relation_cache' => [
+		//     'source' => [
+		//       '@name' => 'ID',
+		//       '@xpath' => 'default_db__x3A__CRM_PROCES:PROCES/PARENT_ID',
+		//     ),
+		//   ),
+		// ),
+		// '$rootObjectNamespace' => 'default_db/CRM_PROCES/PROCES',
+		// '$childName' => 'default_db__x3A__CRM_PROCES:PROCES',
+		$appInfoRootFieldName = null;
+		$appInfoChildFieldName = null;
+		{
+			if (empty($appInfo['flat_relation_cache']['source']['@name'])) throw new Exception("Missing flat_relation_cache/source/@name");
+			if (empty($appInfo['flat_relation_cache']['source']['@xpath'])) throw new Exception("Missing flat_relation_cache/source/@xpath");
+			$appInfoName = $appInfo['flat_relation_cache']['source']['@name'];
+			$appInfoXpath = $appInfo['flat_relation_cache']['source']['@xpath'];
+			// $rootNs = $rootAcl->getNamespace()
+			if ("{$childName}/" === substr($appInfoXpath, 0, strlen("{$childName}/"))) {
+				$appInfoRootFieldName = substr($appInfoXpath, strlen("{$childName}/"));
+				$appInfoChildFieldName = $appInfoName;
+			} else {
+				throw new Exception("TODO parse flat_relation_cache");
+			}
+		}
+		if (!$appInfoRootFieldName || !$appInfoChildFieldName) throw new Exception("Error Processing flat_relation_cache");
+		$sql = "
+			select l.{$rootPrimaryKeyField} as PRIMARY_KEY
+					, r.{$childPrimaryKeyField} as REMOTE_PRIMARY_KEY
+					, '' as REMOTE_TYPENAME
+					, 'WAITING' as A_STATUS
+					, 0 as TRANSACTION_ID
+					, {$lastActionDateField} as A_LAST_ACTION_DATE
+			from `{$rootTableName}` l
+				join `{$childTableName}` r on(r.{$appInfoRootFieldName} = l.{$appInfoChildFieldName})
+		";
+		DBG::log($sql, 'sql', "generateRefSelectSqlByFlatRelationCache");
+		return $sql;
+	}
+	public static function setRefSource($rootObjectNamespace, $childName, $source, $viewSelectSql = null) { // CRM_REF_CONFIG
+		if (!in_array($source, ['view', 'table'])) throw new Exception("Wrong param source - expected 'table' or 'view'");
+		if ('view' === $source && !$viewSelectSql) throw new Exception("Missing create view sql");
+		$refInfo = self::getRefConfig($rootObjectNamespace, $childName);
+		if ($source != $refInfo['SOURCE']) {
+			if ('view' === $source) {
+				$refTableName = "CRM__#REF_TABLE__{$refInfo['ID']}_VIEW";
+				DB::getPDO()->execSql(" CREATE OR REPLACE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `{$refTableName}` AS {$viewSelectSql} ");
+			}
+			$affected = DB::getPDO()->update("CRM_REF_CONFIG", 'ID', $refInfo['ID'], [
+				'SOURCE' => $source,
+			]);
+		}
+	}
+	public static function getRefConfig($rootObjectNamespace, $childName, $childNamespace = null) { // CRM_REF_CONFIG
+		if (!$childNamespace) {
+			$rootAcl = self::getAclByNamespace($rootObjectNamespace);
+			$childXsdType = $rootAcl->getXsdFieldType($childName);
+			list($typePrefix, $childNamespace) = explode(':', $childXsdType, 2);
+			DBG::log(['$childXsdType' => $childXsdType, '$typePrefix' => $typePrefix, '$childNamespace' => $childNamespace], 'array', "DBG get ref table ...");
+			switch ($typePrefix) {
+				case 'ref_uri': $childAcl = self::getAclByNamespace($childNamespace); break;
+				case 'ref': $childAcl = self::getAclByTypeName($childNamespace); break;
+				default: throw new Exception("Expected ref type for field '{$childName}' in object '{$rootObjectNamespace}'");
+			}
+		}
 		$refInfo = [];// define $refInfo = [ ID, A_STATUS, VERSION ]
 		try {// check that ref config table exists
 			$sqlRootTableNs = DB::getPDO()->quote($rootObjectNamespace, PDO::PARAM_STR);
 			$sqlChildName = DB::getPDO()->quote($childName, PDO::PARAM_STR);
 			$sqlChildNamespace = DB::getPDO()->quote($childNamespace, PDO::PARAM_STR);
 			$refInfo = DB::getPDO()->fetchFirst("
-				select c.ID, c.A_STATUS, c.VERSION
+				select c.ID, c.A_STATUS, c.VERSION, c.SOURCE
 				from `CRM_REF_CONFIG` c
 				where c.ROOT_OBJECT_NS = {$sqlRootTableNs}
 					and c.CHILD_NAME = {$sqlChildName}
 					and c.CHILD_NS = {$sqlChildNamespace}
 			");
 		} catch (Exception $e) {
-			DB::getPDO()->exec("
-				CREATE TABLE `CRM_REF_CONFIG` (
+			DB::getPDO()->execSql("
+				CREATE TABLE IF NOT EXISTS `CRM_REF_CONFIG` (
 					`ID` INT NOT NULL AUTO_INCREMENT
 					, `ROOT_OBJECT_NS` VARCHAR(255) NOT NULL
 					, `CHILD_NAME` VARCHAR(255) NOT NULL
@@ -245,9 +384,14 @@ SQL;
 					, PRIMARY KEY (`ID`)
 				) ENGINE = MyISAM DEFAULT CHARSET=latin2;
 			");
+			try {
+				DB::getPDO()->execSql(" ALTER TABLE `CRM_REF_CONFIG` ADD `SOURCE` enum('table', 'view') not null default 'table' ");
+			} catch (Exception $e) {
+				DBG::log($e);
+			}
 		}
 		if (empty($refInfo)) {
-			$refInfo = [ 'ID' => 0, 'A_STATUS' => 'WAITING', 'VERSION' => 0 ];
+			$refInfo = [ 'ID' => 0, 'A_STATUS' => 'WAITING', 'VERSION' => 0, 'SOURCE' => 'table' ];
 			$refInfo['ID'] = DB::getPDO()->insert("CRM_REF_CONFIG", [
 				'ROOT_OBJECT_NS' => $rootObjectNamespace,
 				'CHILD_NAME' => $childName,
@@ -255,33 +399,7 @@ SQL;
 			]);
 		}
 		if (!$refInfo['ID']) throw new Exception("Ref table not found in ref config table for field '{$childName}' in object '{$rootObjectNamespace}'");
-
-		$refTableName = "CRM__#REF_TABLE__{$refInfo['ID']}";
-		if ('WAITING' == $refInfo['A_STATUS']) {
-			DB::getPDO()->exec("
-				CREATE TABLE IF NOT EXISTS `{$refTableName}` (
-					`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'
-					, `TRANACTION_ID` int(11) NOT NULL
-					, `A_LAST_ACTION_DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-					, KEY `PRIMARY_KEY` (`PRIMARY_KEY`)
-					, KEY `REMOTE_PRIMARY_KEY` (`REMOTE_PRIMARY_KEY`)
-				) ENGINE=MyISAM DEFAULT CHARSET=latin2 COMMENT='{$rootObjectNamespace} #REF $childName ({$childNamespace})';
-			");
-			$refInfo['A_STATUS'] = "NORMAL";
-			$refInfo['VERSION'] = self::$REF_TABLE_VERSION;
-			$affected = DB::getPDO()->update("CRM_REF_CONFIG", 'ID', $refInfo['ID'], [
-				'A_STATUS' => $refInfo['A_STATUS'],
-				'VERSION' => $refInfo['VERSION']
-			]);
-		}
-
-		if ($refInfo['VERSION'] < self::$REF_TABLE_VERSION) throw new Exception("TODO: ref table {$refInfo['ID']} require upgrade - field '{$childName}' in object '{$rootObjectNamespace}'");
-
-		$cacheRefTables[$cacheKey] = $refTableName;
-		return $refTableName;
+		return $refInfo;
 	}
 
 	public static function getInstanceId($namespace) { // CRM_INSTANCE_CONFIG