SystemObjectStorageAcl.php 20 KB

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