AclStruct.php 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270
  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_AclReinstall&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. case 'StorageAcl': $this->objectStructView($item); break;
  39. default: throw new Exception("Not implemented type"); break;
  40. }
  41. } catch (Exception $e) {
  42. UI::alert('danger', "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage());
  43. DBG::log($e);
  44. }
  45. UI::endTag('div'); // .container-fluid
  46. UI::dol();
  47. }
  48. public function tableStructAction() {
  49. UI::gora();
  50. UI::menu();
  51. // Router::getRoute('Storage')->navView(); // TODO: header like in Storage_AclUsage
  52. try {
  53. $idStorage = V::get('idStorage', 0, $_REQUEST, 'int');
  54. if (empty($idStorage)) throw new Exception("Missing id storage");
  55. $storageList = Router::getRoute('Storage')->getStorageList();
  56. if (empty($storageList)) throw new Exception("No storage defined");
  57. if (!array_key_exists($idStorage, $storageList)) throw new Exception("Storage not exists");
  58. $tblName = V::get('table', '', $_REQUEST, 'word');
  59. if (empty($tblName)) throw new Exception("No table name");
  60. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  61. $this->tableStructView($item, $tblName, $idStorage);
  62. } catch (Exception $e) {
  63. UI::alert('danger', "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage());
  64. }
  65. UI::dol();
  66. }
  67. public function objectStructureAction() { // objectStructAction
  68. UI::gora();
  69. UI::menu();
  70. // Router::getRoute('Storage')->navView(); // TODO: header like in Storage_AclUsage
  71. UI::startTag('div', [ 'class' => 'container-fluid' ]);
  72. try {
  73. $namespace = V::get('namespace', '', $_GET);
  74. if (empty($namespace)) throw new Exception("Missing param namespace");
  75. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  76. $this->objectStructView($item);
  77. } catch (Exception $e) {
  78. UI::alert('danger', "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage());
  79. DBG::log($e);
  80. }
  81. UI::endTag('div'); // .container-fluid
  82. UI::dol();
  83. }
  84. public function tableStructView($item, $tblName, $idStorage) {
  85. $storagePdo = DB::getStorage($idStorage);
  86. $tblStruct = $storagePdo->getTableStruct($tblName);
  87. $idTable = Router::getRoute('Storage')->fetchTableId($idStorage, $tblName);
  88. if ($idTable <= 0) {
  89. UI::alert('warning', "Zasob tabela '{$tblName}' nie istnieje");// TODO: add p5UI btn
  90. DBG::table("tblStruct", $tblStruct, __CLASS__, __FUNCTION__, __LINE__);
  91. throw new Exception("Zasob tabela '{$tblName}' nie istnieje");
  92. }
  93. $cellZasobList = array();
  94. foreach (DB::getPDO()->fetchAllByKey("
  95. select z.ID, z.`DESC`, z.`TYPE` as ZASOB_TYPE, z.A_STATUS, z.SORT_PRIO
  96. from CRM_LISTA_ZASOBOW z
  97. where z.PARENT_ID = '{$idTable}'
  98. ", $key = 'DESC') as $ind => $row) {
  99. $cellZasobList[strtolower($ind)] = $row;
  100. }
  101. $emptyItem = array();
  102. $emptyItem['sort'] = null;
  103. $emptyItem['name'] = '';
  104. $emptyItem['id_zasob'] = '';
  105. $emptyItem['zasob_type'] = '';
  106. $emptyItem['uwagi'] = '';
  107. $emptyItem['type'] = '';
  108. $emptyItem['is_nullable'] = '';
  109. $emptyItem['default_value'] = '';
  110. $emptyItem['default_is_null'] = '';
  111. $emptyItem['max_length'] = '';
  112. $emptyItem['num_precision'] = '';
  113. $emptyItem['num_scale'] = '';
  114. $emptyItem['char_encoding'] = '';
  115. $emptyItem['char_collation'] = '';
  116. $emptyItem['extra'] = '';
  117. $emptyItem['raw_storage_type'] = '';
  118. $tableList = array();
  119. foreach ($tblStruct as $row) {
  120. $cellName = $row['name'];
  121. $tblItem = V::cloneArray($emptyItem);
  122. $tblItem['name'] = $cellName;
  123. foreach ($row as $fldName => $fldVal) {
  124. if (array_key_exists($fldName, $tblItem)) $tblItem[$fldName] = $fldVal;
  125. }
  126. $tblItem['uwagi'] = '';
  127. $lowerCellName = strtolower($cellName);
  128. $tblZasob = V::get($lowerCellName, '', $cellZasobList);
  129. if ($tblZasob) {
  130. $cellZasobList[$lowerCellName]['_checked'] = true;
  131. $tblItem['id_zasob'] = $tblZasob['ID'];
  132. $tblItem['zasob_type'] = $tblZasob['ZASOB_TYPE'];
  133. $tblItem['sort'] = $tblZasob['SORT_PRIO'];
  134. } else {
  135. $tblItem['uwagi'] .= '!Zasob';//'TODO: ADD ZASOB';
  136. $ajaxAddZasobLink = Router::getRoute('Storage')->getLink('addCellToZasoby', [ 'idStorage' => $idStorage, 'tblName' => $tblName, 'cellName' => $cellName]);
  137. $onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addCellToZasoby', { href: '{$ajaxAddZasobLink}' })";
  138. $tblItem['id_zasob'] = '<a onclick="'.$onClick.'" class="btn btn-xs btn-primary" href="#">TODO: ADD ZASOB</a>';
  139. }
  140. $tableList[] = $tblItem;
  141. }
  142. foreach ($cellZasobList as $cellName => $row) {
  143. if ('URL_ACTION' == $row['ZASOB_TYPE']) continue;
  144. if (!$row['_checked']) {
  145. $tblItem = V::cloneArray($emptyItem);
  146. $tblItem['name'] = $cellName;
  147. $tblItem['id_zasob'] = $row['ID'];
  148. $tblItem['zasob_type'] = $row['ZASOB_TYPE'];
  149. $tblItem['uwagi'] = '!DB';//'TODO: nie istnieje w bazie danych';
  150. $tableList[] = $tblItem;
  151. }
  152. }
  153. { // sortBy
  154. $sortByArgName = 'sortBy';
  155. $sortByCol = V::get($sortByArgName, 'name', $_GET);
  156. $sortByDir = V::get("{$sortByArgName}Dir", 'asc', $_GET);
  157. if ('name' === $sortByCol) {
  158. usort($tableList, function($rowA, $rowB) {
  159. $a = $rowA['name']; $b = $rowB['name'];
  160. // if ('ID' == $a) return -1;
  161. // if ('ID' == $b) return 1;
  162. if ($a == $b) return 0;
  163. $a1 = substr($a, 0, 1); $b1 = substr($b, 0, 1);
  164. if (('_' == $a1 || '_' == $b1) && $a1 != $b1) {
  165. return ($a1 < $b1) ? 1 : -1;
  166. }
  167. return ($a < $b) ? -1 : 1;
  168. });
  169. }
  170. else if ('sort' === $sortByCol) {
  171. usort($tableList, function ($a, $b) use ($sortByDir) {
  172. if (null === $a['sort'] && null === $b['sort']) return 0;
  173. if (null === $a['sort'] && null != $b['sort']) return 1;
  174. if (null !== $a['sort'] && null === $b['sort']) return -1;
  175. if ($a['sort'] > $b['sort']) return 'asc' === $sortByDir ? 1 : -1;
  176. if ($a['sort'] < $b['sort']) return 'asc' === $sortByDir ? -1 : 1;
  177. return 0;
  178. });
  179. }
  180. echo UI::h('style', [ 'type' => "text/css" ], "
  181. .ta-ordering { cursor:pointer }
  182. .ta-ordering-desc:after { content:\"\\e252\"; font-family:\"Glyphicons Halflings\"; line-height:1; margin:0 0 0 3px; display:inline-block; color:#bbb }
  183. .ta-ordering-asc:after { content:\"\\e253\"; font-family:\"Glyphicons Halflings\"; line-height:1; margin:0 0 0 3px; display:inline-block; color:#bbb }
  184. .ta-sortable-item { }
  185. .ta-sortable-item-handle { cursor:pointer }
  186. ");
  187. echo UI::h('script', [ 'src' => "static/URI.js" ]);
  188. echo UI::h('script', [], "
  189. function p5UI_table_sortBy_get(n, argName, colName, dir) {
  190. var newUri = URI(window.location.href).setQuery(argName, colName).setQuery(argName+'Dir', dir).build().toString();
  191. window.location.href = newUri
  192. }
  193. ");
  194. }
  195. echo UI::h('details', ['style'=>"margin-bottom:24px; padding:0 10px; background-color:#eee", 'open' => "open"], [
  196. UI::h('summary', ['style'=>"font-size:1.4em; line-height:2em; cursor:pointer; outline:none"], [
  197. "Struktura obiektu '{$item['namespace']}' ",
  198. ]),
  199. UI::h('div', ['style'=>"padding:4px 24px; border-top:1px solid #fff"], [
  200. UI::h('span', ['style'=>"margin-right:12px"], [
  201. ( ($item['idZasob'] > 0)
  202. ? UI::h('span', [ 'title' => "Nr zasobu '{$item['idZasob']}'" ], "Nr zasobu [{$item['idZasob']}]")
  203. : UI::h('span', [ 'title' => "Brak nr zasobu - dodaj do zasobów" ], [
  204. UI::hButtonAjax("+ do zasobów", 'addAclObjectToZasobyAjax', [
  205. 'class' => "btn btn-xs btn-primary",
  206. 'href' => Router::getRoute('Storage')->getLink('addAclObjectToZasobyAjax'),
  207. 'data' => [
  208. 'idStorage' => $item['idDatabase'],
  209. 'namespace' => $item['namespace'],
  210. ]
  211. ])
  212. ])
  213. ),
  214. ]),
  215. // UI::h('span', ['style'=>"margin:0 12px"], [
  216. // ( ($item['isObjectActive'] > 0)
  217. // ? UI::h('span', [ 'class' => "label label-success", 'title' => "Namespace active" ], "Active")
  218. // : UI::h('span', [ 'title' => "Namespace not active" ], [
  219. // ($item['idZasob'] > 0)
  220. // ? UI::hButtonAjax("Aktywuj", 'activateObjectAjax', [
  221. // 'class' => "btn btn-xs btn-primary",
  222. // 'href' => Router::getRoute('Storage')->getLink('activateObjectAjax'),
  223. // 'data' => [
  224. // 'namespace' => $item['namespace'],
  225. // ]
  226. // ])
  227. // : '',
  228. // ])
  229. // ),
  230. // ]),
  231. UI::h('a', [
  232. 'href' => "index.php?_route=ViewTableAjax&namespace={$item['namespace']}",
  233. 'class' => "btn btn-sm btn-link"
  234. ], "Przeglądaj tabelę"),
  235. ( ($item['idZasob'] > 0)
  236. ? UI::h('a', [
  237. 'href' => "procesy5.php?task=CRM_LISTA_ZASOBOW&filtr_id={$item['idZasob']}&filtr_ids=%2B&filtr_ob=%2B",
  238. 'class' => "btn btn-sm btn-link",
  239. 'title' => "Struktura tabeli w drzewie zasobów"
  240. ], "Zasoby")
  241. : ''
  242. ),
  243. ( ($item['idZasob'] > 0)
  244. ? UI::h('a', [
  245. 'href' => "index.php?FUNCTION_INIT=PROCES_MENU&HEADER_NOT_INIT=YES&_task=PROCES_FOR_TABLE&tblId={$item['idZasob']}",
  246. 'class' => "btn btn-sm btn-link",
  247. 'title' => "Procesy dla aktualnie przeglądanej tabeli"
  248. ], "Procesy")
  249. : ''
  250. ),
  251. // UI::h('a', [
  252. // 'href' => Router::getRoute('Storage_AclReinstall')->getLink('', [ 'namespace' => $item['namespace'] ]),
  253. // 'class' => 'btn btn-sm btn-link', 'style' => "color:#f00",
  254. // 'title' => "Zainstaluje ponownie obiekt"
  255. // ], "reinstall object"),
  256. UI::h('a', [
  257. 'href' => Router::getRoute('Storage_AclUsage')->getLink('', [ 'namespace' => $item['namespace'] ]),
  258. 'class' => "btn btn-sm btn-link",
  259. 'title' => "Uprawnienia - analiza użycia komórek w procesach"
  260. ], "Uprawnienia (analiza użycia)"),
  261. UI::h('a', [
  262. 'href' => Router::getRoute('WfsJsRequestPanel')->getLink('', [ 'namespace' => $item['namespace'] ]),
  263. 'class' => "btn btn-sm btn-link",
  264. 'title' => "JavaScript WFS Panel"
  265. ], "JavaScript WFS Panel"),
  266. UI::h('a', [
  267. 'href' => Router::getRoute('Storage_TestXsd')->getLink('tableXsd', [ 'idStorage' => $idStorage, 'table' => "{$tblName}" ]),
  268. 'class' => "btn btn-md btn-link",
  269. ], "xsd"),
  270. ])
  271. ]);
  272. UI::table([
  273. '__html_id' => 'struct_table',
  274. 'caption' => "Struktura tabeli {$tblName} [{$idTable}]",
  275. 'cols_label' => [
  276. 'sort' => UI::h('nobr', [
  277. 'class' => "ta-ordering" . ('sort' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  278. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'sort', '" . ('sort' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  279. 'title' => "Sortuj wg pola SORT_PRIO z zasobów",
  280. ], "sort"),
  281. 'name' => UI::h('nobr', [
  282. 'class' => "ta-ordering" . ('name' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  283. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'name', '" . ('name' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  284. 'title' => "Sortuj wg nazwy",
  285. ], "namespace"),
  286. ],
  287. 'cols' => array_keys($emptyItem),
  288. 'rows' => array_map(function ($item) use ($sortByCol) {
  289. if ('sort' === $sortByCol && null !== $item['sort'] && !empty($item['id_zasob'])) {
  290. $item['@class'] = "ta-sortable-item";
  291. $item['@class[sort]'] = "ta-sortable-item-handle";
  292. $item['@data']['sort_prio'] = $item['sort'];
  293. $item['@data']['id_zasob'] = $item['id_zasob'];
  294. $item['sort'] = ":: {$item['sort']}";
  295. }
  296. return $item;
  297. }, $tableList),
  298. ]);
  299. echo UI::h('script', [], "
  300. jQuery(document).on('p5UIBtnAjax:Storage:addCellToZasoby:click', function(e, n, payload) {
  301. console.log('event p5UIBtnAjax:Storage:addCellToZasoby:click', n, payload);
  302. });
  303. jQuery(document).on('p5UIBtnAjax:Storage:addCellToZasoby:ajaxLoaded', function(e, n, payload) {
  304. console.log('event p5UIBtnAjax:Storage:addCellToZasoby:ajaxLoaded', n, payload);
  305. if ('success' == payload.type && payload.body && payload.body.id > 0) {
  306. var cellUwagiJQNode = jQuery(n).parents('td').next('td');
  307. cellUwagiJQNode.text(cellUwagiJQNode.text().replace('!Zasob', ''))
  308. jQuery(n).parents('td').text(payload.body.id);
  309. jQuery(n).remove();
  310. }
  311. jQuery.notify(payload.msg, payload.type);
  312. });
  313. ");
  314. $ajaxAddZasobLink = Router::getRoute('Storage')->getLink('addGeomEtykietaCells', [ 'idStorage' => $idStorage, 'tblName' => $tblName]);
  315. $onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addGeomEtykietaCells', { href: '{$ajaxAddZasobLink}' })";
  316. UI::tag('a', ['onclick'=>$onClick, 'class'=>"btn btn-xs btn-default", 'href'=>"#"], "Dodaj komórki etykiet", true);
  317. echo "<i>(<code>`etykieta_x`</code>, <code>`etykieta_y`</code>, <code>`etykieta_obrot`</code>)</i>";
  318. echo UI::h('script', [], "
  319. jQuery(document).on('p5UIBtnAjax:Storage:addGeomEtykietaCells:ajaxLoaded', function(e, n, payload) {
  320. console.log('event p5UIBtnAjax:Storage:addGeomEtykietaCells:ajaxLoaded', n, payload);
  321. if ('success' == payload.type && payload.body && payload.body.id > 0) {
  322. var cellUwagiJQNode = jQuery(n).parents('td').next('td');
  323. cellUwagiJQNode.text(cellUwagiJQNode.text().replace('!Zasob', ''))
  324. jQuery(n).parents('td').text(payload.body.id);
  325. jQuery(n).remove();
  326. }
  327. jQuery.notify(payload.msg, payload.type);
  328. });
  329. ");
  330. $tableActions = array_filter($cellZasobList, function ($row) {
  331. return ('URL_ACTION' == $row['ZASOB_TYPE']);
  332. });
  333. UI::table([
  334. 'caption' => "tableActions",
  335. // 'cols' => array_keys($emptyItem),
  336. 'rows' => array_map(function ($item) {
  337. $sqlIdAction = DB::getPDO()->quote($item['ID'], PDO::PARAM_INT);
  338. $args = DB::getPDO()->fetchAll("
  339. select z.`DESC`
  340. , a.ID as ALIAS_ID, a.`DESC` as ALIAS_DESC, a.OPIS as ALIAS_OPIS
  341. from CRM_LISTA_ZASOBOW z
  342. left join CRM_LISTA_ZASOBOW a on(a.ID = z.ALIAS_ID)
  343. where z.PARENT_ID = {$sqlIdAction}
  344. and z.`TYPE` = 'PARAM_IN'
  345. ");
  346. $definitionArgs = DB::getPDO()->fetchAll("
  347. select p.ID, p.`DESC`
  348. from CRM_LISTA_ZASOBOW z
  349. join CRM_LISTA_ZASOBOW d on(d.ID = z.ALIAS_ID)
  350. left join CRM_LISTA_ZASOBOW p on(p.PARENT_ID = d.ID)
  351. where z.ID = {$sqlIdAction}
  352. and p.`TYPE` = 'PARAM_IN'
  353. ");
  354. $flatDefinitionArgs = implode(";", array_map(function ($arg) {
  355. return "{$arg['ID']}={$arg['DESC']}";
  356. }, $definitionArgs));
  357. return [
  358. 'label' => DB::getPDO()->fetchValue(" select z.OPIS from CRM_LISTA_ZASOBOW z where z.ID = {$sqlIdAction} ") . " " .
  359. UI::h('i', [
  360. 'class' => "glyphicon glyphicon-pencil",
  361. 'style' => "cursor:pointer",
  362. 'onClick' => "return Storage__tableStruct__editActionLabel(this, {$sqlIdAction})"], ''),
  363. 'args' => implode("<br>&", array_map(function ($item) {
  364. return (NULL === $item['ALIAS_ID'])
  365. ? $item['DESC']
  366. : "{$item['DESC']}=" . '{$row["' . $item['ALIAS_DESC'] . '"]}';// TODO: add rmParam btn
  367. }, $args)) . " " .
  368. UI::h('i', [
  369. 'class' => "glyphicon glyphicon-plus-sign",
  370. 'style' => "cursor:pointer",
  371. 'title' => "Dodaj PARAM_IN",
  372. 'onClick' => "return Storage__tableStruct__addParamAction(this, {$sqlIdAction}, '{$flatDefinitionArgs}')"], ''),
  373. // 'args_info' => '<pre>' . var_export($args, true) . '</pre>',
  374. 'ID' => $item['ID'],
  375. 'DESC' => $item['DESC'],
  376. 'A_STATUS' => $item['A_STATUS'],
  377. 'definition args' => implode("", array_map(function ($item) {
  378. return '<div style="white-space:nowrap">' . "[{$item['ID']}] {$item['DESC']}" . '</div>';
  379. }, $definitionArgs)),
  380. ];
  381. }, $tableActions)
  382. ]);
  383. echo UI::h('button', [
  384. 'onClick'=>"Storage__tableStruct__addAction()",
  385. 'class'=>"btn btn-xs btn-default"
  386. ], "Dodaj Akcję");
  387. echo UI::h('link', ['rel'=>"stylesheet", 'type'=>"text/css", 'href'=>"static/sweetalert2.min.css"]);
  388. echo UI::h('script', ['src'=>"static/sweetalert2.min.js"]);
  389. echo UI::h('style', [], "
  390. .swal2-radio.p5-swal-radio-as-list { text-align:left }
  391. .swal2-radio.p5-swal-radio-as-list > label { display:block; margin-left:20px }
  392. ");
  393. UI::inlineJS(__FILE__ . '.tableActions.js', [
  394. 'ID_STORAGE' => $idStorage,
  395. 'TABLE_NAME' => $tblName,
  396. 'FETCH_URL' => Router::getRoute('Storage')->getLink('fetchActionListAjax'),
  397. 'ADD_ACTION_URL' => Router::getRoute('Storage')->getLink('addActionAjax')
  398. ]);
  399. echo '<hr>';
  400. $ajaxAddBaseProcesLink = Router::getRoute('Storage')->getLink('addTableBaseProces', [ 'idStorage' => $idStorage, 'tblName' => $tblName ]);
  401. $onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addTableBaseProces', { href: '{$ajaxAddBaseProcesLink}' })";
  402. UI::tag('a', ['onclick'=>$onClick, 'class'=>"btn btn-xs btn-default", 'href'=>"#"], "Dodaj podstawowy proces dla tabeli '{$tblName}' - read only", true);
  403. echo UI::h('script', [], "
  404. jQuery(document).on('p5UIBtnAjax:Storage:addTableBaseProces:ajaxLoaded', function(e, n, payload) {
  405. jQuery.notify(payload.msg, payload.type);
  406. });
  407. ");
  408. if ('sort' === $sortByCol) {
  409. echo UI::h('script', [], "
  410. jQuery(document).ready(function (){
  411. var tblNode$ = jQuery('#struct_table > tbody')
  412. var getOrder = function () {
  413. var orderIds = []
  414. jQuery('#struct_table > tbody').children('.ta-sortable-item').each(function (idx, trNode) {
  415. orderIds.push(jQuery(trNode).data('id_zasob'))
  416. })
  417. return orderIds
  418. }
  419. var sortOrder = getOrder()
  420. console.log('sortOrder - init', sortOrder)
  421. tblNode$.sortable({
  422. axis: 'y',
  423. handle: '.ta-sortable-item-handle',
  424. items: '.ta-sortable-item',
  425. update: function (event, ui) {
  426. sortOrder = getOrder()
  427. tblNode$.sortable('disable')
  428. tblNode$.find('.ta-sortable-item-handle').css({color:'silver'})
  429. console.log('TODO: disable sortable while ajax')
  430. // window.setTimeout(function () {
  431. // tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  432. // console.log('TODO: ajax fetch result')
  433. // tblNode$.sortable('enable')
  434. // tblNode$.sortable('cancel')
  435. // }, 1000)
  436. window.fetch(
  437. URI(window.location.href)
  438. .setSearch('_task', 'updateAntAclSortAjax')
  439. .setSearch('idZasobOrder', sortOrder)
  440. .build().toString(),
  441. {
  442. method: 'POST',
  443. headers: {
  444. 'Content-Type': 'application/x-www-form-urlencoded' // query string
  445. },
  446. credentials: 'same-origin',
  447. body: JSON.stringify({
  448. namespace: URI.parseQuery(window.location.search).namespace,
  449. sortBy: '{$sortByCol}',
  450. sortByDir: '{$sortByDir}',
  451. sortOrder: sortOrder,
  452. })
  453. }
  454. ).then(function(response) {
  455. return response.json()
  456. }).then(function(payload) {
  457. console.log('updateAntAclSortAjax response', payload);
  458. tblNode$.sortable('enable')
  459. if ('success' !== payload.type) {
  460. tblNode$.sortable('cancel')
  461. }
  462. tblNode$.sortable('enable')
  463. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  464. p5UI__notifyAjaxCallback({
  465. type: payload.type || 'error',
  466. msg: payload.msg || 'Request error'
  467. });
  468. if ('success' === payload.type) {
  469. window.location.reload(true)
  470. }
  471. }).catch(function(e) {
  472. tblNode$.sortable('enable')
  473. tblNode$.sortable('cancel')
  474. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  475. p5UI__notifyAjaxCallback({
  476. type: 'error',
  477. msg: 'Request error ' + e
  478. });
  479. })
  480. }
  481. });
  482. });
  483. ");
  484. }
  485. }
  486. public function objectStructView($item) {
  487. $namespace = $item['namespace'];
  488. { // sortBy
  489. $sortByArgName = 'sortBy';
  490. $sortByCol = V::get($sortByArgName, 'namespace', $_GET);
  491. $sortByDir = V::get("{$sortByArgName}Dir", 'asc', $_GET);
  492. { // add SORT_PRIO
  493. $item['field'] = array_map(function ($field) {
  494. $field['SORT_PRIO'] = ($field['idZasob'] > 0)
  495. ? DB::getPDO()->fetchValue("
  496. select z.SORT_PRIO
  497. from CRM_LISTA_ZASOBOW z
  498. where z.ID = :id
  499. ", [ ':id' => $field['idZasob'] ])
  500. : null
  501. ;
  502. return $field;
  503. }, $item['field']);
  504. }
  505. if ('namespace' === $sortByCol) {
  506. usort($item['field'], function ($a, $b) use ($sortByDir) {
  507. if ($a['fieldNamespace'] > $b['fieldNamespace']) return 'asc' === $sortByDir ? 1 : -1;
  508. if ($a['fieldNamespace'] < $b['fieldNamespace']) return 'asc' === $sortByDir ? -1 : 1;
  509. return 0;
  510. });
  511. }
  512. else if ('sort' === $sortByCol) {
  513. usort($item['field'], function ($a, $b) use ($sortByDir) {
  514. if (null === $a['SORT_PRIO'] && null === $b['SORT_PRIO']) return 0;
  515. if (null === $a['SORT_PRIO'] && null != $b['SORT_PRIO']) return 1;
  516. if (null !== $a['SORT_PRIO'] && null === $b['SORT_PRIO']) return -1;
  517. if ($a['SORT_PRIO'] > $b['SORT_PRIO']) return 'asc' === $sortByDir ? 1 : -1;
  518. if ($a['SORT_PRIO'] < $b['SORT_PRIO']) return 'asc' === $sortByDir ? -1 : 1;
  519. return 0;
  520. });
  521. }
  522. echo UI::h('style', [ 'type' => "text/css" ], "
  523. .ta-ordering { cursor:pointer }
  524. .ta-ordering-desc:after { content:\"\\e252\"; font-family:\"Glyphicons Halflings\"; line-height:1; margin:0 0 0 3px; display:inline-block; color:#bbb }
  525. .ta-ordering-asc:after { content:\"\\e253\"; font-family:\"Glyphicons Halflings\"; line-height:1; margin:0 0 0 3px; display:inline-block; color:#bbb }
  526. .ta-sortable-item { }
  527. .ta-sortable-item-handle { cursor:pointer }
  528. ");
  529. echo UI::h('script', [ 'src' => "static/URI.js" ]);
  530. echo UI::h('script', [], "
  531. function p5UI_table_sortBy_get(n, argName, colName, dir) {
  532. var newUri = URI(window.location.href).setQuery(argName, colName).setQuery(argName+'Dir', dir).build().toString();
  533. window.location.href = newUri
  534. }
  535. ");
  536. }
  537. if ('setFieldRefConfig' === V::get('_postTask', '', $_POST)) {
  538. $objectNamespace = $namespace;
  539. $childTypeName = V::get('field', '', $_POST);
  540. $source = V::get('source', '', $_POST);
  541. $toUpdateField = array_filter($item['field'], function ($field) use ($childTypeName) { return ($childTypeName === $field['fieldNamespace']); });
  542. $toUpdateField = (!empty($toUpdateField)) ? reset($toUpdateField) : null;
  543. if (!$toUpdateField) throw new Exception("Field not found '{$childTypeName}'");
  544. $typeField = Type_Field::build($toUpdateField);
  545. $refConfig = RefConfig::fetch($objectNamespace, $childTypeName);
  546. switch ($source) {
  547. case 'view': RefConfig::installRefView($objectNamespace, $childTypeName, $typeField, $refConfig); break;
  548. case 'table': RefConfig::installRefTable($objectNamespace, $childTypeName, $typeField, $refConfig); break;
  549. }
  550. }
  551. if ('preview' === V::get('_postTask', '', $_POST)) {
  552. try {
  553. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  554. $localFields = array_filter($item['field'], function ($field) {
  555. return $field['isLocal'];
  556. });
  557. $refFields = array_filter($item['field'], function ($field) {
  558. return 'ref:' === substr($field['xsdType'], 0, 4);
  559. });
  560. $activeRefFields = array_filter($refFields, function ($field) {
  561. $refNamespace = str_replace(['__x3A__', ':'], '/', substr($field['xsdType'], strlen('ref:')));
  562. return (1 == DB::getPDO()->fetchValue("
  563. select t.isObjectActive
  564. from `CRM_#CACHE_ACL_OBJECT` t
  565. where t.`namespace` = '{$refNamespace}'
  566. "));
  567. });
  568. $previewItems = ACL::getAclByNamespace($namespace)->buildQuery([])->getItems([
  569. 'limit' => 5
  570. ]);
  571. DBG::nicePrint($previewItems, 'items (default query) - preview (limit 5)');
  572. $query = [ 'cols' => array_merge(
  573. array_map(
  574. function ($field) {
  575. return $field['fieldNamespace'];
  576. }, $localFields
  577. ),
  578. array_map(
  579. function ($field) {
  580. return "{$field['fieldNamespace']}/*";
  581. }, $activeRefFields
  582. )
  583. ) ];
  584. DBG::nicePrint($query, 'items with ref/* - query');
  585. $previewItems = ACL::getAclByNamespace($namespace)->buildQuery($query)->getItems([
  586. 'limit' => 5
  587. ]);
  588. DBG::nicePrint($previewItems, 'items with ref/* - preview (limit 5)');
  589. $query = [ 'cols' => array_merge(
  590. array_map(
  591. function ($field) {
  592. return $field['fieldNamespace'];
  593. }, $localFields
  594. ),
  595. array_map(
  596. function ($field) {
  597. return "{$field['fieldNamespace']}";
  598. }, $activeRefFields
  599. )
  600. ) ];
  601. DBG::nicePrint($query, 'items with ref as xlink - query');
  602. $previewItems = ACL::getAclByNamespace($namespace)->buildQuery($query)->getItems([
  603. 'limit' => 5
  604. ]);
  605. DBG::nicePrint($previewItems, 'items with ref as xlink - preview (limit 5)');
  606. } catch (Exception $e) {
  607. DBG::log($e);
  608. UI::alert('danger', $e->getMessage());
  609. }
  610. }
  611. echo UI::h('div', ['style'=>"margin-bottom:24px; padding:0 10px; background-color:#eee", 'open' => "open"], [
  612. UI::h('div', [], [
  613. UI::h('a', [
  614. 'class' => "btn btn-link",
  615. 'href' => Router::getRoute('Storage')->getLink('tableList', [ 'idStorage' => $item['idDatabase'] ]),
  616. ], "&laquo wróć do listy"),
  617. " ",
  618. UI::h('b', [ 'style' => "font-size:1.1em; line-height:2em" ], "Struktura obiektu '{$namespace}'"),
  619. // UI::h('small', ['style'=>"font-size:0.8em; font-style:italic; color:#aaa"], " więcej...")
  620. ]),
  621. UI::h('div', ['style'=>"padding:4px 24px; border-top:1px solid #fff"], [
  622. UI::h('span', ['style'=>"margin-right:12px"], [
  623. ( ($item['idZasob'] > 0)
  624. ? UI::h('span', [ 'title' => "Nr zasobu '{$item['idZasob']}'" ], "Nr zasobu [{$item['idZasob']}]")
  625. : UI::h('span', [ 'title' => "Brak nr zasobu - dodaj do zasobów" ], [
  626. UI::hButtonAjax("+ do zasobów", 'addAclObjectToZasobyAjax', [
  627. 'class' => "btn btn-xs btn-primary",
  628. 'href' => Router::getRoute('Storage')->getLink('addAclObjectToZasobyAjax'),
  629. 'data' => [
  630. 'idStorage' => $item['idDatabase'],
  631. 'namespace' => $item['namespace'],
  632. ]
  633. ])
  634. ])
  635. ),
  636. ]),
  637. UI::h('span', ['style'=>"margin:0 12px"], [
  638. ( ($item['isObjectActive'] > 0)
  639. ? UI::h('span', [ 'class' => "label label-success", 'title' => "Namespace active" ], "Active")
  640. : UI::h('span', [ 'title' => "Namespace not active" ], [
  641. ($item['idZasob'] > 0)
  642. ? UI::hButtonAjax("Aktywuj", 'activateObjectAjax', [
  643. 'class' => "btn btn-xs btn-primary",
  644. 'href' => Router::getRoute('Storage')->getLink('activateObjectAjax'),
  645. 'data' => [
  646. 'namespace' => $item['namespace'],
  647. ]
  648. ])
  649. : '',
  650. ])
  651. ),
  652. ]),
  653. UI::h('a', [
  654. 'href' => "index.php?_route=ViewTableAjax&namespace={$item['namespace']}",
  655. 'class' => "btn btn-sm btn-link"
  656. ], "Przeglądaj tabelę"),
  657. ( ($item['idZasob'] > 0)
  658. ? UI::h('a', [
  659. 'href' => "procesy5.php?task=CRM_LISTA_ZASOBOW&filtr_id={$item['idZasob']}&filtr_ids=%2B&filtr_ob=%2B",
  660. 'class' => "btn btn-sm btn-link",
  661. 'title' => "Struktura tabeli w drzewie zasobów"
  662. ], "Zasoby")
  663. : ''
  664. ),
  665. ( ($item['idZasob'] > 0)
  666. ? UI::h('a', [
  667. 'href' => "index.php?FUNCTION_INIT=PROCES_MENU&HEADER_NOT_INIT=YES&_task=PROCES_FOR_TABLE&tblId={$item['idZasob']}",
  668. 'class' => "btn btn-sm btn-link",
  669. 'title' => "Procesy dla aktualnie przeglądanej tabeli"
  670. ], "Procesy")
  671. : ''
  672. ),
  673. UI::h('a', [
  674. 'href' => Router::getRoute('Storage_AclReinstall')->getLink('', ['namespace' => $item['namespace']]),
  675. 'class' => 'btn btn-sm btn-link', 'style' => "color:#f00",
  676. 'title' => "Zainstaluje ponownie obiekt"
  677. ], "reinstall object"),
  678. UI::h('a', [
  679. 'href' => Router::getRoute('Storage_AclUsage')->getLink('', [ 'namespace' => $item['namespace'] ]),
  680. 'class' => "btn btn-sm btn-link",
  681. 'title' => "Uprawnienia - analiza użycia komórek w procesach"
  682. ], "Uprawnienia (analiza użycia)"),
  683. UI::h('a', [
  684. 'href' => Router::getRoute('WfsJsRequestPanel')->getLink('', [ 'namespace' => $item['namespace'] ]),
  685. 'class' => "btn btn-sm btn-link",
  686. 'title' => "JavaScript WFS Panel"
  687. ], "JavaScript WFS Panel"),
  688. UI::hButtonPost("(podgląd z relacjami)", [
  689. 'data' => [
  690. '_postTask' => 'preview'
  691. ],
  692. 'class' => 'btn btn-sm btn-link', 'style' => "font-style:italic",
  693. 'title' => "Podgląd kilku ostatnich obiektów wraz z relacjami"
  694. ]),
  695. ])
  696. ]);
  697. $thisGetLink = [ $this, 'getLink' ];
  698. { // not installed ref
  699. $refFields = array_filter($item['field'], function ($field) {
  700. return ('ref:' === substr($field['xsdType'], 0, 4) && $field['isActive']);
  701. });
  702. echo UI::h('h3', [], "Obiekty powiązane");
  703. UI::table([
  704. 'rows' => array_map(function ($backRef) use ($thisGetLink) {
  705. $refNamespace = $backRef['namespace'];
  706. $isInstalled = (1 == DB::getPDO()->fetchValue("
  707. select t.isObjectActive
  708. from `CRM_#CACHE_ACL_OBJECT` t
  709. where t.`namespace` = '{$refNamespace}'
  710. "));
  711. return [
  712. 'back ref namespace' => UI::h('a', [
  713. 'class' => "btn btn-xs btn-link",
  714. 'href' => $thisGetLink('', [ 'namespace' => $refNamespace ])
  715. ], "{$refNamespace}"),
  716. // 'idInstance' => $backRef['idInstance'],
  717. // 'isInstalled' => $isInstalled,
  718. '@class' => ($isInstalled) ? "success" : "danger",
  719. ];
  720. }, ACL::getBackRefList($item['namespace'])),
  721. ]);
  722. UI::table([
  723. 'rows' => array_map(function ($field) use ($thisGetLink) {
  724. $refNs = str_replace(['__x3A__', ':'], '/', substr($field['xsdType'], strlen('ref:')));
  725. $refNamespace = ACL::getBaseNamespace($refNs);
  726. $isInstalled = (1 == DB::getPDO()->fetchValue("
  727. select t.isObjectActive
  728. from `CRM_#CACHE_ACL_OBJECT` t
  729. where t.`namespace` = '{$refNamespace}'
  730. "));
  731. $refSource = null;
  732. if ($isInstalled) {
  733. try {
  734. $refTable = ACL::getRefTable($field['objectNamespace'], $field['fieldNamespace']);
  735. DBG::log($refTable, 'array', "getRefTable('{$field['objectNamespace']}', '{$field['fieldNamespace']}')");
  736. $refSource = ACL::getRefSource($field['objectNamespace'], $field['fieldNamespace']);
  737. DBG::log($refSource, 'array', "ACL::getRefSource('{$field['objectNamespace']}', '{$field['fieldNamespace']}')");
  738. } catch (Exception $e) {
  739. DBG::log($e);
  740. }
  741. }
  742. $labelRefSource = [
  743. 'table' => "Tabela",
  744. 'view' => "Widok",
  745. 'backRef' => "BackRef",
  746. ];
  747. return [
  748. 'child ref name' => $field['fieldNamespace'],
  749. // 'xsdType' => $field['xsdType'], // always === "ref:{$field['fieldNamespace']}"
  750. 'ref object' => UI::h('a', [
  751. 'class' => "btn btn-xs btn-link",
  752. 'href' => $thisGetLink('', [ 'namespace' => $refNamespace ])
  753. ], "{$refNs}"),
  754. 'ref source' => UI::h('div', [],
  755. (null === $refSource)
  756. ? [ "ref object not installed" ] // TODO: link to install? is table struct
  757. : [
  758. // UI::hButtonAjax("Tabela ref", "setFieldRefConfig", [
  759. // 'class' => "btn btn-xs btn-default" . ( 'table' === $refSource ? ' disabled' : '' ),
  760. // 'href' => $thisGetLink('setFieldRefConfig'),
  761. // 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], 'do' => 'table' ]
  762. // ]),
  763. // UI::hButtonAjax("Widok (cache)", "setFieldRefConfig", [
  764. // 'title' => "Według flat_relation_cache",
  765. // 'class' => "btn btn-xs btn-default" . ( 'view' === $refSource ? ' disabled' : '' ),
  766. // 'href' => $thisGetLink('setFieldRefConfig'),
  767. // 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], 'do' => 'view' ]
  768. // ]),
  769. $labelRefSource[$refSource] . ' ',
  770. ('view' === $refSource)
  771. ? UI::hButtonPost("Zmień na tabelę", [
  772. 'title' => "Według wygenerowanej tabeli REF",
  773. 'class' => "btn btn-xs btn-default" . ( 'table' === $refSource ? ' disabled' : '' ),
  774. // 'href' => $thisGetLink('setFieldRefConfig'),
  775. 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], '_postTask' => 'setFieldRefConfig', 'source' => 'table' ]
  776. ])
  777. : '',
  778. ('table' === $refSource)
  779. ? UI::hButtonPost("Zmień na widok", [
  780. 'title' => "Według flat_relation_cache",
  781. 'class' => "btn btn-xs btn-default" . ( 'view' === $refSource ? ' disabled' : '' ),
  782. // 'href' => $thisGetLink('setFieldRefConfig'),
  783. 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], '_postTask' => 'setFieldRefConfig', 'source' => 'view' ]
  784. ])
  785. : '',
  786. ]
  787. ),
  788. '@class' => ($isInstalled) ? "success" : "danger",
  789. ]; // TODO: link to install object
  790. }, $refFields)
  791. ]);
  792. }
  793. $thisGetLink = [ $this, 'getLink' ];
  794. UI::table([
  795. '__html_id' => 'struct_table',
  796. 'caption' => UI::h('span', [], [
  797. UI::h('span', [ 'style' => "margin-right:6px;color:#000" ], "Struktura obiektu '{$item['namespace']}'"),
  798. UI::h('code', [ 'style' => "margin-right:6px;color:#000" ], "(PrimaryKey: " . ($item['primaryKey'] ? $item['primaryKey'] : "Brak" ) . ")"),
  799. ]),
  800. // 'sortBy' => [
  801. // 'method' => 'get',
  802. // 'argName' => '_sortBy',
  803. // 'allow' => ['sort', 'namespace'],
  804. // 'default' => ['namespace', 'asc'],
  805. // ],
  806. 'cols_label' => [
  807. 'sort' => UI::h('nobr', [
  808. 'class' => "ta-ordering" . ('sort' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  809. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'sort', '" . ('sort' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  810. 'title' => "Sortuj wg pola SORT_PRIO z zasobów",
  811. ], "sort"),
  812. 'namespace' => UI::h('nobr', [
  813. 'class' => "ta-ordering" . ('namespace' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  814. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'namespace', '" . ('namespace' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  815. 'title' => "Sortuj wg nazwy pola",
  816. ], "namespace"),
  817. ],
  818. 'rows' => array_map(function ($field) use ($item, $thisGetLink, $sortByCol) {
  819. $tblItem = [];
  820. if ('sort' === $sortByCol && null !== $field['SORT_PRIO'] && !empty($field['idZasob'])) {
  821. $tblItem['@class'] = "ta-sortable-item";
  822. $tblItem['@class[sort]'] = "ta-sortable-item-handle";
  823. $tblItem['@data']['sort_prio'] = $field['SORT_PRIO'];
  824. $tblItem['@data']['id_zasob'] = $field['idZasob'];
  825. $field['SORT_PRIO'] = ":: {$field['SORT_PRIO']}";
  826. }
  827. $tblItem['sort'] = V::get('SORT_PRIO', null, $field);
  828. foreach ($field as $k => $v) {
  829. if ('SORT_PRIO' === $k) continue;
  830. $tblItem[$k] = $v;
  831. }
  832. $tblItem['namespace'] = UI::h('span', [], [
  833. UI::h('span', ['style' => "color:#aaa"], substr($field['namespace'], 0, strlen($field['objectNamespace']) + 1)),
  834. UI::h('span', ['style' => "color:#000"], substr($field['namespace'], strlen($field['objectNamespace']) + 1)),
  835. ]);
  836. $tblItem['idZasob'] = ($field['idZasob'] > 0)
  837. ? $field['idZasob']
  838. : (
  839. ($item['idZasob'] > 0)
  840. ? UI::hButtonAjax("+ do zasobów", 'addFieldToZasobyAjax', [
  841. 'class' => "btn btn-xs btn-primary",
  842. 'href' => $thisGetLink('addFieldToZasobyAjax'),
  843. 'data' => [
  844. 'namespace' => $item['namespace'],
  845. 'fieldNamespace' => $field['namespace'],
  846. ]
  847. ])
  848. : UI::h('span', ['title'=>"Brak Nr zasobu dla obiektu", 'class'=>"btn btn-xs btn-danger"], "Brak nr zasobu obiektu")
  849. )
  850. ;
  851. unset($tblItem['objectNamespace']);
  852. unset($tblItem['fieldNamespace']);
  853. return $tblItem;
  854. }, array_filter($item['field'], function ($field) { return $field['isActive']; }))
  855. ]);
  856. $removedFields = array_filter($item['field'], function ($field) { return !$field['isActive']; });
  857. if (!empty($removedFields)) {
  858. echo UI::h('details', [ 'style' => "margin-bottom:12px; padding:6px; background-color:#dedede; color:#000" ], [
  859. UI::h('summary', [ 'style' => "padding:0 3px; outline:none; cursor:pointer" ], "Pola w koszu (".count($removedFields).")"),
  860. UI::h('table', [ 'style' => "margin:6px 0 0 0; background-color:#fff; font-size:x-small", 'class' => "table table-bordered table-hover table-condensed" ], [
  861. UI::h('thead', [], [
  862. UI::h('tr', [], [
  863. UI::h('th', [], "#"),
  864. UI::h('th', [], "namespace"),
  865. UI::h('th', [], "idZasob"),
  866. UI::h('th', [], "xsdType"),
  867. UI::h('th', [], "xsdRestrictions"),
  868. UI::h('th', [], "appInfo"),
  869. UI::h('th', [], "minOccurs"),
  870. UI::h('th', [], "maxOccurs"),
  871. UI::h('th', [], "isActive"),
  872. ]),
  873. ]),
  874. UI::h('tbody', [], array_map(function ($field) use ($item, $thisGetLink) {
  875. return UI::h('tr', [], [
  876. UI::h('td', [], [
  877. UI::hButtonAjax("usuń", 'removeFieldFromTrashAjax', [
  878. 'class' => "btn btn-xs btn-danger",
  879. 'href' => $thisGetLink('removeFieldFromTrashAjax'),
  880. 'data' => [
  881. 'namespace' => $item['namespace'],
  882. 'fieldNamespace' => $field['namespace'],
  883. ]
  884. ])
  885. ]),
  886. UI::h('td', [], $field['fieldNamespace']),
  887. UI::h('td', [], [
  888. ($field['idZasob'] > 0)
  889. ? UI::h('span', [ 'class' => 'text-danger', 'title' => "Zasób zostanie usunięty" ], "{$field['idZasob']}")
  890. : UI::h('span', [ 'class' => 'text-muted' ], "brak")
  891. ]),
  892. UI::h('td', [], $field['xsdType']),
  893. UI::h('td', [], $field['xsdRestrictions']),
  894. UI::h('td', [], $field['appInfo']),
  895. UI::h('td', [], $field['minOccurs']),
  896. UI::h('td', [], $field['maxOccurs']),
  897. UI::h('td', [], $field['isActive']),
  898. ]);
  899. }, $removedFields)),
  900. ]),
  901. ]);
  902. }
  903. UI::hButtonAjaxOnResponse('removeFieldFromTrashAjax', /* payload, n */ "
  904. if (!payload.type) return false
  905. jQuery.notify(payload.msg, payload.type)
  906. if ('success' == payload.type) {
  907. var trJqNode = jQuery(n).closest('tr')
  908. var tbodyJqNode = trJqNode.parent()
  909. var detailsJqNode = trJqNode.closest('details')
  910. trJqNode.remove()
  911. if (!tbodyJqNode.children().length) {
  912. detailsJqNode.remove()
  913. }
  914. }
  915. ");
  916. UI::hButtonAjaxOnResponse('addFieldToZasobyAjax', /* payload, n */ "
  917. if (!payload.type) return false
  918. if (payload.body && payload.body.id && payload.body.id > 0) { // if ('success' == payload.type) {
  919. n.parentNode.replaceChild(document.createTextNode(payload.body.id), n)
  920. }
  921. jQuery.notify(payload.msg, payload.type)
  922. ");
  923. UI::hButtonAjaxOnResponse('addAclObjectToZasobyAjax', /* payload, n */ "
  924. if (!payload.type) return false
  925. if ('success' === payload.type || 'info' === payload.type) {
  926. if (payload.body && payload.body.id && payload.body.id > 0) {
  927. n.parentNode.replaceChild(document.createTextNode(payload.body.id), n)
  928. } else {
  929. console.log('TODO: addAclObjectToZasobyAjax unknown response', payload);
  930. }
  931. window.location.reload()
  932. }
  933. ");
  934. UI::hButtonAjaxOnResponse('activateObjectAjax', /* payload, n */ "
  935. jQuery.notify(payload.msg, payload.type)
  936. if (!payload.type) return false
  937. if ('success' === payload.type || 'info' === payload.type) {
  938. if (payload.body && payload.body.isObjectActive && payload.body.isObjectActive > 0) {
  939. n.parentNode.replaceChild(document.createTextNode('Active'), n)
  940. } else {
  941. console.log('TODO: activateObjectAjax unknown response', payload);
  942. }
  943. }
  944. ");
  945. if ('sort' === $sortByCol) {
  946. echo UI::h('script', [], "
  947. jQuery(document).ready(function (){
  948. var tblNode$ = jQuery('#struct_table > tbody')
  949. var getOrder = function () {
  950. var orderIds = []
  951. jQuery('#struct_table > tbody').children('.ta-sortable-item').each(function (idx, trNode) {
  952. orderIds.push(jQuery(trNode).data('id_zasob'))
  953. })
  954. return orderIds
  955. }
  956. var sortOrder = getOrder()
  957. console.log('sortOrder - init', sortOrder)
  958. tblNode$.sortable({
  959. axis: 'y',
  960. handle: '.ta-sortable-item-handle',
  961. items: '.ta-sortable-item',
  962. update: function (event, ui) {
  963. sortOrder = getOrder()
  964. tblNode$.sortable('disable')
  965. tblNode$.find('.ta-sortable-item-handle').css({color:'silver'})
  966. console.log('TODO: disable sortable while ajax')
  967. // window.setTimeout(function () {
  968. // tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  969. // console.log('TODO: ajax fetch result')
  970. // tblNode$.sortable('enable')
  971. // tblNode$.sortable('cancel')
  972. // }, 1000)
  973. window.fetch(
  974. URI(window.location.href)
  975. .setSearch('_task', 'updateAntAclSortAjax')
  976. .setSearch('idZasobOrder', sortOrder)
  977. .build().toString(),
  978. {
  979. method: 'POST',
  980. headers: {
  981. 'Content-Type': 'application/x-www-form-urlencoded' // query string
  982. },
  983. credentials: 'same-origin',
  984. body: JSON.stringify({
  985. namespace: URI.parseQuery(window.location.search).namespace,
  986. sortBy: '{$sortByCol}',
  987. sortByDir: '{$sortByDir}',
  988. sortOrder: sortOrder,
  989. })
  990. }
  991. ).then(function(response) {
  992. return response.json()
  993. }).then(function(payload) {
  994. console.log('updateAntAclSortAjax response', payload);
  995. tblNode$.sortable('enable')
  996. if ('success' !== payload.type) {
  997. tblNode$.sortable('cancel')
  998. }
  999. tblNode$.sortable('enable')
  1000. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  1001. p5UI__notifyAjaxCallback({
  1002. type: payload.type || 'error',
  1003. msg: payload.msg || 'Request error'
  1004. });
  1005. if ('success' === payload.type) {
  1006. window.location.reload(true)
  1007. }
  1008. }).catch(function(e) {
  1009. tblNode$.sortable('enable')
  1010. tblNode$.sortable('cancel')
  1011. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  1012. p5UI__notifyAjaxCallback({
  1013. type: 'error',
  1014. msg: 'Request error ' + e
  1015. });
  1016. })
  1017. }
  1018. });
  1019. });
  1020. ");
  1021. }
  1022. if ($item['isObjectActive']) {
  1023. echo UI::hButtonAjax("Dodaj podstawowy proces dla obiektu '{$item['namespace']}' - read only (TODO)", 'addObjectBaseProcesAjax', [
  1024. 'class' => "btn btn-xs btn-default",
  1025. 'href' => Router::getRoute('Storage')->getLink('addObjectBaseProcesAjax'),
  1026. 'data' => [ 'namespace' => $item['namespace'] ]
  1027. ]);
  1028. UI::hButtonAjaxOnResponse('addObjectBaseProcesAjax', /* payload, n */ "
  1029. jQuery.notify(payload.msg, payload.type)
  1030. ");
  1031. }
  1032. DBG::nicePrint($item, '$item');
  1033. }
  1034. public function updateAntAclSortAjaxAction() {
  1035. return Response::sendTryCatchJson(array($this, 'updateAntAclSortAjax'), $args = 'JSON_FROM_REQUEST_BODY');
  1036. }
  1037. public function updateAntAclSortAjax($args) {
  1038. DBG::log($args, 'array', "args");
  1039. $namespace = V::get('namespace', '', $args);
  1040. if (empty($namespace)) throw new Exception("Missing param namespace");
  1041. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  1042. DBG::log($item, 'array', "\$item");
  1043. $sortByArgName = 'sortBy';
  1044. $sortByCol = V::get($sortByArgName, 'namespace', $args);
  1045. $sortByDir = V::get("{$sortByArgName}Dir", 'asc', $args);
  1046. if ('sort' !== $sortByCol) throw new Exception("Only sort by SORT_PRIO allowed to update");
  1047. if (!in_array($sortByDir, ['asc', 'desc'])) throw new Exception("Wrong order by dir arg");
  1048. if ('asc' !== $sortByDir) throw new Exception("Only sort asc is allowed"); // DBG
  1049. $sortPrioIdsFromZasoby = DB::getPDO()->fetchAll("
  1050. select z.ID, z.SORT_PRIO
  1051. from CRM_LISTA_ZASOBOW z
  1052. where z.PARENT_ID = :p_id
  1053. order by z.SORT_PRIO asc, z.ID asc -- default order in Zasoby tree
  1054. ", [
  1055. ':p_id' => $item['idZasob']
  1056. ]);
  1057. DBG::log($sortPrioIdsFromZasoby, 'array', "\$sortPrioIdsFromZasoby");
  1058. $idZasobCurrentOrder = array_map(function ($orderRow) {
  1059. return (int)$orderRow['ID'];
  1060. }, $sortPrioIdsFromZasoby);
  1061. DBG::log($idZasobCurrentOrder, 'array', "\$idZasobCurrentOrder");
  1062. DBG::log(array_diff_assoc($args['sortOrder'], $idZasobCurrentOrder), 'array', "array_diff_assoc(\$args['sortOrder'], \$idZasobCurrentOrder)");
  1063. DBG::log(array_diff_assoc($idZasobCurrentOrder, $args['sortOrder']), 'array', "array_diff_assoc(\$idZasobCurrentOrder, \$args['sortOrder'])");
  1064. $orderDiff = array_diff_assoc($args['sortOrder'], $idZasobCurrentOrder);
  1065. foreach ($orderDiff as $sortPrio => $idZasob) {
  1066. DB::getPDO()->update('CRM_LISTA_ZASOBOW', 'ID', $idZasob, [
  1067. 'SORT_PRIO' => $sortPrio,
  1068. ]);
  1069. }
  1070. return [
  1071. 'type' => 'success',
  1072. 'msg' => "OK",
  1073. 'DBG__args' => $args
  1074. ];
  1075. }
  1076. public function removeFieldFromTrashAjaxAction() {
  1077. DBG::log($_REQUEST, 'array', '$_REQUEST');
  1078. Response::sendTryCatchJson(array($this, 'removeFieldFromTrashAjax'), $_REQUEST);
  1079. }
  1080. public function removeFieldFromTrashAjax($args) {
  1081. $namespace = V::get('namespace', '', $args);
  1082. if (empty($namespace)) throw new HttpException("Missing namespace");
  1083. $fieldNamespace = V::get('fieldNamespace', '', $args);
  1084. if (empty($fieldNamespace)) throw new HttpException("Missing fieldNamespace");
  1085. $fieldItem = SchemaFactory::loadDefaultObject('SystemObjectField')->getItem($fieldNamespace);
  1086. if (!$fieldItem) throw new HttpException("Field not found '{$fieldNamespace}'", 404);
  1087. DBG::log($fieldItem, 'array', "\$fieldItem");
  1088. if ('p5:enum' === $fieldItem['xsdType']) {
  1089. // DBG::log(DB::getPDO()->fetchAll("
  1090. // select e.*
  1091. // from `CRM_#CACHE_ACL_OBJECT_FIELD_enum` e
  1092. // where e.objectNamespace = :objectNamespace
  1093. // and e.fieldNamespace = :fieldNamespace
  1094. // ", [
  1095. // ':objectNamespace' => $fieldItem['objectNamespace'],
  1096. // ':fieldNamespace' => $fieldItem['fieldNamespace'],
  1097. // ]), 'array', "enum values");
  1098. DB::getPDO()->execSql("
  1099. DELETE from `CRM_#CACHE_ACL_OBJECT_FIELD_enum`
  1100. where objectNamespace = :objectNamespace
  1101. and fieldNamespace = :fieldNamespace
  1102. and isActive = 0
  1103. ", [
  1104. ':objectNamespace' => $fieldItem['objectNamespace'],
  1105. ':fieldNamespace' => $fieldItem['fieldNamespace'],
  1106. ]);
  1107. }
  1108. DB::getPDO()->execSql("
  1109. DELETE from `CRM_#CACHE_ACL_OBJECT_FIELD`
  1110. where namespace = :namespace
  1111. and objectNamespace = :objectNamespace
  1112. and _rootTableName = :rootTableName
  1113. and isActive = 0
  1114. limit 1
  1115. ", [
  1116. 'namespace' => $fieldItem['namespace'],
  1117. 'objectNamespace' => $fieldItem['objectNamespace'],
  1118. 'rootTableName' => $fieldItem['_rootTableName'],
  1119. ]);
  1120. if ($fieldItem['idZasob'] > 0) {
  1121. $zasob = DB::getPDO()->fetchFirst(" select z.ID, z.A_STATUS, z.DESC from CRM_LISTA_ZASOBOW z where z.ID = :id ", [ ':id' => $fieldItem['idZasob'] ]);
  1122. if ($zasob) {
  1123. if ('DELETED' !== $zasob['A_STATUS']) {
  1124. $affected = DB::getPDO()->update('CRM_LISTA_ZASOBOW', 'ID', $zasob['ID'], [
  1125. 'A_STATUS' => 'DELETED',
  1126. 'A_RECORD_UPDATE_DATE' => 'NOW()',
  1127. 'A_RECORD_UPDATE_AUTHOR' => User::getLogin(),
  1128. ]);
  1129. if ($affected) {
  1130. DB::getPDO()->insert('CRM_LISTA_ZASOBOW_HIST', [
  1131. 'ID_USERS2' => $zasob['ID'],
  1132. 'A_STATUS' => 'DELETED',
  1133. 'A_RECORD_CREATE_DATE' => 'NOW()',
  1134. 'A_RECORD_CREATE_AUTHOR' => User::getLogin(),
  1135. ]);
  1136. }
  1137. }
  1138. }
  1139. $wskazniki = DB::getPDO()->fetchAll("
  1140. select w.ID, w.A_STATUS
  1141. from CRM_WSKAZNIK w
  1142. where w.ID_ZASOB = :id
  1143. ", [ ':id' => $fieldItem['idZasob'] ]);
  1144. if (!empty($wskazniki)) {
  1145. foreach ($wskazniki as $wsk) {
  1146. if ('DELETED' !== $wsk['A_STATUS']) {
  1147. $affected = DB::getPDO()->update('CRM_WSKAZNIK', 'ID', $wsk['ID'], [
  1148. 'A_STATUS' => 'DELETED',
  1149. 'A_RECORD_UPDATE_DATE' => 'NOW()',
  1150. 'A_RECORD_UPDATE_AUTHOR' => User::getLogin(),
  1151. ]);
  1152. if ($affected) {
  1153. DB::getPDO()->insert('CRM_WSKAZNIK_HIST', [
  1154. 'ID_USERS2' => $wsk['ID'],
  1155. 'A_STATUS' => 'DELETED',
  1156. 'A_RECORD_CREATE_DATE' => 'NOW()',
  1157. 'A_RECORD_CREATE_AUTHOR' => User::getLogin(),
  1158. ]);
  1159. }
  1160. }
  1161. }
  1162. }
  1163. }
  1164. return [
  1165. 'type' => "success",
  1166. 'msg' => "Usunięto pole {$fieldItem['fieldNamespace']}",
  1167. ];
  1168. }
  1169. public function addFieldToZasobyAjaxAction() {
  1170. DBG::log($_REQUEST, 'array', '$_REQUEST');
  1171. Response::sendTryCatchJson(array($this, 'addFieldToZasobyAjax'), $_REQUEST);
  1172. }
  1173. public function addFieldToZasobyAjax($args) {
  1174. $namespace = V::get('namespace', '', $args);
  1175. if (empty($namespace)) throw new HttpException("Missing namespace");
  1176. $fieldNamespace = V::get('fieldNamespace', '', $args);
  1177. if (empty($fieldNamespace)) throw new HttpException("Missing fieldNamespace");
  1178. $fieldItem = SchemaFactory::loadDefaultObject('SystemObjectField')->getItem($fieldNamespace);
  1179. if (!$fieldItem) throw new HttpException("Field not found '{$fieldNamespace}'", 404);
  1180. DBG::log($fieldItem, 'array', "\$fieldItem");
  1181. if ($fieldItem['idZasob'] > 0) throw (new AlertSuccessException("Field already added to Zasoby '{$fieldItem['idZasob']}'"))->setBody([ 'id' => $fieldItem['idZasob'] ]);
  1182. $objectItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace);
  1183. if (!$objectItem) throw new HttpException("Object not found '{$namespace}'", 404);
  1184. DBG::log($objectItem, 'array', "\$objectItem");
  1185. if (!$objectItem['idZasob']) throw new Exception("Missing Object idZasob");
  1186. $zasobItem = DB::getPDO()->fetchFirst("
  1187. select zField.ID, zField.`DESC`, zField.`TYPE`, zField.PARENT_ID
  1188. from CRM_LISTA_ZASOBOW as zField
  1189. join CRM_LISTA_ZASOBOW as zTable on(zTable.ID = zField.PARENT_ID)
  1190. where zTable.`ID` = '{$objectItem['idZasob']}'
  1191. and zTable.`TYPE` = 'TABELA'
  1192. and zField.`DESC` = '{$fieldItem['fieldNamespace']}'
  1193. and zField.`TYPE` = 'KOMORKA'
  1194. ");
  1195. if ($zasobItem) {
  1196. SchemaFactory::loadDefaultObject('SystemObjectField')->updateItem([
  1197. 'namespace' => $fieldItem['namespace'],
  1198. 'idZasob' => $zasobItem['ID']
  1199. ]);
  1200. throw (new AlertSuccessException("Zasob już istnieje"))->setBody([ 'id' => $zasobItem['ID'] ]);
  1201. }
  1202. $newFieldItem = [
  1203. 'PARENT_ID' => $objectItem['idZasob'],
  1204. 'TYPE' => 'KOMORKA',
  1205. 'DESC' => $fieldItem['fieldNamespace'],
  1206. 'DESC_PL' => $fieldItem['fieldNamespace'],
  1207. ];
  1208. DBG::log($newFieldItem, 'array', "add new field item");
  1209. try {
  1210. $acl = User::getAcl()->getObjectAcl('default_db', 'crm_lista_zasobow');
  1211. } catch (Exception $e) {
  1212. throw new Exception("Brak dostępu do tabeli Zasoby");
  1213. }
  1214. $createdId = $acl->addItem($newFieldItem);
  1215. if (!$createdId) throw new Exception("Nie udało się utworzyć nowego rekordu!");
  1216. SchemaFactory::loadDefaultObject('SystemObjectField')->updateItem([
  1217. 'namespace' => $fieldItem['namespace'],
  1218. 'idZasob' => $createdId
  1219. ]);
  1220. throw (new AlertSuccessException("Utworzono pomyślnie rekord nr {$createdId}"))->setBody([ 'id' => $createdId ]);
  1221. }
  1222. }