ACL.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. <?php
  2. Lib::loadClass('Core_AclHelper');
  3. class ACL {
  4. public static $REF_TABLE_VERSION = 1;
  5. /**
  6. * Ids List of Proces Init for given tabel (skip filters)
  7. */
  8. public static function getTableProcesInitIds($idTable) {
  9. $procesInitList = self::getTableProcesInitList($idTable);
  10. return array_keys($procesInitList);
  11. }
  12. /**
  13. * List of Proces Init for given table (skip filters)
  14. */
  15. public static function getTableProcesInitList($idTable) {
  16. $tableProcesInitList = array();
  17. $sqlIdProcesListSql = <<<SQL
  18. select tpv.`ID_PROCES`
  19. from `CRM_PROCES_idx_TABLE_TO_PROCES_VIEW` tpv
  20. where tpv.`ID_TABLE`='{$idTable}'
  21. SQL;
  22. $fetchTableProcesInitListSql = <<<SQL
  23. -- time ~0.07 -- no goto and return
  24. select p.`ID`, p.`DESC`
  25. from `CRM_PROCES` p
  26. where p.`ID` in(
  27. select i.`idx_PROCES_INIT_ID`
  28. from `CRM_PROCES_idx` i
  29. where i.`ID_PROCES` in({$sqlIdProcesListSql})
  30. )
  31. and p.`TYPE`='PROCES_INIT'
  32. order by p.`SORT_PRIO`
  33. SQL;
  34. /*
  35. SELECT p.`ID` , p.`DESC`
  36. FROM `CRM_PROCES` p
  37. WHERE p.`ID`
  38. IN (
  39. SELECT i.`idx_PROCES_INIT_ID`
  40. FROM `CRM_PROCES_idx` i
  41. WHERE i.`ID_PROCES`
  42. IN (
  43. SELECT tpv.`ID_PROCES`
  44. FROM `CRM_PROCES_idx_TABLE_TO_PROCES_VIEW` tpv
  45. WHERE tpv.`ID_TABLE` = '13051'
  46. )
  47. )
  48. AND p.`TYPE` = 'PROCES_INIT'
  49. order by p.`SORT_PRIO`
  50. */
  51. $fetchTableProcesInitListSql = <<<SQL
  52. -- time ~0.15s
  53. select p.`ID`, p.`DESC`
  54. from `CRM_PROCES` p
  55. where p.`ID` in(
  56. select i.`idx_PROCES_INIT_ID`
  57. from `CRM_PROCES_idx` i
  58. where i.`ID_PROCES` in({$sqlIdProcesListSql})
  59. union
  60. select ig.`idx_PROCES_INIT_ID`
  61. from `CRM_PROCES_idx` i
  62. join `CRM_PROCES_idx` ig on(ig.`ID_PROCES`=i.`idx_PROCES_WITH_GROUPS_ID`)
  63. where i.`ID_PROCES` in({$sqlIdProcesListSql})
  64. )
  65. and p.`TYPE`='PROCES_INIT'
  66. order by p.`SORT_PRIO`
  67. SQL;
  68. $fetchTableProcesInitListSql = <<<SQL
  69. -- time ~0.14
  70. select p.`ID`, p.`DESC`
  71. from `CRM_PROCES` p
  72. where p.`ID` in(
  73. select i.`idx_PROCES_INIT_ID`
  74. from `CRM_PROCES_idx` i
  75. where i.`ID_PROCES` in({$sqlIdProcesListSql})
  76. or i.`ID_PROCES` in(
  77. select ig.`idx_PROCES_WITH_GROUPS_ID`
  78. from `CRM_PROCES_idx` ig
  79. where ig.`ID_PROCES` in({$sqlIdProcesListSql})
  80. )
  81. )
  82. and p.`TYPE`='PROCES_INIT'
  83. order by p.`SORT_PRIO`
  84. SQL;
  85. //echo'<pre>$fetchTableProcesInitListSql('.$idTable.') ';print_r($fetchTableProcesInitListSql);echo'</pre>';
  86. $tableProcesInitList = array();
  87. $db = DB::getDB();
  88. $res = $db->query($fetchTableProcesInitListSql);
  89. while ($r = $db->fetch($res)) {
  90. $tableProcesInitList[$r->ID] = $r->DESC;
  91. }
  92. return $tableProcesInitList;
  93. }
  94. public static function getProcesInitMapTreeOnlyIds($ids) {
  95. $mapTree = array();
  96. $map = self::getProcesInitMapOnlyIds($ids);
  97. foreach ($map as $r) {
  98. if ('PROCES_INIT' == $r->TYPE) {
  99. $mapTree[$r->ID_PROCES] = array();
  100. }
  101. }
  102. foreach ($map as $r) {
  103. if ('GOTO_AND_RETURN' == $r->TYPE) {
  104. $mapTree[$r->idx_MAIN_PROCES_INIT_ID][$r->ID_PROCES] = array();
  105. }
  106. }
  107. foreach ($map as $r) {
  108. if ('GOTO_AND_RETURN_LVL2' == $r->TYPE) {
  109. $mapTree[$r->idx_MAIN_PROCES_INIT_ID][$r->idx_GOTO_LVL2_INIT_ID][$r->ID_PROCES] = true;
  110. }
  111. }
  112. return $mapTree;
  113. }
  114. public static function getProcesInitMapOnlyIds($ids) {
  115. $map = array();
  116. $sqlIds = V::filter($ids, array('V', 'filterPositiveInteger'));
  117. $sqlIds = implode(',', $sqlIds);
  118. if (empty($sqlIds)) return $map;
  119. $sql = <<<SQL
  120. select i.`ID_PROCES`
  121. , i.`PARENT_ID`
  122. , i.`TYPE`
  123. , i.`idx_PROCES_INIT_ID`
  124. , i.`idx_MAIN_PROCES_INIT_ID`
  125. , i.`idx_PROCES_WITH_GROUPS_ID`
  126. , IF(i.`TYPE`='GOTO_AND_RETURN_LVL2'
  127. , (select ig.`idx_PROCES_INIT_ID`
  128. from `CRM_PROCES_idx` ig
  129. where ig.`ID_PROCES`=i.`PARENT_ID`
  130. limit 1)
  131. , 0
  132. ) as idx_GOTO_LVL2_INIT_ID
  133. from `CRM_PROCES_idx` i
  134. where i.`ID_PROCES` in({$sqlIds})
  135. and i.`idx_MAIN_PROCES_INIT_ID` in({$sqlIds})
  136. SQL;
  137. DBG::_('DBG_MAP', '1', "MAP SQL", $sql, __CLASS__, __FUNCTION__, __LINE__);
  138. $db = DB::getDB();
  139. $res = $db->query($sql);
  140. while ($r = $db->fetch($res)) {
  141. $map[] = $r;
  142. }
  143. //DBG::table("MAP", $map, __CLASS__, __FUNCTION__, __LINE__);
  144. return $map;
  145. }
  146. public static function canGroupViewProces($idGroup, $idProcesInit) {
  147. $isAllowed = false;
  148. $idProcesInit = (int)$idProcesInit;
  149. if (!$idProcesInit) return false;
  150. $checkProcesAccessSql = <<<SQL
  151. select count(*) as cnt
  152. from `CRM_PROCES_idx_GROUP_to_INIT_VIEW` giv
  153. where giv.`ID_GROUP` = '{$idGroup}'
  154. and giv.`ID_PROCES_INIT` = '{$idProcesInit}'
  155. SQL;
  156. $db = DB::getDB();
  157. $res = $db->query($checkProcesAccessSql);
  158. if ($r = $db->fetch($res)) {
  159. if ($r->cnt > 0) {
  160. $isAllowed = true;
  161. }
  162. }
  163. return $isAllowed;
  164. }
  165. public static function getStorageByNamespace($namespace, $forceTblAclInit = false) {
  166. Lib::loadClass('Core_AclHelper');
  167. Lib::loadClass('SchemaFactory');
  168. $ns = Core_AclHelper::parseNamespaceUrl($namespace);
  169. DBG::log($ns, 'array', "parseNamespaceUrl({$namespace})");
  170. if ('default_db' == $ns['prefix']) {
  171. $acl = User::getAcl()->getObjectAcl($ns['prefix'], $ns['name']);
  172. } else if ('objects' == $ns['prefix']) {
  173. $acl = SchemaFactory::loadDefaultObject($ns['name']);
  174. } else if ('default_objects' == $ns['prefix']) {
  175. $acl = SchemaFactory::loadDefaultObject($ns['name']);
  176. } else if ('default_db__x3A__' == substr($ns['prefix'], 0, 17)) {
  177. $rootTableName = strtolower(substr($ns['prefix'], 17));
  178. $acl = SchemaFactory::loadTableObject($rootTableName, $ns['name']);
  179. } else {
  180. throw new HttpException("Not Implemented", 501);
  181. }
  182. $acl->init($forceTblAclInit);
  183. return $acl;
  184. }
  185. public static function getAclByNamespace($namespace, $forceTblAclInit = false) {
  186. return Core_AclHelper::getAclByNamespace($namespace, $forceTblAclInit);
  187. }
  188. public static function getAclByTypeName($typeName, $forceTblAclInit = false) {
  189. return Core_AclHelper::getAclByNamespace(str_replace(':', '/', $typeName), $forceTblAclInit);
  190. }
  191. public static function parseNamespaceUrl($namespace) {// returns assoc array: [ 'name', 'url', 'prefix', 'sourceName' ]
  192. return Core_AclHelper::parseNamespaceUrl($namespace);
  193. }
  194. public static function getRefTable($rootObjectNamespace, $childName) { // CRM_REF_CONFIG
  195. static $cacheRefTables = array();
  196. DBG::log("DBG get ref table ({$rootObjectNamespace}, {$childName}) ...");
  197. $cacheKey = "{$rootObjectNamespace}/{$childName}";
  198. if (array_key_exists($cacheKey, $cacheRefTables)) return $cacheRefTables[$cacheKey];
  199. $rootAcl = self::getAclByNamespace($rootObjectNamespace);
  200. $childXsdType = $rootAcl->getXsdFieldType($childName);
  201. list($typePrefix, $childNamespace) = explode(':', $childXsdType, 2);
  202. DBG::log(['$childXsdType' => $childXsdType, '$typePrefix' => $typePrefix, '$childNamespace' => $childNamespace], 'array', "DBG get ref table ...");
  203. switch ($typePrefix) {
  204. case 'ref_uri': $childAcl = self::getAclByNamespace($childNamespace); break;
  205. case 'ref': $childAcl = self::getAclByTypeName($childNamespace); break;
  206. default: throw new Exception("Expected ref type for field '{$childName}' in object '{$rootObjectNamespace}'");
  207. }
  208. $refInfo = self::getRefConfig($rootObjectNamespace, $childName, $childNamespace);
  209. if ('view' === $refInfo['SOURCE']) {
  210. $refTableName = "CRM__#REF_TABLE__{$refInfo['ID']}_VIEW"; // view created by ACL::generateRefSelectSqlByFlatRelationCache
  211. } else {
  212. $refTableName = "CRM__#REF_TABLE__{$refInfo['ID']}";
  213. if ('WAITING' == $refInfo['A_STATUS']) {
  214. DB::getPDO()->execSql("
  215. CREATE TABLE IF NOT EXISTS `{$refTableName}` (
  216. `PRIMARY_KEY` int(11) NOT NULL
  217. , `REMOTE_PRIMARY_KEY` int(11) NOT NULL
  218. , `REMOTE_TYPENAME` varchar(255) NOT NULL DEFAULT ''
  219. , `A_STATUS` enum('WAITING', 'NORMAL', 'DELETED') NOT NULL DEFAULT 'WAITING'
  220. , `TRANSACTION_ID` int(11) NOT NULL
  221. , `A_LAST_ACTION_DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
  222. , KEY `PRIMARY_KEY` (`PRIMARY_KEY`)
  223. , KEY `REMOTE_PRIMARY_KEY` (`REMOTE_PRIMARY_KEY`)
  224. ) ENGINE=MyISAM DEFAULT CHARSET=latin2 COMMENT='{$rootObjectNamespace} #REF $childName ({$childNamespace})';
  225. ");
  226. $refInfo['A_STATUS'] = "NORMAL";
  227. $refInfo['VERSION'] = self::$REF_TABLE_VERSION;
  228. $affected = DB::getPDO()->update("CRM_REF_CONFIG", 'ID', $refInfo['ID'], [
  229. 'A_STATUS' => $refInfo['A_STATUS'],
  230. 'VERSION' => $refInfo['VERSION']
  231. ]);
  232. }
  233. }
  234. if ($refInfo['VERSION'] < self::$REF_TABLE_VERSION) throw new Exception("TODO: ref table {$refInfo['ID']} require upgrade - field '{$childName}' in object '{$rootObjectNamespace}'");
  235. $cacheRefTables[$cacheKey] = $refTableName;
  236. return $refTableName;
  237. }
  238. public static function getRefSource($rootObjectNamespace, $childName) { // CRM_REF_CONFIG
  239. $refInfo = self::getRefConfig($rootObjectNamespace, $childName);
  240. return V::get('SOURCE', 'table', $refInfo);
  241. }
  242. public static function generateRefSelectSqlByFlatRelationCache($rootObjectNamespace, $childName) { // CRM_REF_CONFIG
  243. $appInfo = DB::getPDO()->fetchValue("
  244. select f.appInfo
  245. from `CRM_#CACHE_ACL_OBJECT_FIELD` f
  246. where f.objectNamespace = '{$rootObjectNamespace}'
  247. and f.fieldNamespace = '{$childName}'
  248. ");
  249. if (!$appInfo) throw new Exception("Missing app:info for field '{$rootObjectNamespace}/{$childName}'");
  250. $appInfo = @json_decode($appInfo, $assoc = true);
  251. if (empty($appInfo)) throw new Exception("Empty app:info for field '{$rootObjectNamespace}/{$childName}'");
  252. DBG::log(['$appInfo'=>$appInfo, '$rootObjectNamespace'=>$rootObjectNamespace, '$childName'=>$childName], 'array', "\$appInfo");
  253. $rootAcl = self::getAclByNamespace($rootObjectNamespace);
  254. $childXsdType = $rootAcl->getXsdFieldType($childName);
  255. list($typePrefix, $childNamespace) = explode(':', $childXsdType, 2);
  256. switch ($typePrefix) {
  257. case 'ref_uri': $childAcl = self::getAclByNamespace($childNamespace); break;
  258. case 'ref': $childAcl = self::getAclByTypeName($childNamespace); break;
  259. default: throw new Exception("Expected ref type for field '{$childName}' in object '{$rootObjectNamespace}'");
  260. }
  261. $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
  262. $rootPrimaryKeyField = $rootAcl->getPrimaryKeyField();
  263. $childPrimaryKeyField = $childAcl->getPrimaryKeyField();
  264. $rootTableName = $rootAcl->getRootTableName();
  265. $childTableName = $childAcl->getRootTableName();
  266. // '$appInfo' => [
  267. // 'flat_relation_cache' => [
  268. // 'source' => [
  269. // '@name' => 'ID',
  270. // '@xpath' => 'default_db__x3A__CRM_WSKAZNIK:CRM_WSKAZNIK/ID_PROCES',
  271. // ),
  272. // ),
  273. // ),
  274. // '$rootObjectNamespace' => 'default_db/CRM_PROCES/PROCES',
  275. // '$childName' => 'default_db__x3A__CRM_WSKAZNIK:CRM_WSKAZNIK',
  276. // '$appInfo' => [
  277. // 'flat_relation_cache' => [
  278. // 'source' => [
  279. // '@name' => 'ID',
  280. // '@xpath' => 'default_db__x3A__CRM_PROCES:PROCES/PARENT_ID',
  281. // ),
  282. // ),
  283. // ),
  284. // '$rootObjectNamespace' => 'default_db/CRM_PROCES/PROCES',
  285. // '$childName' => 'default_db__x3A__CRM_PROCES:PROCES',
  286. $appInfoRootFieldName = null;
  287. $appInfoChildFieldName = null;
  288. {
  289. if (empty($appInfo['flat_relation_cache']['source']['@name'])) throw new Exception("Missing flat_relation_cache/source/@name");
  290. if (empty($appInfo['flat_relation_cache']['source']['@xpath'])) throw new Exception("Missing flat_relation_cache/source/@xpath");
  291. $appInfoName = $appInfo['flat_relation_cache']['source']['@name'];
  292. $appInfoXpath = $appInfo['flat_relation_cache']['source']['@xpath'];
  293. // $rootNs = $rootAcl->getNamespace()
  294. if ("{$childName}/" === substr($appInfoXpath, 0, strlen("{$childName}/"))) {
  295. $appInfoRootFieldName = substr($appInfoXpath, strlen("{$childName}/"));
  296. $appInfoChildFieldName = $appInfoName;
  297. } else {
  298. throw new Exception("TODO parse flat_relation_cache");
  299. }
  300. }
  301. if (!$appInfoRootFieldName || !$appInfoChildFieldName) throw new Exception("Error Processing flat_relation_cache");
  302. $sql = "
  303. select l.{$rootPrimaryKeyField} as PRIMARY_KEY
  304. , r.{$childPrimaryKeyField} as REMOTE_PRIMARY_KEY
  305. , '' as REMOTE_TYPENAME
  306. , 'WAITING' as A_STATUS
  307. , 0 as TRANSACTION_ID
  308. , {$lastActionDateField} as A_LAST_ACTION_DATE
  309. from `{$rootTableName}` l
  310. join `{$childTableName}` r on(r.{$appInfoRootFieldName} = l.{$appInfoChildFieldName})
  311. ";
  312. DBG::log($sql, 'sql', "generateRefSelectSqlByFlatRelationCache");
  313. return $sql;
  314. }
  315. public static function setRefSource($rootObjectNamespace, $childName, $source, $viewSelectSql = null) { // CRM_REF_CONFIG
  316. if (!in_array($source, ['view', 'table'])) throw new Exception("Wrong param source - expected 'table' or 'view'");
  317. if ('view' === $source && !$viewSelectSql) throw new Exception("Missing create view sql");
  318. $refInfo = self::getRefConfig($rootObjectNamespace, $childName);
  319. if ($source != $refInfo['SOURCE']) {
  320. if ('view' === $source) {
  321. $refTableName = "CRM__#REF_TABLE__{$refInfo['ID']}_VIEW";
  322. DB::getPDO()->execSql(" CREATE OR REPLACE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `{$refTableName}` AS {$viewSelectSql} ");
  323. }
  324. $affected = DB::getPDO()->update("CRM_REF_CONFIG", 'ID', $refInfo['ID'], [
  325. 'SOURCE' => $source,
  326. ]);
  327. }
  328. }
  329. public static function getRefConfig($rootObjectNamespace, $childName, $childNamespace = null) { // CRM_REF_CONFIG
  330. if (!$childNamespace) {
  331. $rootAcl = self::getAclByNamespace($rootObjectNamespace);
  332. $childXsdType = $rootAcl->getXsdFieldType($childName);
  333. list($typePrefix, $childNamespace) = explode(':', $childXsdType, 2);
  334. DBG::log(['$childXsdType' => $childXsdType, '$typePrefix' => $typePrefix, '$childNamespace' => $childNamespace], 'array', "DBG get ref table ...");
  335. switch ($typePrefix) {
  336. case 'ref_uri': $childAcl = self::getAclByNamespace($childNamespace); break;
  337. case 'ref': $childAcl = self::getAclByTypeName($childNamespace); break;
  338. default: throw new Exception("Expected ref type for field '{$childName}' in object '{$rootObjectNamespace}'");
  339. }
  340. }
  341. $refInfo = [];// define $refInfo = [ ID, A_STATUS, VERSION ]
  342. try {// check that ref config table exists
  343. $sqlRootTableNs = DB::getPDO()->quote($rootObjectNamespace, PDO::PARAM_STR);
  344. $sqlChildName = DB::getPDO()->quote($childName, PDO::PARAM_STR);
  345. $sqlChildNamespace = DB::getPDO()->quote($childNamespace, PDO::PARAM_STR);
  346. $refInfo = DB::getPDO()->fetchFirst("
  347. select c.ID, c.A_STATUS, c.VERSION, c.SOURCE
  348. from `CRM_REF_CONFIG` c
  349. where c.ROOT_OBJECT_NS = {$sqlRootTableNs}
  350. and c.CHILD_NAME = {$sqlChildName}
  351. and c.CHILD_NS = {$sqlChildNamespace}
  352. ");
  353. } catch (Exception $e) {
  354. DB::getPDO()->execSql("
  355. CREATE TABLE IF NOT EXISTS `CRM_REF_CONFIG` (
  356. `ID` INT NOT NULL AUTO_INCREMENT
  357. , `ROOT_OBJECT_NS` VARCHAR(255) NOT NULL
  358. , `CHILD_NAME` VARCHAR(255) NOT NULL
  359. , `CHILD_NS` VARCHAR(255) NOT NULL
  360. , `A_STATUS` enum('WAITING', 'NORMAL', 'DELETED') NOT NULL DEFAULT 'WAITING'
  361. , `VERSION` int(11) NOT NULL DEFAULT 0
  362. , `A_LAST_ACTION_DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
  363. , PRIMARY KEY (`ID`)
  364. ) ENGINE = MyISAM DEFAULT CHARSET=latin2;
  365. ");
  366. try {
  367. DB::getPDO()->execSql(" ALTER TABLE `CRM_REF_CONFIG` ADD `SOURCE` enum('table', 'view') not null default 'table' ");
  368. } catch (Exception $e) {
  369. DBG::log($e);
  370. }
  371. }
  372. if (empty($refInfo)) {
  373. $refInfo = [ 'ID' => 0, 'A_STATUS' => 'WAITING', 'VERSION' => 0, 'SOURCE' => 'table' ];
  374. $refInfo['ID'] = DB::getPDO()->insert("CRM_REF_CONFIG", [
  375. 'ROOT_OBJECT_NS' => $rootObjectNamespace,
  376. 'CHILD_NAME' => $childName,
  377. 'CHILD_NS' => $childNamespace
  378. ]);
  379. }
  380. if (!$refInfo['ID']) throw new Exception("Ref table not found in ref config table for field '{$childName}' in object '{$rootObjectNamespace}'");
  381. return $refInfo;
  382. }
  383. public static function getInstanceId($namespace) { // CRM_INSTANCE_CONFIG
  384. $conf = self::getInstanceConfig($namespace);
  385. return $conf['id'];
  386. }
  387. public static function getInstanceConfig($namespace) { // CRM_INSTANCE_CONFIG
  388. try {
  389. $conf = self::fetchInstanceConfig($namespace);
  390. } catch (Exception $e) {
  391. DB::getPDO()->execSql("
  392. create table if not exists `CRM_INSTANCE_CONFIG` (
  393. `id` int(11) not null AUTO_INCREMENT,
  394. `namespace` varchar(255) NOT NULL DEFAULT '',
  395. `rootNamespace` varchar(255) NOT NULL DEFAULT '',
  396. `idInstanceBase` int(11) NOT NULL DEFAULT 0,
  397. `_createdAt` datetime NOT NULL,
  398. UNIQUE KEY `namespace` (`namespace`),
  399. KEY `rootNamespace` (`rootNamespace`),
  400. PRIMARY KEY (`id`)
  401. ) ENGINE=MyISAM DEFAULT CHARSET=latin2
  402. ");
  403. // TODO:?: `_tableInstalled` tinyint(1) not null default 0,
  404. $conf = self::fetchInstanceConfig($namespace);
  405. }
  406. if (!$conf) {
  407. $id = DB::getPDO()->insert("CRM_INSTANCE_CONFIG", [
  408. 'namespace' => $namespace,
  409. 'rootNamespace' => self::getRootNamespace($namespace),
  410. '_createdAt' => 'NOW()',
  411. ]);
  412. $conf = self::fetchInstanceConfig($namespace);
  413. }
  414. if (!$conf) throw new Exception("Instance not found in config table '{$namespace}'");
  415. return $conf;
  416. }
  417. public static function fetchInstanceConfig($namespace) {
  418. return DB::getPDO()->fetchFirst("
  419. select c.*
  420. from `CRM_INSTANCE_CONFIG` c
  421. where c.namespace = '{$namespace}'
  422. ");
  423. }
  424. public static function getRootNamespace($namespace) { // TODO: works only for relative urls! - mv to Acl->getRootNamespace
  425. Lib::loadClass('SchemaFactory');
  426. try {
  427. $objectItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace);
  428. } catch (Exception $e) {
  429. throw new Exception("Object not installed '{$namespace}'");
  430. }
  431. if (!$objectItem['isStructInstalled']) throw new Exception("Object structure not installed '{$namespace}'");
  432. if ($objectItem['idDatabase'] != DB::getPDO()->getZasobId()) throw new Exception("Only default_db supported"); // TODO: support more Sources
  433. return "default_db/{$objectItem['_rootTableName']}";
  434. }
  435. public static function getNamespaceSiblings($namespace) {
  436. return array_map(function ($row) {
  437. return $row['namespace'];
  438. }, DB::getPDO()->fetchAll("
  439. select s.namespace
  440. from CRM_INSTANCE_CONFIG c
  441. join CRM_INSTANCE_CONFIG s on ( s.rootNamespace = c.rootNamespace and s.namespace != c.rootNamespace )
  442. where c.namespace = :namespace
  443. ", [
  444. 'namespace' => $namespace
  445. ]));
  446. }
  447. public static function getFeatureNamespaces($namespace, $pk) {
  448. $instanceTable = self::getInstanceTable($namespace);
  449. return array_map(function ($row) {
  450. return $row['namespace'];
  451. }, DB::getPDO()->fetchAll("
  452. select c.namespace
  453. from `{$instanceTable}` i
  454. join `CRM_INSTANCE_CONFIG` c on ( c.id = i.idInstance )
  455. where i.pk = :pk
  456. ", [
  457. 'pk' => $pk,
  458. ]));
  459. }
  460. public static function getInstanceTable($namespace) {
  461. $conf = self::getInstanceConfig($namespace);
  462. if (!empty($conf['idInstanceBase'])) return "CRM__#INSTANCE_TABLE__{$conf['idInstanceBase']}";
  463. $rootNs = $conf['rootNamespace'];
  464. $rootConf = self::getInstanceConfig($rootNs);
  465. $instanceTableName = "CRM__#INSTANCE_TABLE__{$rootConf['id']}";
  466. if (!empty($rootConf['idInstance'])) {
  467. $affected = DB::getPDO()->update("CRM_INSTANCE_CONFIG", 'rootNamespace', $rootNs, [
  468. 'idInstanceBase' => $rootConf['id']
  469. ]);
  470. return $instanceTableName;
  471. }
  472. // TODO: fetch primaryKeyType - TODO: store primaryKey and primaryKeyType in SystemObject item
  473. $pkType = 'int';
  474. DB::getPDO()->exec("
  475. CREATE TABLE IF NOT EXISTS `{$instanceTableName}` (
  476. `pk` int(11) NOT NULL COMMENT 'primary key'
  477. , `idInstance` int(11) NOT NULL
  478. , `_createdAt` datetime NOT NULL
  479. , KEY `pk` (`pk`)
  480. , KEY `idInstance` (`idInstance`)
  481. ) ENGINE=MyISAM DEFAULT CHARSET=latin2 COMMENT='{$rootNs} #INSTANCE';
  482. ");
  483. $affected = DB::getPDO()->update("CRM_INSTANCE_CONFIG", 'rootNamespace', $rootNs, [
  484. 'idInstanceBase' => $rootConf['id']
  485. ]);
  486. return $instanceTableName;
  487. }
  488. // @params $from - ( ACL | tableName | namespace | etc... - only ACL)
  489. public static function query($from, $prefix = 't') {
  490. Lib::loadClass('AclQueryBuilder');
  491. $query = new AclQueryBuilder();
  492. $query->from($from, $prefix);
  493. return $query;
  494. }
  495. /**
  496. * @param mixed $object - Core_AclBase or string - namespace
  497. * @return Core_AclFields
  498. */
  499. public static function getObjectFields($object) {
  500. // TODO: try to get structure from `CRM_#CACHE_ACL_OBJECT_FIELD`
  501. // if ($object is instance Core_AclBase) {
  502. // if ($object->isStructInstalled) then get structure from `CRM_#CACHE_ACL_OBJECT_FIELD` and put into Core_AclFields
  503. // else get from $object->getFields() and put into Core_AclFields
  504. }
  505. public static function canUserReadObject($idUser, $aclOrIdZasob) {
  506. throw new Exception("TODO: canUserReadObjec({$idUser}, {$aclOrIdZasob})");
  507. }
  508. public static function canUserCreateObject($idUser, $aclOrIdZasob) {
  509. throw new Exception("TODO: canUserCreateObjec({$idUser}, {$aclOrIdZasob})");
  510. }
  511. public static function canUserWriteObject($idUser, $aclOrIdZasob) {
  512. throw new Exception("TODO: canUserWriteObjec({$idUser}, {$aclOrIdZasob})");
  513. }
  514. public static function canUserReadObjectField($idUser, $aclOrIdZasob, $fieldNameOrXPath) {
  515. throw new Exception("TODO: canUserReadObjectFiel({$idUser}, {$aclOrIdZasob}, {$fieldNameOrXPath})");
  516. }
  517. public static function canUserCreateObjectField($idUser, $aclOrIdZasob, $fieldNameOrXPath) {
  518. throw new Exception("TODO: canUserCreateObjectFiel({$idUser}, {$aclOrIdZasob}, {$fieldNameOrXPath})");
  519. }
  520. public static function canUserWriteObjectField($idUser, $aclOrIdZasob, $fieldNameOrXPath) {
  521. throw new Exception("TODO: canUserWriteObjectFiel({$idUser}, {$aclOrIdZasob}, {$fieldNameOrXPath})");
  522. }
  523. // TODO: replace below:
  524. // AclBase->canCreateField
  525. // AclBase->canReadField
  526. // AclBase->canReadObjectField
  527. // AclBase->canWriteField
  528. // AclBase->canWriteObjectField
  529. // AclBase->canWriteRecord
  530. // AclBase->canReadRecord
  531. }