AclStruct.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. <?php
  2. Lib::loadClass('RouteBase');
  3. Lib::loadClass('Router');
  4. Lib::loadClass('Response');
  5. Lib::loadClass('UI');
  6. Lib::loadClass('SchemaFactory');
  7. class Route_Storage_AclStruct extends RouteBase {
  8. public function handleAuth() {
  9. if (!User::logged()) {
  10. User::authByRequest();
  11. }
  12. }
  13. public function defaultAction() {
  14. UI::gora();
  15. UI::menu();
  16. // Router::getRoute('Storage')->navView(); // TODO: header like in Storage_AclUsage
  17. UI::startTag('div', [ 'class' => 'container-fluid' ]);
  18. try {
  19. $namespace = V::get('namespace', '', $_GET);
  20. if (empty($namespace)) throw new Exception("Missing param namespace");
  21. // [idZasob] => 25872
  22. // [idDatabase] => 36
  23. // [namespace] => default_db/CRM_PROCES/CRM_PROCES
  24. // [_rootTableName] => CRM_PROCES
  25. // [_type] => AntAcl
  26. // [hasStruct] => 1
  27. // [isStructInstalled] => 1
  28. // [isObjectActive] => 1
  29. // [description] =>
  30. // [name] => CRM_PROCES
  31. // [nsPrefix] => default_db__x3A__CRM_PROCES
  32. // [typeName] => default_db__x3A__CRM_PROCES:CRM_PROCES
  33. // [reinstallLink] => https://biuro.biall-net.pl/dev-pl/se-master/index.php?_route=Storage&_task=objectReinstall&namespace=default_db/CRM_PROCES/CRM_PROCES
  34. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  35. switch ($item['_type']) {
  36. case 'TableAcl': $this->tableStructView($item, $item['name'], $item['idDatabase']); break;
  37. case 'AntAcl': $this->objectStructView($item); break;
  38. default: throw new Exception("Not implemented type"); break;
  39. }
  40. } catch (Exception $e) {
  41. UI::alert('danger', "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage());
  42. DBG::log($e);
  43. }
  44. UI::endTag('div'); // .container-fluid
  45. UI::dol();
  46. }
  47. public function tableStructAction() {
  48. UI::gora();
  49. UI::menu();
  50. // Router::getRoute('Storage')->navView(); // TODO: header like in Storage_AclUsage
  51. try {
  52. $idStorage = V::get('idStorage', 0, $_REQUEST, 'int');
  53. if (empty($idStorage)) throw new Exception("Missing id storage");
  54. $storageList = Router::getRoute('Storage')->getStorageList();
  55. if (empty($storageList)) throw new Exception("No storage defined");
  56. if (!array_key_exists($idStorage, $storageList)) throw new Exception("Storage not exists");
  57. $tblName = V::get('table', '', $_REQUEST, 'word');
  58. if (empty($tblName)) throw new Exception("No table name");
  59. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  60. $this->tableStructView($item, $tblName, $idStorage);
  61. } catch (Exception $e) {
  62. UI::alert('danger', "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage());
  63. }
  64. UI::dol();
  65. }
  66. public function objectStructureAction() { // objectStructAction
  67. UI::gora();
  68. UI::menu();
  69. // Router::getRoute('Storage')->navView(); // TODO: header like in Storage_AclUsage
  70. UI::startTag('div', [ 'class' => 'container-fluid' ]);
  71. try {
  72. $namespace = V::get('namespace', '', $_GET);
  73. if (empty($namespace)) throw new Exception("Missing param namespace");
  74. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  75. $this->objectStructView($item);
  76. } catch (Exception $e) {
  77. UI::alert('danger', "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage());
  78. DBG::log($e);
  79. }
  80. UI::endTag('div'); // .container-fluid
  81. UI::dol();
  82. }
  83. public function tableStructView($item, $tblName, $idStorage) {
  84. $storagePdo = DB::getStorage($idStorage);
  85. $tblStruct = $storagePdo->getTableStruct($tblName);
  86. $idTable = Router::getRoute('Storage')->fetchTableId($idStorage, $tblName);
  87. if ($idTable <= 0) {
  88. UI::alert('warning', "Zasob tabela '{$tblName}' nie istnieje");// TODO: add p5UI btn
  89. DBG::table("tblStruct", $tblStruct, __CLASS__, __FUNCTION__, __LINE__);
  90. throw new Exception("Zasob tabela '{$tblName}' nie istnieje");
  91. }
  92. $cellZasobList = array();
  93. foreach (DB::getPDO()->fetchAllByKey("
  94. select z.ID, z.`DESC`, z.`TYPE` as ZASOB_TYPE, z.A_STATUS
  95. from CRM_LISTA_ZASOBOW z
  96. where z.PARENT_ID = '{$idTable}'
  97. ", $key = 'DESC') as $ind => $row) {
  98. $cellZasobList[strtolower($ind)] = $row;
  99. }
  100. $emptyItem = array();
  101. $emptyItem['name'] = '';
  102. $emptyItem['id_zasob'] = '';
  103. $emptyItem['zasob_type'] = '';
  104. $emptyItem['uwagi'] = '';
  105. $emptyItem['type'] = '';
  106. $emptyItem['is_nullable'] = '';
  107. $emptyItem['default_value'] = '';
  108. $emptyItem['default_is_null'] = '';
  109. $emptyItem['max_length'] = '';
  110. $emptyItem['num_precision'] = '';
  111. $emptyItem['num_scale'] = '';
  112. $emptyItem['char_encoding'] = '';
  113. $emptyItem['char_collation'] = '';
  114. $emptyItem['extra'] = '';
  115. $emptyItem['raw_storage_type'] = '';
  116. $tableList = array();
  117. foreach ($tblStruct as $row) {
  118. $cellName = $row['name'];
  119. $tblItem = V::cloneArray($emptyItem);
  120. $tblItem['name'] = $cellName;
  121. foreach ($row as $fldName => $fldVal) {
  122. if (array_key_exists($fldName, $tblItem)) $tblItem[$fldName] = $fldVal;
  123. }
  124. $tblItem['uwagi'] = '';
  125. $lowerCellName = strtolower($cellName);
  126. $tblZasob = V::get($lowerCellName, '', $cellZasobList);
  127. if ($tblZasob) {
  128. $cellZasobList[$lowerCellName]['_checked'] = true;
  129. $tblItem['id_zasob'] = $tblZasob['ID'];
  130. $tblItem['zasob_type'] = $tblZasob['ZASOB_TYPE'];
  131. } else {
  132. $tblItem['uwagi'] .= '!Zasob';//'TODO: ADD ZASOB';
  133. $ajaxAddZasobLink = Router::getRoute('Storage')->getLink('addCellToZasoby', [ 'idStorage' => $idStorage, 'tblName' => $tblName, 'cellName' => $cellName]);
  134. $onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addCellToZasoby', { href: '{$ajaxAddZasobLink}' })";
  135. $tblItem['id_zasob'] = '<a onclick="'.$onClick.'" class="btn btn-xs btn-primary" href="#">TODO: ADD ZASOB</a>';
  136. }
  137. $tableList[] = $tblItem;
  138. }
  139. foreach ($cellZasobList as $cellName => $row) {
  140. if ('URL_ACTION' == $row['ZASOB_TYPE']) continue;
  141. if (!$row['_checked']) {
  142. $tblItem = V::cloneArray($emptyItem);
  143. $tblItem['name'] = $cellName;
  144. $tblItem['id_zasob'] = $row['ID'];
  145. $tblItem['zasob_type'] = $row['ZASOB_TYPE'];
  146. $tblItem['uwagi'] = '!DB';//'TODO: nie istnieje w bazie danych';
  147. $tableList[] = $tblItem;
  148. }
  149. }
  150. usort($tableList, function($rowA, $rowB) {
  151. $a = $rowA['name']; $b = $rowB['name'];
  152. if ('ID' == $a) return -1;
  153. if ('ID' == $b) return 1;
  154. if ($a == $b) return 0;
  155. $a1 = substr($a, 0, 1); $b1 = substr($b, 0, 1);
  156. if (('_' == $a1 || '_' == $b1) && $a1 != $b1) {
  157. return ($a1 < $b1) ? 1 : -1;
  158. }
  159. return ($a < $b) ? -1 : 1;
  160. });
  161. UI::table([
  162. 'caption' => UI::h('span', [], [
  163. "Komórki [{$idTable}] ",
  164. UI::h('a', [
  165. 'href' => "index.php?_route=ViewTableAjax&namespace=default_db/{$tblName}",
  166. 'class' => "btn btn-md btn-link"
  167. ], "Przeglądaj tabelę"),
  168. UI::h('a', [
  169. 'href' => "procesy5.php?task=CRM_LISTA_ZASOBOW&filtr_id={$idTable}&filtr_ids=%2B&filtr_ob=%2B",
  170. 'class' => "btn btn-md btn-link",
  171. 'title' => "Struktura aktualnie przeglądanej tabeli"
  172. ], "Zasoby"),
  173. UI::h('a', [
  174. 'href' => "index.php?FUNCTION_INIT=PROCES_MENU&HEADER_NOT_INIT=YES&_task=PROCES_FOR_TABLE&tblId={$idTable}",
  175. 'class' => "btn btn-md btn-link",
  176. 'title' => "Procesy dla aktualnie przeglądanej tabeli"
  177. ], "Procesy"),
  178. UI::h('a', [
  179. 'href' => Router::getRoute('Storage_AclUsage')->getLink('', [ 'namespace' => "default_db/{$tblName}" ]),
  180. 'class' => "btn btn-md btn-link",
  181. 'title' => "Uprawnienia - analiza użycia komórek w procesach"
  182. ], "Uprawnienia (analiza użycia)"),
  183. ]),
  184. 'cols' => array_keys($emptyItem),
  185. 'rows' => $tableList
  186. ]);
  187. echo UI::h('script', [], "
  188. jQuery(document).on('p5UIBtnAjax:Storage:addCellToZasoby:click', function(e, n, payload) {
  189. console.log('event p5UIBtnAjax:Storage:addCellToZasoby:click', n, payload);
  190. });
  191. jQuery(document).on('p5UIBtnAjax:Storage:addCellToZasoby:ajaxLoaded', function(e, n, payload) {
  192. console.log('event p5UIBtnAjax:Storage:addCellToZasoby:ajaxLoaded', n, payload);
  193. if ('success' == payload.type && payload.body && payload.body.id > 0) {
  194. var cellUwagiJQNode = jQuery(n).parents('td').next('td');
  195. cellUwagiJQNode.text(cellUwagiJQNode.text().replace('!Zasob', ''))
  196. jQuery(n).parents('td').text(payload.body.id);
  197. jQuery(n).remove();
  198. }
  199. jQuery.notify(payload.msg, payload.type);
  200. });
  201. ");
  202. $ajaxAddZasobLink = Router::getRoute('Storage')->getLink('addGeomEtykietaCells', [ 'idStorage' => $idStorage, 'tblName' => $tblName]);
  203. $onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addGeomEtykietaCells', { href: '{$ajaxAddZasobLink}' })";
  204. UI::tag('a', ['onclick'=>$onClick, 'class'=>"btn btn-xs btn-default", 'href'=>"#"], "Dodaj komórki etykiet", true);
  205. echo "<i>(<code>`etykieta_x`</code>, <code>`etykieta_y`</code>, <code>`etykieta_obrot`</code>)</i>";
  206. echo UI::h('script', [], "
  207. jQuery(document).on('p5UIBtnAjax:Storage:addGeomEtykietaCells:ajaxLoaded', function(e, n, payload) {
  208. console.log('event p5UIBtnAjax:Storage:addGeomEtykietaCells:ajaxLoaded', n, payload);
  209. if ('success' == payload.type && payload.body && payload.body.id > 0) {
  210. var cellUwagiJQNode = jQuery(n).parents('td').next('td');
  211. cellUwagiJQNode.text(cellUwagiJQNode.text().replace('!Zasob', ''))
  212. jQuery(n).parents('td').text(payload.body.id);
  213. jQuery(n).remove();
  214. }
  215. jQuery.notify(payload.msg, payload.type);
  216. });
  217. ");
  218. $tableActions = array_filter($cellZasobList, function ($row) {
  219. return ('URL_ACTION' == $row['ZASOB_TYPE']);
  220. });
  221. UI::table([
  222. 'caption' => "tableActions",
  223. // 'cols' => array_keys($emptyItem),
  224. 'rows' => array_map(function ($item) {
  225. $sqlIdAction = DB::getPDO()->quote($item['ID'], PDO::PARAM_INT);
  226. $args = DB::getPDO()->fetchAll("
  227. select z.`DESC`
  228. , a.ID as ALIAS_ID, a.`DESC` as ALIAS_DESC, a.OPIS as ALIAS_OPIS
  229. from CRM_LISTA_ZASOBOW z
  230. left join CRM_LISTA_ZASOBOW a on(a.ID = z.ALIAS_ID)
  231. where z.PARENT_ID = {$sqlIdAction}
  232. and z.`TYPE` = 'PARAM_IN'
  233. ");
  234. $definitionArgs = DB::getPDO()->fetchAll("
  235. select p.ID, p.`DESC`
  236. from CRM_LISTA_ZASOBOW z
  237. join CRM_LISTA_ZASOBOW d on(d.ID = z.ALIAS_ID)
  238. left join CRM_LISTA_ZASOBOW p on(p.PARENT_ID = d.ID)
  239. where z.ID = {$sqlIdAction}
  240. and p.`TYPE` = 'PARAM_IN'
  241. ");
  242. $flatDefinitionArgs = implode(";", array_map(function ($arg) {
  243. return "{$arg['ID']}={$arg['DESC']}";
  244. }, $definitionArgs));
  245. return [
  246. 'label' => DB::getPDO()->fetchValue(" select z.OPIS from CRM_LISTA_ZASOBOW z where z.ID = {$sqlIdAction} ") . " " .
  247. UI::h('i', [
  248. 'class' => "glyphicon glyphicon-pencil",
  249. 'style' => "cursor:pointer",
  250. 'onClick' => "return Storage__tableStruct__editActionLabel(this, {$sqlIdAction})"], ''),
  251. 'args' => implode("<br>&", array_map(function ($item) {
  252. return (NULL === $item['ALIAS_ID'])
  253. ? $item['DESC']
  254. : "{$item['DESC']}=" . '{$row["' . $item['ALIAS_DESC'] . '"]}';// TODO: add rmParam btn
  255. }, $args)) . " " .
  256. UI::h('i', [
  257. 'class' => "glyphicon glyphicon-plus-sign",
  258. 'style' => "cursor:pointer",
  259. 'title' => "Dodaj PARAM_IN",
  260. 'onClick' => "return Storage__tableStruct__addParamAction(this, {$sqlIdAction}, '{$flatDefinitionArgs}')"], ''),
  261. // 'args_info' => '<pre>' . var_export($args, true) . '</pre>',
  262. 'ID' => $item['ID'],
  263. 'DESC' => $item['DESC'],
  264. 'A_STATUS' => $item['A_STATUS'],
  265. 'definition args' => implode("", array_map(function ($item) {
  266. return '<div style="white-space:nowrap">' . "[{$item['ID']}] {$item['DESC']}" . '</div>';
  267. }, $definitionArgs)),
  268. ];
  269. }, $tableActions)
  270. ]);
  271. echo UI::h('button', [
  272. 'onClick'=>"Storage__tableStruct__addAction()",
  273. 'class'=>"btn btn-xs btn-default"
  274. ], "Dodaj Akcję");
  275. echo UI::h('link', ['rel'=>"stylesheet", 'type'=>"text/css", 'href'=>"static/sweetalert2.min.css"]);
  276. echo UI::h('script', ['src'=>"static/sweetalert2.min.js"]);
  277. echo UI::h('style', [], "
  278. .swal2-radio.p5-swal-radio-as-list { text-align:left }
  279. .swal2-radio.p5-swal-radio-as-list > label { display:block; margin-left:20px }
  280. ");
  281. UI::inlineJS(__FILE__ . '.tableActions.js', [
  282. 'ID_STORAGE' => $idStorage,
  283. 'TABLE_NAME' => $tblName,
  284. 'FETCH_URL' => Router::getRoute('Storage')->getLink('fetchActionListAjax'),
  285. 'ADD_ACTION_URL' => Router::getRoute('Storage')->getLink('addActionAjax')
  286. ]);
  287. echo '<hr>';
  288. $ajaxAddBaseProcesLink = Router::getRoute('Storage')->getLink('addTableBaseProces', [ 'idStorage' => $idStorage, 'tblName' => $tblName ]);
  289. $onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addTableBaseProces', { href: '{$ajaxAddBaseProcesLink}' })";
  290. UI::tag('a', ['onclick'=>$onClick, 'class'=>"btn btn-xs btn-default", 'href'=>"#"], "Dodaj podstawowy proces dla tabeli '{$tblName}' - read only", true);
  291. echo UI::h('script', [], "
  292. jQuery(document).on('p5UIBtnAjax:Storage:addTableBaseProces:ajaxLoaded', function(e, n, payload) {
  293. jQuery.notify(payload.msg, payload.type);
  294. });
  295. ");
  296. }
  297. public function objectStructView($item) {
  298. $namespace = $item['namespace'];
  299. { // sortBy
  300. $sortByArgName = 'sortBy';
  301. $sortByCol = V::get($sortByArgName, 'namespace', $_GET);
  302. $sortByDir = V::get("{$sortByArgName}Dir", 'asc', $_GET);
  303. { // add SORT_PRIO
  304. $item['field'] = array_map(function ($field) {
  305. $field['SORT_PRIO'] = ($field['idZasob'] > 0)
  306. ? DB::getPDO()->fetchValue("
  307. select z.SORT_PRIO
  308. from CRM_LISTA_ZASOBOW z
  309. where z.ID = :id
  310. ", [ ':id' => $field['idZasob'] ])
  311. : null
  312. ;
  313. return $field;
  314. }, $item['field']);
  315. }
  316. if ('namespace' === $sortByCol) {
  317. usort($item['field'], function ($a, $b) use ($sortByDir) {
  318. if ($a['fieldNamespace'] > $b['fieldNamespace']) return 'asc' === $sortByDir ? 1 : -1;
  319. if ($a['fieldNamespace'] < $b['fieldNamespace']) return 'asc' === $sortByDir ? -1 : 1;
  320. return 0;
  321. });
  322. }
  323. else if ('sort' === $sortByCol) {
  324. usort($item['field'], function ($a, $b) use ($sortByDir) {
  325. if (null === $a['SORT_PRIO'] && null === $b['SORT_PRIO']) return 0;
  326. if (null === $a['SORT_PRIO'] && null != $b['SORT_PRIO']) return 1;
  327. if (null !== $a['SORT_PRIO'] && null === $b['SORT_PRIO']) return -1;
  328. if ($a['SORT_PRIO'] > $b['SORT_PRIO']) return 'asc' === $sortByDir ? 1 : -1;
  329. if ($a['SORT_PRIO'] < $b['SORT_PRIO']) return 'asc' === $sortByDir ? -1 : 1;
  330. return 0;
  331. });
  332. }
  333. echo UI::h('style', [ 'type' => "text/css" ], "
  334. .ta-ordering { cursor:pointer }
  335. .ta-ordering-desc:after { content:\"\\e252\"; font-family:\"Glyphicons Halflings\"; line-height:1; margin:0 0 0 3px; display:inline-block; color:#bbb }
  336. .ta-ordering-asc:after { content:\"\\e253\"; font-family:\"Glyphicons Halflings\"; line-height:1; margin:0 0 0 3px; display:inline-block; color:#bbb }
  337. .ta-sortable-item { }
  338. .ta-sortable-item-handle { cursor:pointer }
  339. ");
  340. echo UI::h('script', [ 'src' => "static/URI.js" ]);
  341. echo UI::h('script', [], "
  342. function p5UI_table_sortBy_get(n, argName, colName, dir) {
  343. var newUri = URI(window.location.href).setQuery(argName, colName).setQuery(argName+'Dir', dir).build().toString();
  344. window.location.href = newUri
  345. }
  346. ");
  347. }
  348. if ('setFieldRefConfig' === V::get('_postTask', '', $_POST)) {
  349. $field = V::get('field', '', $_POST);
  350. $source = V::get('source', '', $_POST);
  351. switch ($source) {
  352. case 'view':
  353. $refSelect = ACL::generateRefSelectSqlByFlatRelationCache($namespace, $field);
  354. ACL::setRefSource($namespace, $field, 'view', $refSelect);
  355. break;
  356. case 'table': ACL::setRefSource($namespace, $field, 'table'); break;
  357. }
  358. }
  359. if ('preview' === V::get('_postTask', '', $_POST)) {
  360. try {
  361. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  362. $localFields = array_filter($item['field'], function ($field) {
  363. return $field['isLocal'];
  364. });
  365. $refFields = array_filter($item['field'], function ($field) {
  366. return 'ref:' === substr($field['xsdType'], 0, 4);
  367. });
  368. $activeRefFields = array_filter($refFields, function ($field) {
  369. $refNamespace = str_replace(['__x3A__', ':'], '/', substr($field['xsdType'], strlen('ref:')));
  370. return (1 == DB::getPDO()->fetchValue("
  371. select t.isObjectActive
  372. from `CRM_#CACHE_ACL_OBJECT` t
  373. where t.`namespace` = '{$refNamespace}'
  374. "));
  375. });
  376. $previewItems = ACL::getAclByNamespace($namespace)->buildQuery([])->getItems([
  377. 'limit' => 5
  378. ]);
  379. DBG::nicePrint($previewItems, 'items (default query) - preview (limit 5)');
  380. $query = [ 'cols' => array_merge(
  381. array_map(
  382. function ($field) {
  383. return $field['fieldNamespace'];
  384. }, $localFields
  385. ),
  386. array_map(
  387. function ($field) {
  388. return "{$field['fieldNamespace']}/*";
  389. }, $activeRefFields
  390. )
  391. ) ];
  392. DBG::nicePrint($query, 'items with ref/* - query');
  393. $previewItems = ACL::getAclByNamespace($namespace)->buildQuery($query)->getItems([
  394. 'limit' => 5
  395. ]);
  396. DBG::nicePrint($previewItems, 'items with ref/* - preview (limit 5)');
  397. $query = [ 'cols' => array_merge(
  398. array_map(
  399. function ($field) {
  400. return $field['fieldNamespace'];
  401. }, $localFields
  402. ),
  403. array_map(
  404. function ($field) {
  405. return "{$field['fieldNamespace']}";
  406. }, $activeRefFields
  407. )
  408. ) ];
  409. DBG::nicePrint($query, 'items with ref as xlink - query');
  410. $previewItems = ACL::getAclByNamespace($namespace)->buildQuery($query)->getItems([
  411. 'limit' => 5
  412. ]);
  413. DBG::nicePrint($previewItems, 'items with ref as xlink - preview (limit 5)');
  414. } catch (Exception $e) {
  415. DBG::log($e);
  416. UI::alert('danger', $e->getMessage());
  417. }
  418. }
  419. echo UI::h('details', ['style'=>"margin-bottom:24px; padding:0 10px; background-color:#eee", 'open' => "open"], [
  420. UI::h('summary', ['style'=>"font-size:1.4em; line-height:2em; cursor:pointer; outline:none"], [
  421. "Struktura obiektu '{$namespace}' ",
  422. // UI::h('small', ['style'=>"font-size:0.8em; font-style:italic; color:#aaa"], " więcej...")
  423. ]),
  424. UI::h('div', ['style'=>"padding:4px 24px; border-top:1px solid #fff"], [
  425. UI::h('span', ['style'=>"margin-right:12px"], [
  426. ( ($item['idZasob'] > 0)
  427. ? UI::h('span', [ 'title' => "Nr zasobu '{$item['idZasob']}'" ], "Nr zasobu [{$item['idZasob']}]")
  428. : UI::h('span', [ 'title' => "Brak nr zasobu - dodaj do zasobów" ], [
  429. UI::hButtonAjax("+ do zasobów", 'addAclObjectToZasobyAjax', [
  430. 'class' => "btn btn-xs btn-primary",
  431. 'href' => Router::getRoute('Storage')->getLink('addAclObjectToZasobyAjax'),
  432. 'data' => [
  433. 'idStorage' => $item['idDatabase'],
  434. 'namespace' => $item['namespace'],
  435. ]
  436. ])
  437. ])
  438. ),
  439. ]),
  440. UI::h('span', ['style'=>"margin:0 12px"], [
  441. ( ($item['isObjectActive'] > 0)
  442. ? UI::h('span', [ 'class' => "label label-success", 'title' => "Namespace active" ], "Active")
  443. : UI::h('span', [ 'title' => "Namespace not active" ], [
  444. ($item['idZasob'] > 0)
  445. ? UI::hButtonAjax("Aktywuj", 'activateObjectAjax', [
  446. 'class' => "btn btn-xs btn-primary",
  447. 'href' => Router::getRoute('Storage')->getLink('activateObjectAjax'),
  448. 'data' => [
  449. 'namespace' => $item['namespace'],
  450. ]
  451. ])
  452. : '',
  453. ])
  454. ),
  455. ]),
  456. UI::h('a', [
  457. 'href' => "index.php?_route=ViewTableAjax&namespace={$item['namespace']}",
  458. 'class' => "btn btn-sm btn-link"
  459. ], "Przeglądaj tabelę"),
  460. ( ($item['idZasob'] > 0)
  461. ? UI::h('a', [
  462. 'href' => "procesy5.php?task=CRM_LISTA_ZASOBOW&filtr_id={$item['idZasob']}&filtr_ids=%2B&filtr_ob=%2B",
  463. 'class' => "btn btn-sm btn-link",
  464. 'title' => "Struktura tabeli w drzewie zasobów"
  465. ], "Zasoby")
  466. : ''
  467. ),
  468. ( ($item['idZasob'] > 0)
  469. ? UI::h('a', [
  470. 'href' => "index.php?FUNCTION_INIT=PROCES_MENU&HEADER_NOT_INIT=YES&_task=PROCES_FOR_TABLE&tblId={$item['idZasob']}",
  471. 'class' => "btn btn-sm btn-link",
  472. 'title' => "Procesy dla aktualnie przeglądanej tabeli"
  473. ], "Procesy")
  474. : ''
  475. ),
  476. UI::h('a', [
  477. 'href' => Router::getRoute('Storage')->getLink('objectReinstall', ['namespace' => $item['namespace']]),
  478. 'class' => 'btn btn-sm btn-link', 'style' => "color:#f00",
  479. 'title' => "Zainstaluje ponownie obiekt"
  480. ], "reinstall object"),
  481. UI::h('a', [
  482. 'href' => Router::getRoute('Storage_AclUsage')->getLink('', [ 'namespace' => $item['namespace'] ]),
  483. 'class' => "btn btn-sm btn-link",
  484. 'title' => "Uprawnienia - analiza użycia komórek w procesach"
  485. ], "Uprawnienia (analiza użycia)"),
  486. UI::hButtonPost("(podgląd z relacjami)", [
  487. 'data' => [
  488. '_postTask' => 'preview'
  489. ],
  490. 'class' => 'btn btn-sm btn-link', 'style' => "font-style:italic",
  491. 'title' => "Podgląd kilku ostatnich obiektów wraz z relacjami"
  492. ]),
  493. ])
  494. ]);
  495. $thisGetLink = [Router::getRoute('Storage'), 'getLink'];
  496. { // not installed ref
  497. $refFields = array_filter($item['field'], function ($field) {
  498. return 'ref:' === substr($field['xsdType'], 0, 4);
  499. });
  500. UI::table([
  501. 'caption' => UI::h('span', [], "Obiekty powiązane (TODO backRef)"),
  502. 'rows' => array_map(function ($field) use ($thisGetLink) {
  503. $refNamespace = str_replace(['__x3A__', ':'], '/', substr($field['xsdType'], strlen('ref:')));
  504. $isInstalled = (1 == DB::getPDO()->fetchValue("
  505. select t.isObjectActive
  506. from `CRM_#CACHE_ACL_OBJECT` t
  507. where t.`namespace` = '{$refNamespace}'
  508. "));
  509. $refSource = null;
  510. if ($isInstalled) {
  511. try {
  512. $refTable = ACL::getRefTable($field['objectNamespace'], $field['fieldNamespace']);
  513. DBG::log($refTable, 'array', "getRefTable('{$field['objectNamespace']}', '{$field['fieldNamespace']}')");
  514. $refSource = ACL::getRefSource($field['objectNamespace'], $field['fieldNamespace']);
  515. DBG::log($refSource, 'array', "ACL::getRefSource('{$field['objectNamespace']}', '{$field['fieldNamespace']}')");
  516. } catch (Exception $e) {
  517. DBG::log($e);
  518. }
  519. }
  520. return [
  521. 'fieldName' => $field['fieldNamespace'],
  522. // 'xsdType' => $field['xsdType'], // always === "ref:{$field['fieldNamespace']}"
  523. 'ref object' => UI::h('a', [
  524. 'class' => "btn btn-xs btn-link",
  525. 'href' => $thisGetLink('objectStruct', [ 'namespace' => $refNamespace ])
  526. ], "objectStruct ({$refNamespace})"),
  527. 'ref source' => UI::h('div', [],
  528. (null === $refSource)
  529. ? [ "ref object not installed" ] // TODO: link to install? is table struct
  530. : [
  531. // UI::hButtonAjax("Tabela ref", "setFieldRefConfig", [
  532. // 'class' => "btn btn-xs btn-default" . ( 'table' === $refSource ? ' disabled' : '' ),
  533. // 'href' => $thisGetLink('setFieldRefConfig'),
  534. // 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], 'do' => 'table' ]
  535. // ]),
  536. // UI::hButtonAjax("Widok (cache)", "setFieldRefConfig", [
  537. // 'title' => "Według flat_relation_cache",
  538. // 'class' => "btn btn-xs btn-default" . ( 'view' === $refSource ? ' disabled' : '' ),
  539. // 'href' => $thisGetLink('setFieldRefConfig'),
  540. // 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], 'do' => 'view' ]
  541. // ]),
  542. UI::hButtonPost("Tabela ref", [
  543. 'title' => "Według wygenerowanej tabeli REF",
  544. 'class' => "btn btn-xs btn-default" . ( 'table' === $refSource ? ' disabled' : '' ),
  545. // 'href' => $thisGetLink('setFieldRefConfig'),
  546. 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], '_postTask' => 'setFieldRefConfig', 'source' => 'table' ]
  547. ]),
  548. UI::hButtonPost("Widok (cache)", [
  549. 'title' => "Według flat_relation_cache",
  550. 'class' => "btn btn-xs btn-default" . ( 'view' === $refSource ? ' disabled' : '' ),
  551. // 'href' => $thisGetLink('setFieldRefConfig'),
  552. 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], '_postTask' => 'setFieldRefConfig', 'source' => 'view' ]
  553. ]),
  554. ]
  555. ),
  556. '@class' => ($isInstalled) ? "success" : "danger",
  557. ]; // TODO: link to install object
  558. }, $refFields)
  559. ]);
  560. }
  561. UI::table([
  562. '__html_id' => 'struct_table',
  563. 'caption' => UI::h('span', [], [
  564. UI::h('span', [ 'style' => "margin-right:6px;color:#000" ], "Struktura obiektu '{$item['namespace']}'"),
  565. ]),
  566. // 'sortBy' => [
  567. // 'method' => 'get',
  568. // 'argName' => '_sortBy',
  569. // 'allow' => ['sort', 'namespace'],
  570. // 'default' => ['namespace', 'asc'],
  571. // ],
  572. 'cols_label' => [
  573. 'sort' => UI::h('nobr', [
  574. 'class' => "ta-ordering" . ('sort' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  575. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'sort', '" . ('sort' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  576. 'title' => "Sortuj wg pola SORT_PRIO z zasobów",
  577. ], "sort"),
  578. 'namespace' => UI::h('nobr', [
  579. 'class' => "ta-ordering" . ('namespace' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  580. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'namespace', '" . ('namespace' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  581. 'title' => "Sortuj wg pola SORT_PRIO z zasobów",
  582. ], "namespace"),
  583. ],
  584. 'rows' => array_map(function ($field) use ($item, $thisGetLink) {
  585. $tblItem = [];
  586. if (null !== $field['SORT_PRIO'] && !empty($field['idZasob'])) {
  587. $tblItem['@class'] = "ta-sortable-item";
  588. $tblItem['@class[sort]'] = "ta-sortable-item-handle";
  589. $tblItem['@data']['sort_prio'] = $field['SORT_PRIO'];
  590. $tblItem['@data']['id_zasob'] = $field['idZasob'];
  591. $field['SORT_PRIO'] = ":: {$field['SORT_PRIO']}";
  592. }
  593. $tblItem['sort'] = V::get('SORT_PRIO', null, $field);
  594. foreach ($field as $k => $v) {
  595. if ('SORT_PRIO' === $k) continue;
  596. $tblItem[$k] = $v;
  597. }
  598. $tblItem['namespace'] = UI::h('span', [], [
  599. UI::h('span', ['style' => "color:#aaa"], substr($field['namespace'], 0, strlen($field['objectNamespace']) + 1)),
  600. UI::h('span', ['style' => "color:#000"], substr($field['namespace'], strlen($field['objectNamespace']) + 1)),
  601. ]);
  602. $tblItem['idZasob'] = ($field['idZasob'] > 0)
  603. ? $field['idZasob']
  604. : (
  605. ($item['idZasob'] > 0)
  606. ? UI::hButtonAjax("+ do zasobów", 'addFieldToZasobyAjax', [
  607. 'class' => "btn btn-xs btn-primary",
  608. 'href' => $thisGetLink('addFieldToZasobyAjax'),
  609. 'data' => [
  610. 'namespace' => $item['namespace'],
  611. 'fieldNamespace' => $field['namespace'],
  612. ]
  613. ])
  614. : UI::h('span', ['title'=>"Brak Nr zasobu dla obiektu", 'class'=>"btn btn-xs btn-danger"], "Brak nr zasobu obiektu")
  615. )
  616. ;
  617. unset($tblItem['objectNamespace']);
  618. unset($tblItem['fieldNamespace']);
  619. return $tblItem;
  620. }, $item['field'])
  621. ]);
  622. UI::hButtonAjaxOnResponse('addFieldToZasobyAjax', /* payload, n */ "
  623. if (!payload.type) return false
  624. if (payload.body && payload.body.id && payload.body.id > 0) { // if ('success' == payload.type) {
  625. n.parentNode.replaceChild(document.createTextNode(payload.body.id), n)
  626. }
  627. jQuery.notify(payload.msg, payload.type)
  628. ");
  629. UI::hButtonAjaxOnResponse('addAclObjectToZasobyAjax', /* payload, n */ "
  630. if (!payload.type) return false
  631. if ('success' === payload.type || 'info' === payload.type) {
  632. if (payload.body && payload.body.id && payload.body.id > 0) {
  633. n.parentNode.replaceChild(document.createTextNode(payload.body.id), n)
  634. } else {
  635. console.log('TODO: addAclObjectToZasobyAjax unknown response', payload);
  636. }
  637. window.location.reload()
  638. }
  639. ");
  640. UI::hButtonAjaxOnResponse('activateObjectAjax', /* payload, n */ "
  641. jQuery.notify(payload.msg, payload.type)
  642. if (!payload.type) return false
  643. if ('success' === payload.type || 'info' === payload.type) {
  644. if (payload.body && payload.body.isObjectActive && payload.body.isObjectActive > 0) {
  645. n.parentNode.replaceChild(document.createTextNode('Active'), n)
  646. } else {
  647. console.log('TODO: activateObjectAjax unknown response', payload);
  648. }
  649. }
  650. ");
  651. if ('sort' === $sortByCol) {
  652. echo UI::h('script', [], "
  653. jQuery(document).ready(function (){
  654. var tblNode$ = jQuery('#struct_table > tbody')
  655. var getOrder = function () {
  656. var orderIds = []
  657. jQuery('#struct_table > tbody').children('.ta-sortable-item').each(function (idx, trNode) {
  658. orderIds.push(jQuery(trNode).data('id_zasob'))
  659. })
  660. return orderIds
  661. }
  662. var sortOrder = getOrder()
  663. console.log('sortOrder - init', sortOrder)
  664. tblNode$.sortable({
  665. axis: 'y',
  666. handle: '.ta-sortable-item-handle',
  667. items: '.ta-sortable-item',
  668. update: function (event, ui) {
  669. sortOrder = getOrder()
  670. tblNode$.sortable('disable')
  671. tblNode$.find('.ta-sortable-item-handle').css({color:'silver'})
  672. console.log('TODO: disable sortable while ajax')
  673. // window.setTimeout(function () {
  674. // tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  675. // console.log('TODO: ajax fetch result')
  676. // tblNode$.sortable('enable')
  677. // tblNode$.sortable('cancel')
  678. // }, 1000)
  679. window.fetch(
  680. URI(window.location.href)
  681. .setSearch('_task', 'updateAntAclSortAjax')
  682. .setSearch('idZasobOrder', sortOrder)
  683. .build().toString(),
  684. {
  685. method: 'POST',
  686. headers: {
  687. 'Content-Type': 'application/x-www-form-urlencoded' // query string
  688. },
  689. credentials: 'same-origin',
  690. body: JSON.stringify({
  691. namespace: URI.parseQuery(window.location.search).namespace,
  692. sortBy: '{$sortByCol}',
  693. sortByDir: '{$sortByDir}',
  694. sortOrder: sortOrder,
  695. })
  696. }
  697. ).then(function(response) {
  698. return response.json()
  699. }).then(function(payload) {
  700. console.log('updateAntAclSortAjax response', payload);
  701. tblNode$.sortable('enable')
  702. if ('success' !== payload.type) {
  703. tblNode$.sortable('cancel')
  704. }
  705. tblNode$.sortable('enable')
  706. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  707. p5UI__notifyAjaxCallback({
  708. type: payload.type || 'error',
  709. msg: payload.msg || 'Request error'
  710. });
  711. }).catch(function(e) {
  712. tblNode$.sortable('enable')
  713. tblNode$.sortable('cancel')
  714. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  715. p5UI__notifyAjaxCallback({
  716. type: 'error',
  717. msg: 'Request error ' + e
  718. });
  719. })
  720. }
  721. });
  722. });
  723. ");
  724. }
  725. if ($item['isObjectActive']) {
  726. echo UI::hButtonAjax("Dodaj podstawowy proces dla obiektu '{$item['namespace']}' - read only (TODO)", 'addObjectBaseProcesAjax', [
  727. 'class' => "btn btn-xs btn-default",
  728. 'href' => Router::getRoute('Storage')->getLink('addObjectBaseProcesAjax'),
  729. 'data' => [ 'namespace' => $item['namespace'] ]
  730. ]);
  731. UI::hButtonAjaxOnResponse('addObjectBaseProcesAjax', /* payload, n */ "
  732. jQuery.notify(payload.msg, payload.type)
  733. ");
  734. }
  735. DBG::nicePrint($item, '$item');
  736. }
  737. public function updateAntAclSortAjaxAction() {
  738. return Response::sendTryCatchJson(array($this, 'updateAntAclSortAjax'), $args = 'JSON_FROM_REQUEST_BODY');
  739. }
  740. public function updateAntAclSortAjax($args) {
  741. DBG::log($args, 'array', "args");
  742. $namespace = V::get('namespace', '', $args);
  743. if (empty($namespace)) throw new Exception("Missing param namespace");
  744. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  745. DBG::log($item, 'array', "\$item");
  746. $sortByArgName = 'sortBy';
  747. $sortByCol = V::get($sortByArgName, 'namespace', $args);
  748. $sortByDir = V::get("{$sortByArgName}Dir", 'asc', $args);
  749. if ('sort' !== $sortByCol) throw new Exception("Only sort by SORT_PRIO allowed to update");
  750. if (!in_array($sortByDir, ['asc', 'desc'])) throw new Exception("Wrong order by dir arg");
  751. if ('asc' !== $sortByDir) throw new Exception("Only sort asc is allowed"); // DBG
  752. $sortPrioIdsFromZasoby = DB::getPDO()->fetchAll("
  753. select z.ID, z.SORT_PRIO
  754. from CRM_LISTA_ZASOBOW z
  755. where z.PARENT_ID = :p_id
  756. order by z.SORT_PRIO asc, z.ID asc -- default order in Zasoby tree
  757. ", [
  758. ':p_id' => $item['idZasob']
  759. ]);
  760. DBG::log($sortPrioIdsFromZasoby, 'array', "\$sortPrioIdsFromZasoby");
  761. $idZasobCurrentOrder = array_map(function ($orderRow) {
  762. return (int)$orderRow['ID'];
  763. }, $sortPrioIdsFromZasoby);
  764. DBG::log($idZasobCurrentOrder, 'array', "\$idZasobCurrentOrder");
  765. DBG::log(array_diff_assoc($args['sortOrder'], $idZasobCurrentOrder), 'array', "array_diff_assoc(\$args['sortOrder'], \$idZasobCurrentOrder)");
  766. DBG::log(array_diff_assoc($idZasobCurrentOrder, $args['sortOrder']), 'array', "array_diff_assoc(\$idZasobCurrentOrder, \$args['sortOrder'])");
  767. $orderDiff = array_diff_assoc($args['sortOrder'], $idZasobCurrentOrder);
  768. foreach ($orderDiff as $sortPrio => $idZasob) {
  769. DB::getPDO()->update('CRM_LISTA_ZASOBOW', 'ID', $idZasob, [
  770. 'SORT_PRIO' => $sortPrio,
  771. ]);
  772. }
  773. return [
  774. 'type' => 'success',
  775. 'msg' => "OK",
  776. 'DBG__args' => $args
  777. ];
  778. }
  779. }