SystemObjectStorageAcl.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. <?php
  2. Lib::loadClass('Core_AclSimpleSchemaBase');
  3. Lib::loadClass('ParseOgcFilter');
  4. Lib::loadClass('Router');
  5. Lib::loadClass('SchemaVersionUpgrade');
  6. class Schema_SystemObjectStorageAcl extends Core_AclSimpleSchemaBase {
  7. public $_simpleSchema = [
  8. 'root' => [
  9. '@namespace' => 'default_objects/SystemObject',
  10. '@primaryKey' => 'namespace',
  11. 'idZasob' => [ '@type' => 'xsd:integer' ],
  12. 'idDatabase' => [ '@type' => 'xsd:integer' ],
  13. 'namespace' => [ '@type' => 'xsd:string' ],
  14. '_rootTableName' => [ '@type' => 'xsd:string' ],
  15. '_type' => [ '@type' => 'xsd:string' ],
  16. 'hasStruct' => [ '@type' => 'xsd:integer' ], // 0 - removed, old, 1 - has config, structure
  17. 'isStructInstalled' => [ '@type' => 'xsd:integer' ], // installed
  18. 'isObjectActive' => [ '@type' => 'xsd:integer' ], // (0,1) - admin settings with restrictions: (hasStruct, isStructInstalled, all fields installed and with idZasob)
  19. 'description' => [ '@type' => 'xsd:string' ],
  20. 'name' => [ '@type' => 'p5:string' ],
  21. 'typeName' => [ '@type' => 'p5:string' ],
  22. 'nsPrefix' => [ '@type' => 'p5:string' ],
  23. 'reinstallLink' => [ '@type' => 'p5:www_link' ],
  24. 'instanceTableSource' => [ '@type' => 'xsd:string' ], // enum('table', 'view') default 'view'
  25. // 'A_RECORD_CREATE_AUTHOR' => [ '@type' => 'xsd:string' , '@label' => 'autor' ],
  26. // 'A_RECORD_CREATE_DATE' => [ '@type' => 'xsd:date' , '@label' => 'utworzono' ],
  27. // 'A_RECORD_UPDATE_AUTHOR' => [ '@type' => 'xsd:string' , '@label' => 'zaktualizował' ],
  28. // 'A_RECORD_UPDATE_DATE' => [ '@type' => 'xsd:date', '@label' => 'zaktualizowano' ],
  29. 'field' => [ '@ref' => 'default_objects/SystemObjectField', '@maxOccurs' => 'unbounded' ]
  30. ]
  31. ];
  32. // public $_rootTableName = 'CRM_LISTA_ZASOBOW';
  33. public $_rootTableName = 'CRM_#CACHE_ACL_OBJECT';
  34. public function __construct($simpleSchema = null) {
  35. parent::__construct($simpleSchema);
  36. SchemaVersionUpgrade::upgradeSchema();
  37. }
  38. public function updateCache($idDatabase = null) {
  39. DBG::simpleLog('schema', "SystemObject::updateCache...");
  40. // DB::getPDO()->execSql(" drop table if exists `{$this->_rootTableName}` "); // TODO: DBG
  41. DB::getPDO()->execSql(" update `{$this->_rootTableName}` set hasStruct = 0 ");
  42. $sourceStorage = SchemaFactory::loadDefaultObject('SystemSource');
  43. $listSourceToUpdate = $sourceStorage->getItems([ 'f_hasConfig' => 1 ]);
  44. foreach ($listSourceToUpdate as $source) {
  45. if ('default_objects' == $source['nsPrefix']) {
  46. $this->_updateDefaultObjectsStorageAclCache($source['idZasob']);
  47. }
  48. else {
  49. try {
  50. $this->_updateDatabaseCache($source);
  51. } catch (AlertWarningException $e) {
  52. UI::alert('warning', "Warning source '{$source['idZasob']}': " . $e->getMessage());
  53. continue;
  54. } catch (Exception $e) {
  55. UI::alert('danger', "Error source '{$source['idZasob']}': " . $e->getMessage());
  56. continue;
  57. }
  58. }
  59. }
  60. // Ant objects in: SE/schema/ant-object/
  61. $basePath = APP_PATH_SCHEMA . "/ant-object";
  62. foreach (glob("{$basePath}/*/*/build.xml", GLOB_NOSORT) as $buildXmlPath) {
  63. try {
  64. $this->_updateAntObjectCache($buildXmlPath, $basePath);
  65. } catch (Exception $e) {
  66. UI::alert('danger', $e->getMessage());
  67. }
  68. }
  69. if ($activeProject = Config::getProjectPath()) {
  70. $baseAntObjectPath = "{$activeProject}/schema/ant-object";
  71. DBG::nicePrint($baseAntObjectPath, "\$baseAntObjectPath");
  72. foreach (glob("{$baseAntObjectPath}/*/*/build.xml", GLOB_NOSORT) as $buildXmlPath) {
  73. try {
  74. $this->_updateAntObjectCache($buildXmlPath, $baseAntObjectPath);
  75. } catch (Exception $e) {
  76. UI::alert('danger', $e->getMessage());
  77. }
  78. }
  79. }
  80. // Remove AntAcl with no struct (!hasStruct)
  81. DB::getPDO()->execSql("
  82. DELETE from `CRM_#CACHE_ACL_OBJECT`
  83. where hasStruct = 0 and _type = 'AntAcl' and idZasob IS NULL
  84. ");
  85. // TODO: Fix AntAcl without struct but added to Zasoby
  86. $toRemoveInstalledAntAcl = DB::getPDO()->fetchAll("
  87. select *
  88. from `CRM_#CACHE_ACL_OBJECT`
  89. where hasStruct = 0 and _type = 'AntAcl' and idZasob IS NOT NULL
  90. ");
  91. DBG::nicePrint($toRemoveInstalledAntAcl, "to remove AntAcl added to Zasoby already but without xsd file");
  92. foreach ($toRemoveInstalledAntAcl as $antAclToRmInfo) {
  93. self::deleteObjectFromCache($antAclToRmInfo['idZasob'], $antAclToRmInfo['namespace']);
  94. }
  95. // Fix objects AntAcl which struct is not installed
  96. $listAntAclObjectsToFix = DB::getPDO()->fetchAll("
  97. select t.*
  98. from `CRM_#CACHE_ACL_OBJECT` t
  99. where t._type = 'AntAcl'
  100. and t.idZasob is not NULL
  101. and t.hasStruct = 1
  102. and t.isStructInstalled = 0
  103. ");
  104. if (!empty($listAntAclObjectsToFix)) {
  105. UI::alert('info', "Fix AntAcl objects which is not installed (total: ".count($listAntAclObjectsToFix).")");
  106. foreach ($listAntAclObjectsToFix as $antAclInfo) {
  107. $namespace = $antAclInfo['namespace'];
  108. DBG::nicePrint($antAclInfo, "\$antAclInfo ({$namespace})");
  109. $zasobyStruct = DB::getPDO()->fetchAll("
  110. select z.ID, z.`DESC`
  111. from `CRM_LISTA_ZASOBOW` z
  112. where z.PARENT_ID = :parent_id
  113. and z.`TYPE` = 'KOMORKA'
  114. and z.A_STATUS not in ('DELETED')
  115. ", [ ':parent_id' => $antAclInfo['idZasob'] ]);
  116. DBG::nicePrint($zasobyStruct, "\$zasobyStruct ({$namespace})");
  117. ob_start();
  118. {
  119. Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
  120. { // if build.xml file not exists then remove from Acl Cache (and Zasoby)
  121. Lib::loadClass('Api_WfsNs');
  122. $typeName = Api_WfsNs::toTypeName($namespace);
  123. $antAclPath = Schema_SystemObjectFieldStorageAcl::getAntAclXsdBasePath($typeName);
  124. if (!file_exists("{$antAclPath}/build.xml")) {
  125. UI::alert('danger', "Ant build file not exists for namespace '{$antAclInfo['namespace']}' - Removing AntAcl");
  126. self::deleteObjectFromCache($antAclInfo['idZasob'], $antAclInfo['namespace']);
  127. ob_get_clean();
  128. continue;
  129. }
  130. }
  131. $objFieldAcl = new Schema_SystemObjectFieldStorageAcl();
  132. try {
  133. $objFieldAcl->updateCache($namespace);
  134. } catch (Exception $e) {
  135. UI::alert('danger', $e->getMessage());
  136. self::deleteObjectFromCache($antAclInfo['idZasob'], $antAclInfo['namespace']);
  137. ob_get_clean();
  138. continue;
  139. }
  140. }
  141. $reinstallLog = ob_get_clean();
  142. // DBG::nicePrint($reinstallLog, "\$reinstallLog ({$namespace})");
  143. $fieldCacheStruct = DB::getPDO()->fetchAll("
  144. select t.namespace, t.fieldNamespace
  145. from `CRM_#CACHE_ACL_OBJECT_FIELD` t
  146. where t.objectNamespace = :namespace
  147. and t.idZasob is NULL
  148. ", [ ':namespace' => $namespace ]);
  149. DBG::nicePrint($fieldCacheStruct, "\$fieldCacheStruct ({$namespace})");
  150. $fieldsToFix = [];
  151. foreach ($fieldCacheStruct as $cacheField) {
  152. $fieldName = $cacheField['fieldNamespace'];
  153. foreach ($zasobyStruct as $fieldZasob) {
  154. if ($fieldZasob['DESC'] === $fieldName) {
  155. $fieldsToFix[] = [
  156. 'idZasob' => $fieldZasob['ID'],
  157. 'namespace' => $cacheField['namespace'],
  158. ];
  159. }
  160. }
  161. }
  162. DBG::nicePrint($fieldsToFix, "\$fieldsToFix ({$namespace})");
  163. foreach ($fieldsToFix as $fixField) {
  164. $affected = SchemaFactory::loadDefaultObject('SystemObjectField')->updateItem([
  165. 'namespace' => $fixField['namespace'],
  166. 'idZasob' => $fixField['idZasob']
  167. ]);
  168. if (!$affected) UI::alert('warning', "field ({$fixField['namespace']}) update idZasob failed");
  169. }
  170. $affected = SchemaFactory::loadDefaultObject('SystemObject')->updateItem([
  171. 'namespace' => $namespace,
  172. 'isObjectActive' => 1
  173. ]);
  174. ($affected)
  175. ? UI::alert('success', "object ({$namespace}) activated")
  176. : UI::alert('warning', "object ({$namespace}) activation failed");
  177. }
  178. }
  179. // // foreach ... DB::getPDO($idDatabase)->fetchAll(select real _rootTableName)
  180. // foreach (Core_AclHelper::getCustomAclList() as $typeName) {
  181. // $ns = Core_AclHelper::parseTypeName($typeName);
  182. // $namespace = str_replace('__x3A__', '/', $ns['prefix']) . "/{$ns['name']}";
  183. // $sqlNs = DB::getPDO()->quote($namespace, PDO::PARAM_STR);
  184. // $idZasob = DB::getPDO()->fetchValue(" select ID from CRM_LISTA_ZASOBOW where `DESC` = {$sqlNs} and `TYPE` = 'TABELA' and A_STATUS in('WAITING', 'NORMAL') ");
  185. // if (!$idZasob) {
  186. // DBG::nicePrint($ns, "TODO: insert zasob PARENT_ID = ?");
  187. // }
  188. // }
  189. SchemaVersionUpgrade::fixSystemObjectCoreTablesStructInstalled();
  190. }
  191. function _updateDefaultObjectsStorageAclCache($idSource) {
  192. $clsFiles = array_map(function ($clsFile) {
  193. return substr($clsFile, strlen(APP_PATH_LIB . "/Schema/"), -1 * strlen('StorageAcl.php'));
  194. // return str_replace('/', '_', substr($clsFile, strlen(APP_PATH_LIB . "/Schema/"), -1 * strlen('StorageAcl.php')));
  195. }, array_merge(
  196. glob(APP_PATH_LIB . "/Schema/*StorageAcl.php", GLOB_NOSORT),
  197. glob(APP_PATH_LIB . "/Schema/*/*StorageAcl.php", GLOB_NOSORT)
  198. ));
  199. DBG::log($clsFiles, 'array', "DBG glob default_objects");
  200. foreach ($clsFiles as $clsName) {
  201. try {
  202. $acl = SchemaFactory::loadDefaultObject($clsName);
  203. $namespace = $acl->getNamespace();
  204. DB::getPDO()->insertOrUpdate($this->_rootTableName, [
  205. 'namespace' => $namespace,
  206. 'idDatabase' => $idSource,
  207. '_type' => "StorageAcl",
  208. '_rootTableName' => $acl->getRootTableName(),
  209. 'hasStruct' => 1
  210. ]);
  211. } catch (Exception $e) {
  212. UI::alert('danger', $e->getMessage());
  213. }
  214. }
  215. DB::getPDO()->execSql("
  216. insert into `{$this->_rootTableName}` (namespace, idZasob, idDatabase, description, hasStruct)
  217. select concat('default_objects/', t.`DESC`)
  218. , t.ID as idZasob
  219. , '{$idSource}' as idDatabase
  220. , t.`OPIS` as description
  221. , 1 as hasStruct
  222. from CRM_LISTA_ZASOBOW t
  223. where t.`TYPE` = 'TABELA'
  224. and t.A_STATUS in('NORMAL', 'WAITING')
  225. and t.PARENT_ID = {$idSource}
  226. and t.`DESC` not like '%/%'
  227. on duplicate key update idZasob = t.ID
  228. , hasStruct = 1
  229. ");
  230. }
  231. function _updateDatabaseCache($source) {
  232. $dbName = DB::getPDO($source['idZasob'])->getDatabaseName();
  233. $dbType = DB::getPDO($source['idZasob'])->getType();
  234. switch ($dbType) {
  235. case 'mysql': return $this->_updateDatabaseMysqlCache($source, $dbName, $dbType);
  236. default: throw new AlertWarningException("Not imeplemented db type '{$dbType}': { id: {$source['idZasob']}, nsPrefix: '{$source['nsPrefix']}', dbName: '{$dbName}', dbType: <b>'{$dbType}'</b>}");
  237. }
  238. }
  239. function _updateDatabaseMysqlCache($source, $dbName) {
  240. // TODO: if another DB split select and insert
  241. DB::getPDO()->execSql("
  242. insert into `{$this->_rootTableName}` (namespace, idDatabase, _rootTableName, _type, description, hasStruct, isStructInstalled)
  243. select concat('{$source['nsPrefix']}/', t.TABLE_NAME) as namespace
  244. , '{$source['idZasob']}' as idDatabase
  245. , t.TABLE_NAME as _rootTableName
  246. , 'TableAcl' as _type
  247. , t.TABLE_COMMENT as description
  248. , 1 as hasStruct
  249. , 1 as isStructInstalled
  250. from INFORMATION_SCHEMA.TABLES t
  251. where t.TABLE_SCHEMA = '{$dbName}'
  252. and t.TABLE_NAME not like '%#%'
  253. and t.TABLE_NAME not like '%@%'
  254. on duplicate key update _rootTableName = t.TABLE_NAME
  255. , hasStruct = 1
  256. , isStructInstalled = 1
  257. ");
  258. // Insert to Cache from Zasoby
  259. // NOTE: hasStruct cannot be set bc struct may not exists
  260. DB::getPDO()->execSql("
  261. insert into `{$this->_rootTableName}` (namespace, idZasob, idDatabase, description)
  262. select IF(t.`DESC` like '{$source['nsPrefix']}/%',
  263. t.`DESC`,
  264. concat('{$source['nsPrefix']}/', t.`DESC`)
  265. ) as namespace
  266. , t.ID as idZasob
  267. , '{$source['idZasob']}' as idDatabase
  268. , t.`OPIS` as description
  269. from CRM_LISTA_ZASOBOW t
  270. where t.`TYPE` = 'TABELA'
  271. and t.A_STATUS in('NORMAL', 'WAITING')
  272. and t.PARENT_ID = {$source['idZasob']}
  273. on duplicate key update idZasob = t.ID
  274. ");
  275. }
  276. function _updateAntObjectCache($buildXmlPath, $basePath) {
  277. // format: "{$basePath}/{prefix}.{rootTableName}/{objectName}/build.xml"
  278. // regex: ^([a-zA-Z_]*)\.([a-zA-Z_]*)\/([a-zA-Z_]*)$
  279. // example: SE/schema/ant-object/default_db.test_perms/TestPermsAnt/build.xml
  280. $relativePath = substr($buildXmlPath, strlen("{$basePath}/")); // expected: "{prefix}.{rootTableName}/{objectName}/build.xml"
  281. $ret = preg_match_all('/^([0-9a-zA-Z_]*)\.([0-9a-zA-Z_]*)\/([0-9a-zA-Z_-]*)\/build\.xml$/', $relativePath, $matches, PREG_SET_ORDER);
  282. if (!$ret) throw new Exception("Syntax error in ant acl path: {$relativePath}");
  283. $antInfo = [
  284. 'sourceName' => $matches[0][1],
  285. 'rootTableName' => $matches[0][2],
  286. 'objectName' => $matches[0][3],
  287. ];
  288. DBG::nicePrint($antInfo, "relativePath({$relativePath})");
  289. $idDatabase = DB::getPDO($antInfo['sourceName'])->getZasobId();
  290. $namespace = "{$antInfo['sourceName']}/{$antInfo['rootTableName']}/{$antInfo['objectName']}";
  291. DB::getPDO()->insertOrUpdate($this->_rootTableName, [
  292. 'namespace' => $namespace,
  293. 'idDatabase' => $idDatabase,
  294. '_type' => "AntAcl",
  295. '_rootTableName' => $antInfo['rootTableName'],
  296. 'hasStruct' => 1
  297. ]);
  298. }
  299. public function _parseWhere($params = []) {
  300. $sqlWhere = [];
  301. DBG::log($params, 'array', "SystemObject::_parseWhere");
  302. if (!empty($params['#refFrom'])) {
  303. // '#refFrom' => [
  304. // 'namespace' => 'default_objects/SystemSource',
  305. // 'primaryKey' => $sourceItem['idZasob']
  306. // ]
  307. if (empty($params['#refFrom']['namespace'])) throw new Exception("Missing refFrom/namespace");
  308. if (empty($params['#refFrom']['primaryKey'])) throw new Exception("Missing refFrom/primaryKey");
  309. if ('default_objects/SystemSource' != $params['#refFrom']['namespace']) throw new Exception("Unsupported refFrom/namespace '{$params['#refFrom']['namespace']}'");
  310. $sqlWhere[] = "t.idDatabase = " . DB::getPDO()->quote($params['#refFrom']['primaryKey'], PDO::PARAM_INT);
  311. }
  312. {
  313. $filterParams = [];
  314. $xsdFields = $this->getXsdTypes();
  315. foreach ($params as $k => $v) {
  316. if ('f_' != substr($k, 0, 2)) continue;
  317. $fieldName = substr($k, 2);
  318. if (!array_key_exists($fieldName, $xsdFields)) {
  319. // TODO: check query by xpath or use different param prefix
  320. throw new Exception("Field '{$fieldName}' not found in '{$this->_namespace}'");
  321. }
  322. if ('p5:www_link' == $xsdFields[$fieldName]) {
  323. continue;
  324. }
  325. $filterParams[$fieldName] = $v;
  326. }
  327. }
  328. if (!empty($filterParams)) {
  329. DBG::log($filterParams, 'array', "SystemObject::_parseWhere TODO \$filterParams");
  330. foreach ($filterParams as $fieldName => $value) {
  331. if (is_array($value)) {
  332. DBG::log($value, 'array', "TODO SystemObject::_parseWhere array value for \$filterParams[{$fieldName}]");
  333. } else if (is_scalar($value)) {
  334. if ('=' == substr($value, 0, 1)) {
  335. $sqlWhere[] = "t.{$fieldName} = " . DB::getPDO()->quote(substr($value, 1), PDO::PARAM_STR);
  336. } else {
  337. $sqlWhere[] = "t.{$fieldName} like " . DB::getPDO()->quote("%{$value}%", PDO::PARAM_STR);
  338. }
  339. } else {
  340. DBG::log($value, 'array', "BUG SystemObject::_parseWhere unknown type for \$filterParams[{$fieldName}]");
  341. }
  342. }
  343. }
  344. return (!empty($sqlWhere)) ? "where " . implode(" and ", $sqlWhere) : '';
  345. }
  346. public function getTotal($params = []) {
  347. $sqlWhere = $this->_parseWhere($params);
  348. return DB::getPDO()->fetchValue("
  349. select count(1) as cnt
  350. from `{$this->_rootTableName}` t
  351. {$sqlWhere}
  352. ");
  353. }
  354. public function clearGetItemCache($pk = null) {
  355. if (!$this->_cache) return;
  356. if (!$pk) $this->_cache = [];
  357. else if (array_key_exists($pk, $this->_cache)) unset($this->_cache[$pk]);
  358. }
  359. public function getItem($pk, $params = []) {
  360. // TODO: ceche query for: $pk = 'default_db/CRM_PROCES/PROCES', $params = [ 'propertyName' => "*,field" ]
  361. $pk = ACL::getBaseNamespace($pk);
  362. if (!$this->_cache) $this->_cache = [];
  363. if (1 === count($params) && "*,field" === V::get('propertyName', '', $params)) {
  364. if (array_key_exists($pk, $this->_cache)) return $this->_cache[$pk];
  365. $this->_cache[$pk] = $this->_fetchItem($pk, $params);
  366. } else {
  367. return $this->_fetchItem($pk, $params);
  368. }
  369. return $this->_cache[$pk];
  370. }
  371. public function _fetchItem($pk, $params = []) {
  372. if (!$pk) throw new Exception("Missing primary key '{$this->_namespace}'");
  373. $pkField = $this->getSqlPrimaryKeyField();
  374. if (!$pkField) throw new Exception("Missing primary key field defined in '{$this->_namespace}'");
  375. $sqlPk = DB::getPDO()->quote($pk, PDO::PARAM_STR);
  376. $item = DB::getPDO()->fetchFirst("
  377. select t.*
  378. from `{$this->_rootTableName}` t
  379. where t.`{$pkField}` = {$sqlPk}
  380. ");
  381. if (!$item) throw new Exception("Item '{$pk}' not exists - type '{$this->_namespace}'");
  382. return $this->buildFeatureFromSqlRow($item, $params);
  383. }
  384. public function getItems($params = []) {
  385. $sqlWhere = $this->_parseWhere($params);
  386. $currSortCol = V::get('order_by', 'idZasob', $params);
  387. $currSortFlip = strtolower(V::get('order_dir', 'desc', $params));
  388. // TODO: validate $currSortCol is in field list
  389. // TODO: validate $currSortFlip ('asc' or 'desc')
  390. $xsdFields = $this->getXsdTypes();
  391. if (!array_key_exists($currSortCol, $xsdFields)) throw new Exception("Field '{$currSortCol}' not found in '{$this->_namespace}'");
  392. if (!in_array($currSortFlip, ['asc', 'desc'])) throw new Exception("Sort dir not allowed");
  393. $sqlOrderBy = "order by t.`{$currSortCol}` {$currSortFlip}";
  394. $limit = V::get('limit', 0, $params, 'int');
  395. $limit = ($limit < 0) ? 0 : $limit;
  396. $offset = V::get('limitstart', 0, $params, 'int');
  397. $offset = ($offset < 0) ? 0 : $offset;
  398. $sqlLimit = ($limit > 0)
  399. ? "limit {$limit} offset {$offset}"
  400. : '';
  401. Lib::loadClass('AclQueryItems');
  402. $query = new AclQueryItems($this);
  403. $query->setParams($params);
  404. $query->setSource('default_db');
  405. $query->setRawSql("
  406. select t.*
  407. from `{$this->_rootTableName}` t
  408. {$sqlWhere}
  409. {$sqlOrderBy}
  410. {$sqlLimit}
  411. ");
  412. return $query->fetchAll();
  413. }
  414. public function buildFeatureFromSqlRow($item, $params = []) {
  415. DBG::log($params, 'array', "buildFeatureFromSqlRow... '{$item['namespace']}'");
  416. $exNs = explode('/', $item['namespace']);
  417. $item['name'] = array_pop($exNs);
  418. $item['nsPrefix'] = implode('__x3A__', $exNs);
  419. $item['typeName'] = implode('__x3A__', $exNs) . ':' . $item['name'];
  420. $item['reinstallLink'] = Router::getRoute('Storage_AclReinstall')->getLink('', [ 'namespace' => $item['namespace'] ]);
  421. if (!empty($params['propertyName'])) {
  422. if (is_string($params['propertyName'])) $params['propertyName'] = explode(',', $params['propertyName']);
  423. if (!is_array($params['propertyName'])) throw new Exception("Wrong param propertyName - expected array or string");
  424. foreach ($params['propertyName'] as $fetchField) {
  425. if ('*' == $fetchField) continue;
  426. if ('field' == $fetchField) {
  427. $item['field'] = SchemaFactory::loadDefaultObject('SystemObjectField')->getItems([
  428. '__backRef' => [
  429. 'namespace' => 'default_objects/SystemObject',
  430. 'primaryKey' => $item['namespace']
  431. ],
  432. 'order_by' => 'sortPrio',
  433. 'order_dir' => 'asc',
  434. ]);
  435. }
  436. }
  437. }
  438. return $item;
  439. }
  440. public function updateItem($itemPatch) { // @required [ 'namespace' => ... ] (primaryKey)
  441. $pkField = $this->getPrimaryKeyField();
  442. $pk = V::get($pkField, null, $itemPatch);
  443. if (null === $pk) throw new Exception("BUG missing primary key field for '{$this->_namespace}' updateItem");
  444. $this->clearGetItemCache($pk);
  445. DBG::log(['updateItem $itemPatch', $itemPatch]);
  446. unset($itemPatch[$pkField]);
  447. if (empty($itemPatch)) return 0;
  448. foreach ($itemPatch as $fieldName => $value) {
  449. if ('isStructInstalled' == $fieldName) continue;
  450. if ('isObjectActive' == $fieldName) continue;
  451. if ('primaryKey' == $fieldName) continue;
  452. if ('appInfo' == $fieldName) continue;
  453. throw new Exception("Update field '{$fieldName}' not allowed for '{$this->_namespace}'");
  454. }
  455. return DB::getPDO()->update($this->_rootTableName, $pkField, $pk, $itemPatch);
  456. }
  457. static function deleteObjectFromCache($idZasob, $namespace) {
  458. if (!$idZasob) throw new Exception("Missing idZasob in deleteObjectFromCache");
  459. if (!$namespace) throw new Exception("Missing namespace in deleteObjectFromCache");
  460. DB::getPDO()->execSql("
  461. DELETE from `CRM_#CACHE_ACL_OBJECT` where idZasob = :id_zasob
  462. ", [
  463. ':id_zasob' => $idZasob,
  464. ]);
  465. DB::getPDO()->execSql("
  466. DELETE from `CRM_#CACHE_ACL_OBJECT_FIELD` where objectNamespace = :namespace
  467. ", [
  468. ':namespace' => $namespace,
  469. ]);
  470. DB::getPDO()->insert('CRM_LISTA_ZASOBOW_HIST', [
  471. 'ID_USERS2' => $idZasob,
  472. 'A_STATUS' => "DELETED",
  473. 'A_RECORD_UPDATE_AUTHOR' => "update-acl-cache",
  474. 'A_RECORD_UPDATE_DATE' => "NOW()",
  475. ]);
  476. DB::getPDO()->update('CRM_LISTA_ZASOBOW', 'ID', $idZasob, [
  477. 'A_STATUS' => "DELETED",
  478. 'A_RECORD_UPDATE_AUTHOR' => "update-acl-cache",
  479. 'A_RECORD_UPDATE_DATE' => "NOW()",
  480. ]);
  481. }
  482. }