AclStruct.php 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127
  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. UI::table([
  196. '__html_id' => 'struct_table',
  197. 'caption' => UI::h('span', [], [
  198. "Struktura tabeli {$tblName} [{$idTable}] ",
  199. UI::h('a', [
  200. 'href' => "index.php?_route=ViewTableAjax&namespace=default_db/{$tblName}",
  201. 'class' => "btn btn-md btn-link"
  202. ], "Przeglądaj tabelę"),
  203. UI::h('a', [
  204. 'href' => "procesy5.php?task=CRM_LISTA_ZASOBOW&filtr_id={$idTable}&filtr_ids=%2B&filtr_ob=%2B",
  205. 'class' => "btn btn-md btn-link",
  206. 'title' => "Struktura aktualnie przeglądanej tabeli"
  207. ], "Zasoby"),
  208. UI::h('a', [
  209. 'href' => "index.php?FUNCTION_INIT=PROCES_MENU&HEADER_NOT_INIT=YES&_task=PROCES_FOR_TABLE&tblId={$idTable}",
  210. 'class' => "btn btn-md btn-link",
  211. 'title' => "Procesy dla aktualnie przeglądanej tabeli"
  212. ], "Procesy"),
  213. UI::h('a', [
  214. 'href' => Router::getRoute('Storage_AclUsage')->getLink('', [ 'namespace' => "default_db/{$tblName}" ]),
  215. 'class' => "btn btn-md btn-link",
  216. 'title' => "Uprawnienia - analiza użycia komórek w procesach"
  217. ], "Uprawnienia (analiza użycia)"),
  218. UI::h('a', [
  219. 'href' => Router::getRoute('Storage_TestXsd')->getLink('tableXsd', [ 'idStorage' => $idStorage, 'table' => "{$tblName}" ]),
  220. 'class' => "btn btn-md btn-link",
  221. ], "xsd"),
  222. ]),
  223. 'cols_label' => [
  224. 'sort' => UI::h('nobr', [
  225. 'class' => "ta-ordering" . ('sort' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  226. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'sort', '" . ('sort' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  227. 'title' => "Sortuj wg pola SORT_PRIO z zasobów",
  228. ], "sort"),
  229. 'name' => UI::h('nobr', [
  230. 'class' => "ta-ordering" . ('name' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  231. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'name', '" . ('name' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  232. 'title' => "Sortuj wg nazwy",
  233. ], "namespace"),
  234. ],
  235. 'cols' => array_keys($emptyItem),
  236. 'rows' => array_map(function ($item) use ($sortByCol) {
  237. if ('sort' === $sortByCol && null !== $item['sort'] && !empty($item['id_zasob'])) {
  238. $item['@class'] = "ta-sortable-item";
  239. $item['@class[sort]'] = "ta-sortable-item-handle";
  240. $item['@data']['sort_prio'] = $item['sort'];
  241. $item['@data']['id_zasob'] = $item['id_zasob'];
  242. $item['sort'] = ":: {$item['sort']}";
  243. }
  244. return $item;
  245. }, $tableList),
  246. ]);
  247. echo UI::h('script', [], "
  248. jQuery(document).on('p5UIBtnAjax:Storage:addCellToZasoby:click', function(e, n, payload) {
  249. console.log('event p5UIBtnAjax:Storage:addCellToZasoby:click', n, payload);
  250. });
  251. jQuery(document).on('p5UIBtnAjax:Storage:addCellToZasoby:ajaxLoaded', function(e, n, payload) {
  252. console.log('event p5UIBtnAjax:Storage:addCellToZasoby:ajaxLoaded', n, payload);
  253. if ('success' == payload.type && payload.body && payload.body.id > 0) {
  254. var cellUwagiJQNode = jQuery(n).parents('td').next('td');
  255. cellUwagiJQNode.text(cellUwagiJQNode.text().replace('!Zasob', ''))
  256. jQuery(n).parents('td').text(payload.body.id);
  257. jQuery(n).remove();
  258. }
  259. jQuery.notify(payload.msg, payload.type);
  260. });
  261. ");
  262. $ajaxAddZasobLink = Router::getRoute('Storage')->getLink('addGeomEtykietaCells', [ 'idStorage' => $idStorage, 'tblName' => $tblName]);
  263. $onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addGeomEtykietaCells', { href: '{$ajaxAddZasobLink}' })";
  264. UI::tag('a', ['onclick'=>$onClick, 'class'=>"btn btn-xs btn-default", 'href'=>"#"], "Dodaj komórki etykiet", true);
  265. echo "<i>(<code>`etykieta_x`</code>, <code>`etykieta_y`</code>, <code>`etykieta_obrot`</code>)</i>";
  266. echo UI::h('script', [], "
  267. jQuery(document).on('p5UIBtnAjax:Storage:addGeomEtykietaCells:ajaxLoaded', function(e, n, payload) {
  268. console.log('event p5UIBtnAjax:Storage:addGeomEtykietaCells:ajaxLoaded', n, payload);
  269. if ('success' == payload.type && payload.body && payload.body.id > 0) {
  270. var cellUwagiJQNode = jQuery(n).parents('td').next('td');
  271. cellUwagiJQNode.text(cellUwagiJQNode.text().replace('!Zasob', ''))
  272. jQuery(n).parents('td').text(payload.body.id);
  273. jQuery(n).remove();
  274. }
  275. jQuery.notify(payload.msg, payload.type);
  276. });
  277. ");
  278. $tableActions = array_filter($cellZasobList, function ($row) {
  279. return ('URL_ACTION' == $row['ZASOB_TYPE']);
  280. });
  281. UI::table([
  282. 'caption' => "tableActions",
  283. // 'cols' => array_keys($emptyItem),
  284. 'rows' => array_map(function ($item) {
  285. $sqlIdAction = DB::getPDO()->quote($item['ID'], PDO::PARAM_INT);
  286. $args = DB::getPDO()->fetchAll("
  287. select z.`DESC`
  288. , a.ID as ALIAS_ID, a.`DESC` as ALIAS_DESC, a.OPIS as ALIAS_OPIS
  289. from CRM_LISTA_ZASOBOW z
  290. left join CRM_LISTA_ZASOBOW a on(a.ID = z.ALIAS_ID)
  291. where z.PARENT_ID = {$sqlIdAction}
  292. and z.`TYPE` = 'PARAM_IN'
  293. ");
  294. $definitionArgs = DB::getPDO()->fetchAll("
  295. select p.ID, p.`DESC`
  296. from CRM_LISTA_ZASOBOW z
  297. join CRM_LISTA_ZASOBOW d on(d.ID = z.ALIAS_ID)
  298. left join CRM_LISTA_ZASOBOW p on(p.PARENT_ID = d.ID)
  299. where z.ID = {$sqlIdAction}
  300. and p.`TYPE` = 'PARAM_IN'
  301. ");
  302. $flatDefinitionArgs = implode(";", array_map(function ($arg) {
  303. return "{$arg['ID']}={$arg['DESC']}";
  304. }, $definitionArgs));
  305. return [
  306. 'label' => DB::getPDO()->fetchValue(" select z.OPIS from CRM_LISTA_ZASOBOW z where z.ID = {$sqlIdAction} ") . " " .
  307. UI::h('i', [
  308. 'class' => "glyphicon glyphicon-pencil",
  309. 'style' => "cursor:pointer",
  310. 'onClick' => "return Storage__tableStruct__editActionLabel(this, {$sqlIdAction})"], ''),
  311. 'args' => implode("<br>&", array_map(function ($item) {
  312. return (NULL === $item['ALIAS_ID'])
  313. ? $item['DESC']
  314. : "{$item['DESC']}=" . '{$row["' . $item['ALIAS_DESC'] . '"]}';// TODO: add rmParam btn
  315. }, $args)) . " " .
  316. UI::h('i', [
  317. 'class' => "glyphicon glyphicon-plus-sign",
  318. 'style' => "cursor:pointer",
  319. 'title' => "Dodaj PARAM_IN",
  320. 'onClick' => "return Storage__tableStruct__addParamAction(this, {$sqlIdAction}, '{$flatDefinitionArgs}')"], ''),
  321. // 'args_info' => '<pre>' . var_export($args, true) . '</pre>',
  322. 'ID' => $item['ID'],
  323. 'DESC' => $item['DESC'],
  324. 'A_STATUS' => $item['A_STATUS'],
  325. 'definition args' => implode("", array_map(function ($item) {
  326. return '<div style="white-space:nowrap">' . "[{$item['ID']}] {$item['DESC']}" . '</div>';
  327. }, $definitionArgs)),
  328. ];
  329. }, $tableActions)
  330. ]);
  331. echo UI::h('button', [
  332. 'onClick'=>"Storage__tableStruct__addAction()",
  333. 'class'=>"btn btn-xs btn-default"
  334. ], "Dodaj Akcję");
  335. echo UI::h('link', ['rel'=>"stylesheet", 'type'=>"text/css", 'href'=>"static/sweetalert2.min.css"]);
  336. echo UI::h('script', ['src'=>"static/sweetalert2.min.js"]);
  337. echo UI::h('style', [], "
  338. .swal2-radio.p5-swal-radio-as-list { text-align:left }
  339. .swal2-radio.p5-swal-radio-as-list > label { display:block; margin-left:20px }
  340. ");
  341. UI::inlineJS(__FILE__ . '.tableActions.js', [
  342. 'ID_STORAGE' => $idStorage,
  343. 'TABLE_NAME' => $tblName,
  344. 'FETCH_URL' => Router::getRoute('Storage')->getLink('fetchActionListAjax'),
  345. 'ADD_ACTION_URL' => Router::getRoute('Storage')->getLink('addActionAjax')
  346. ]);
  347. echo '<hr>';
  348. $ajaxAddBaseProcesLink = Router::getRoute('Storage')->getLink('addTableBaseProces', [ 'idStorage' => $idStorage, 'tblName' => $tblName ]);
  349. $onClick = "return p5UI__ButtonAjax(this, 'p5UIBtnAjax:Storage:addTableBaseProces', { href: '{$ajaxAddBaseProcesLink}' })";
  350. UI::tag('a', ['onclick'=>$onClick, 'class'=>"btn btn-xs btn-default", 'href'=>"#"], "Dodaj podstawowy proces dla tabeli '{$tblName}' - read only", true);
  351. echo UI::h('script', [], "
  352. jQuery(document).on('p5UIBtnAjax:Storage:addTableBaseProces:ajaxLoaded', function(e, n, payload) {
  353. jQuery.notify(payload.msg, payload.type);
  354. });
  355. ");
  356. if ('sort' === $sortByCol) {
  357. echo UI::h('script', [], "
  358. jQuery(document).ready(function (){
  359. var tblNode$ = jQuery('#struct_table > tbody')
  360. var getOrder = function () {
  361. var orderIds = []
  362. jQuery('#struct_table > tbody').children('.ta-sortable-item').each(function (idx, trNode) {
  363. orderIds.push(jQuery(trNode).data('id_zasob'))
  364. })
  365. return orderIds
  366. }
  367. var sortOrder = getOrder()
  368. console.log('sortOrder - init', sortOrder)
  369. tblNode$.sortable({
  370. axis: 'y',
  371. handle: '.ta-sortable-item-handle',
  372. items: '.ta-sortable-item',
  373. update: function (event, ui) {
  374. sortOrder = getOrder()
  375. tblNode$.sortable('disable')
  376. tblNode$.find('.ta-sortable-item-handle').css({color:'silver'})
  377. console.log('TODO: disable sortable while ajax')
  378. // window.setTimeout(function () {
  379. // tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  380. // console.log('TODO: ajax fetch result')
  381. // tblNode$.sortable('enable')
  382. // tblNode$.sortable('cancel')
  383. // }, 1000)
  384. window.fetch(
  385. URI(window.location.href)
  386. .setSearch('_task', 'updateAntAclSortAjax')
  387. .setSearch('idZasobOrder', sortOrder)
  388. .build().toString(),
  389. {
  390. method: 'POST',
  391. headers: {
  392. 'Content-Type': 'application/x-www-form-urlencoded' // query string
  393. },
  394. credentials: 'same-origin',
  395. body: JSON.stringify({
  396. namespace: URI.parseQuery(window.location.search).namespace,
  397. sortBy: '{$sortByCol}',
  398. sortByDir: '{$sortByDir}',
  399. sortOrder: sortOrder,
  400. })
  401. }
  402. ).then(function(response) {
  403. return response.json()
  404. }).then(function(payload) {
  405. console.log('updateAntAclSortAjax response', payload);
  406. tblNode$.sortable('enable')
  407. if ('success' !== payload.type) {
  408. tblNode$.sortable('cancel')
  409. }
  410. tblNode$.sortable('enable')
  411. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  412. p5UI__notifyAjaxCallback({
  413. type: payload.type || 'error',
  414. msg: payload.msg || 'Request error'
  415. });
  416. if ('success' === payload.type) {
  417. window.location.reload(true)
  418. }
  419. }).catch(function(e) {
  420. tblNode$.sortable('enable')
  421. tblNode$.sortable('cancel')
  422. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  423. p5UI__notifyAjaxCallback({
  424. type: 'error',
  425. msg: 'Request error ' + e
  426. });
  427. })
  428. }
  429. });
  430. });
  431. ");
  432. }
  433. }
  434. public function objectStructView($item) {
  435. $namespace = $item['namespace'];
  436. { // sortBy
  437. $sortByArgName = 'sortBy';
  438. $sortByCol = V::get($sortByArgName, 'namespace', $_GET);
  439. $sortByDir = V::get("{$sortByArgName}Dir", 'asc', $_GET);
  440. { // add SORT_PRIO
  441. $item['field'] = array_map(function ($field) {
  442. $field['SORT_PRIO'] = ($field['idZasob'] > 0)
  443. ? DB::getPDO()->fetchValue("
  444. select z.SORT_PRIO
  445. from CRM_LISTA_ZASOBOW z
  446. where z.ID = :id
  447. ", [ ':id' => $field['idZasob'] ])
  448. : null
  449. ;
  450. return $field;
  451. }, $item['field']);
  452. }
  453. if ('namespace' === $sortByCol) {
  454. usort($item['field'], function ($a, $b) use ($sortByDir) {
  455. if ($a['fieldNamespace'] > $b['fieldNamespace']) return 'asc' === $sortByDir ? 1 : -1;
  456. if ($a['fieldNamespace'] < $b['fieldNamespace']) return 'asc' === $sortByDir ? -1 : 1;
  457. return 0;
  458. });
  459. }
  460. else if ('sort' === $sortByCol) {
  461. usort($item['field'], function ($a, $b) use ($sortByDir) {
  462. if (null === $a['SORT_PRIO'] && null === $b['SORT_PRIO']) return 0;
  463. if (null === $a['SORT_PRIO'] && null != $b['SORT_PRIO']) return 1;
  464. if (null !== $a['SORT_PRIO'] && null === $b['SORT_PRIO']) return -1;
  465. if ($a['SORT_PRIO'] > $b['SORT_PRIO']) return 'asc' === $sortByDir ? 1 : -1;
  466. if ($a['SORT_PRIO'] < $b['SORT_PRIO']) return 'asc' === $sortByDir ? -1 : 1;
  467. return 0;
  468. });
  469. }
  470. echo UI::h('style', [ 'type' => "text/css" ], "
  471. .ta-ordering { cursor:pointer }
  472. .ta-ordering-desc:after { content:\"\\e252\"; font-family:\"Glyphicons Halflings\"; line-height:1; margin:0 0 0 3px; display:inline-block; color:#bbb }
  473. .ta-ordering-asc:after { content:\"\\e253\"; font-family:\"Glyphicons Halflings\"; line-height:1; margin:0 0 0 3px; display:inline-block; color:#bbb }
  474. .ta-sortable-item { }
  475. .ta-sortable-item-handle { cursor:pointer }
  476. ");
  477. echo UI::h('script', [ 'src' => "static/URI.js" ]);
  478. echo UI::h('script', [], "
  479. function p5UI_table_sortBy_get(n, argName, colName, dir) {
  480. var newUri = URI(window.location.href).setQuery(argName, colName).setQuery(argName+'Dir', dir).build().toString();
  481. window.location.href = newUri
  482. }
  483. ");
  484. }
  485. if ('setFieldRefConfig' === V::get('_postTask', '', $_POST)) {
  486. $field = V::get('field', '', $_POST);
  487. $source = V::get('source', '', $_POST);
  488. switch ($source) {
  489. case 'view':
  490. $refSelect = ACL::generateRefSelectSqlByFlatRelationCache($namespace, $field);
  491. ACL::setRefSource($namespace, $field, 'view', $refSelect);
  492. break;
  493. case 'table': ACL::setRefSource($namespace, $field, 'table'); break;
  494. }
  495. }
  496. if ('preview' === V::get('_postTask', '', $_POST)) {
  497. try {
  498. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  499. $localFields = array_filter($item['field'], function ($field) {
  500. return $field['isLocal'];
  501. });
  502. $refFields = array_filter($item['field'], function ($field) {
  503. return 'ref:' === substr($field['xsdType'], 0, 4);
  504. });
  505. $activeRefFields = array_filter($refFields, function ($field) {
  506. $refNamespace = str_replace(['__x3A__', ':'], '/', substr($field['xsdType'], strlen('ref:')));
  507. return (1 == DB::getPDO()->fetchValue("
  508. select t.isObjectActive
  509. from `CRM_#CACHE_ACL_OBJECT` t
  510. where t.`namespace` = '{$refNamespace}'
  511. "));
  512. });
  513. $previewItems = ACL::getAclByNamespace($namespace)->buildQuery([])->getItems([
  514. 'limit' => 5
  515. ]);
  516. DBG::nicePrint($previewItems, 'items (default query) - preview (limit 5)');
  517. $query = [ 'cols' => array_merge(
  518. array_map(
  519. function ($field) {
  520. return $field['fieldNamespace'];
  521. }, $localFields
  522. ),
  523. array_map(
  524. function ($field) {
  525. return "{$field['fieldNamespace']}/*";
  526. }, $activeRefFields
  527. )
  528. ) ];
  529. DBG::nicePrint($query, 'items with ref/* - query');
  530. $previewItems = ACL::getAclByNamespace($namespace)->buildQuery($query)->getItems([
  531. 'limit' => 5
  532. ]);
  533. DBG::nicePrint($previewItems, 'items with ref/* - preview (limit 5)');
  534. $query = [ 'cols' => array_merge(
  535. array_map(
  536. function ($field) {
  537. return $field['fieldNamespace'];
  538. }, $localFields
  539. ),
  540. array_map(
  541. function ($field) {
  542. return "{$field['fieldNamespace']}";
  543. }, $activeRefFields
  544. )
  545. ) ];
  546. DBG::nicePrint($query, 'items with ref as xlink - query');
  547. $previewItems = ACL::getAclByNamespace($namespace)->buildQuery($query)->getItems([
  548. 'limit' => 5
  549. ]);
  550. DBG::nicePrint($previewItems, 'items with ref as xlink - preview (limit 5)');
  551. } catch (Exception $e) {
  552. DBG::log($e);
  553. UI::alert('danger', $e->getMessage());
  554. }
  555. }
  556. echo UI::h('details', ['style'=>"margin-bottom:24px; padding:0 10px; background-color:#eee", 'open' => "open"], [
  557. UI::h('summary', ['style'=>"font-size:1.4em; line-height:2em; cursor:pointer; outline:none"], [
  558. "Struktura obiektu '{$namespace}' ",
  559. // UI::h('small', ['style'=>"font-size:0.8em; font-style:italic; color:#aaa"], " więcej...")
  560. ]),
  561. UI::h('div', ['style'=>"padding:4px 24px; border-top:1px solid #fff"], [
  562. UI::h('span', ['style'=>"margin-right:12px"], [
  563. ( ($item['idZasob'] > 0)
  564. ? UI::h('span', [ 'title' => "Nr zasobu '{$item['idZasob']}'" ], "Nr zasobu [{$item['idZasob']}]")
  565. : UI::h('span', [ 'title' => "Brak nr zasobu - dodaj do zasobów" ], [
  566. UI::hButtonAjax("+ do zasobów", 'addAclObjectToZasobyAjax', [
  567. 'class' => "btn btn-xs btn-primary",
  568. 'href' => Router::getRoute('Storage')->getLink('addAclObjectToZasobyAjax'),
  569. 'data' => [
  570. 'idStorage' => $item['idDatabase'],
  571. 'namespace' => $item['namespace'],
  572. ]
  573. ])
  574. ])
  575. ),
  576. ]),
  577. UI::h('span', ['style'=>"margin:0 12px"], [
  578. ( ($item['isObjectActive'] > 0)
  579. ? UI::h('span', [ 'class' => "label label-success", 'title' => "Namespace active" ], "Active")
  580. : UI::h('span', [ 'title' => "Namespace not active" ], [
  581. ($item['idZasob'] > 0)
  582. ? UI::hButtonAjax("Aktywuj", 'activateObjectAjax', [
  583. 'class' => "btn btn-xs btn-primary",
  584. 'href' => Router::getRoute('Storage')->getLink('activateObjectAjax'),
  585. 'data' => [
  586. 'namespace' => $item['namespace'],
  587. ]
  588. ])
  589. : '',
  590. ])
  591. ),
  592. ]),
  593. UI::h('a', [
  594. 'href' => "index.php?_route=ViewTableAjax&namespace={$item['namespace']}",
  595. 'class' => "btn btn-sm btn-link"
  596. ], "Przeglądaj tabelę"),
  597. ( ($item['idZasob'] > 0)
  598. ? UI::h('a', [
  599. 'href' => "procesy5.php?task=CRM_LISTA_ZASOBOW&filtr_id={$item['idZasob']}&filtr_ids=%2B&filtr_ob=%2B",
  600. 'class' => "btn btn-sm btn-link",
  601. 'title' => "Struktura tabeli w drzewie zasobów"
  602. ], "Zasoby")
  603. : ''
  604. ),
  605. ( ($item['idZasob'] > 0)
  606. ? UI::h('a', [
  607. 'href' => "index.php?FUNCTION_INIT=PROCES_MENU&HEADER_NOT_INIT=YES&_task=PROCES_FOR_TABLE&tblId={$item['idZasob']}",
  608. 'class' => "btn btn-sm btn-link",
  609. 'title' => "Procesy dla aktualnie przeglądanej tabeli"
  610. ], "Procesy")
  611. : ''
  612. ),
  613. UI::h('a', [
  614. 'href' => Router::getRoute('Storage_AclReinstall')->getLink('', ['namespace' => $item['namespace']]),
  615. 'class' => 'btn btn-sm btn-link', 'style' => "color:#f00",
  616. 'title' => "Zainstaluje ponownie obiekt"
  617. ], "reinstall object"),
  618. UI::h('a', [
  619. 'href' => Router::getRoute('Storage_AclUsage')->getLink('', [ 'namespace' => $item['namespace'] ]),
  620. 'class' => "btn btn-sm btn-link",
  621. 'title' => "Uprawnienia - analiza użycia komórek w procesach"
  622. ], "Uprawnienia (analiza użycia)"),
  623. UI::hButtonPost("(podgląd z relacjami)", [
  624. 'data' => [
  625. '_postTask' => 'preview'
  626. ],
  627. 'class' => 'btn btn-sm btn-link', 'style' => "font-style:italic",
  628. 'title' => "Podgląd kilku ostatnich obiektów wraz z relacjami"
  629. ]),
  630. ])
  631. ]);
  632. $thisGetLink = [ $this, 'getLink' ];
  633. { // not installed ref
  634. $refFields = array_filter($item['field'], function ($field) {
  635. return ('ref:' === substr($field['xsdType'], 0, 4) && $field['isActive']);
  636. });
  637. echo UI::h('h3', [], "Obiekty powiązane");
  638. UI::table([
  639. 'rows' => array_map(function ($backRef) use ($thisGetLink) {
  640. $refNamespace = $backRef['namespace'];
  641. $isInstalled = (1 == DB::getPDO()->fetchValue("
  642. select t.isObjectActive
  643. from `CRM_#CACHE_ACL_OBJECT` t
  644. where t.`namespace` = '{$refNamespace}'
  645. "));
  646. return [
  647. 'back ref namespace' => UI::h('a', [
  648. 'class' => "btn btn-xs btn-link",
  649. 'href' => $thisGetLink('', [ 'namespace' => $refNamespace ])
  650. ], "{$refNamespace}"),
  651. // 'idInstance' => $backRef['idInstance'],
  652. // 'isInstalled' => $isInstalled,
  653. '@class' => ($isInstalled) ? "success" : "danger",
  654. ];
  655. }, ACL::getBackRefList($item['namespace'])),
  656. ]);
  657. UI::table([
  658. 'rows' => array_map(function ($field) use ($thisGetLink) {
  659. $refNamespace = str_replace(['__x3A__', ':'], '/', substr($field['xsdType'], strlen('ref:')));
  660. $isInstalled = (1 == DB::getPDO()->fetchValue("
  661. select t.isObjectActive
  662. from `CRM_#CACHE_ACL_OBJECT` t
  663. where t.`namespace` = '{$refNamespace}'
  664. "));
  665. $refSource = null;
  666. if ($isInstalled) {
  667. try {
  668. $refTable = ACL::getRefTable($field['objectNamespace'], $field['fieldNamespace']);
  669. DBG::log($refTable, 'array', "getRefTable('{$field['objectNamespace']}', '{$field['fieldNamespace']}')");
  670. $refSource = ACL::getRefSource($field['objectNamespace'], $field['fieldNamespace']);
  671. DBG::log($refSource, 'array', "ACL::getRefSource('{$field['objectNamespace']}', '{$field['fieldNamespace']}')");
  672. } catch (Exception $e) {
  673. DBG::log($e);
  674. }
  675. }
  676. return [
  677. 'child ref name' => $field['fieldNamespace'],
  678. // 'xsdType' => $field['xsdType'], // always === "ref:{$field['fieldNamespace']}"
  679. 'ref object' => UI::h('a', [
  680. 'class' => "btn btn-xs btn-link",
  681. 'href' => $thisGetLink('', [ 'namespace' => $refNamespace ])
  682. ], "{$refNamespace}"),
  683. 'ref source' => UI::h('div', [],
  684. (null === $refSource)
  685. ? [ "ref object not installed" ] // TODO: link to install? is table struct
  686. : [
  687. // UI::hButtonAjax("Tabela ref", "setFieldRefConfig", [
  688. // 'class' => "btn btn-xs btn-default" . ( 'table' === $refSource ? ' disabled' : '' ),
  689. // 'href' => $thisGetLink('setFieldRefConfig'),
  690. // 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], 'do' => 'table' ]
  691. // ]),
  692. // UI::hButtonAjax("Widok (cache)", "setFieldRefConfig", [
  693. // 'title' => "Według flat_relation_cache",
  694. // 'class' => "btn btn-xs btn-default" . ( 'view' === $refSource ? ' disabled' : '' ),
  695. // 'href' => $thisGetLink('setFieldRefConfig'),
  696. // 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], 'do' => 'view' ]
  697. // ]),
  698. UI::hButtonPost("Tabela ref", [
  699. 'title' => "Według wygenerowanej tabeli REF",
  700. 'class' => "btn btn-xs btn-default" . ( 'table' === $refSource ? ' disabled' : '' ),
  701. // 'href' => $thisGetLink('setFieldRefConfig'),
  702. 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], '_postTask' => 'setFieldRefConfig', 'source' => 'table' ]
  703. ]),
  704. UI::hButtonPost("Widok (cache)", [
  705. 'title' => "Według flat_relation_cache",
  706. 'class' => "btn btn-xs btn-default" . ( 'view' === $refSource ? ' disabled' : '' ),
  707. // 'href' => $thisGetLink('setFieldRefConfig'),
  708. 'data' => [ 'namespace' => $refNamespace, 'field' => $field['fieldNamespace'], '_postTask' => 'setFieldRefConfig', 'source' => 'view' ]
  709. ]),
  710. ]
  711. ),
  712. '@class' => ($isInstalled) ? "success" : "danger",
  713. ]; // TODO: link to install object
  714. }, $refFields)
  715. ]);
  716. }
  717. $thisGetLink = [ $this, 'getLink' ];
  718. UI::table([
  719. '__html_id' => 'struct_table',
  720. 'caption' => UI::h('span', [], [
  721. UI::h('span', [ 'style' => "margin-right:6px;color:#000" ], "Struktura obiektu '{$item['namespace']}'"),
  722. ]),
  723. // 'sortBy' => [
  724. // 'method' => 'get',
  725. // 'argName' => '_sortBy',
  726. // 'allow' => ['sort', 'namespace'],
  727. // 'default' => ['namespace', 'asc'],
  728. // ],
  729. 'cols_label' => [
  730. 'sort' => UI::h('nobr', [
  731. 'class' => "ta-ordering" . ('sort' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  732. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'sort', '" . ('sort' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  733. 'title' => "Sortuj wg pola SORT_PRIO z zasobów",
  734. ], "sort"),
  735. 'namespace' => UI::h('nobr', [
  736. 'class' => "ta-ordering" . ('namespace' === $sortByCol ? " ta-ordering-" . ( 'asc' === $sortByDir ? 'asc' : 'desc' ) : '' ),
  737. 'onClick' => "return p5UI_table_sortBy_get(this, '{$sortByArgName}', 'namespace', '" . ('namespace' === $sortByCol ? ( 'asc' === $sortByDir ? 'desc' : 'asc' ) : 'asc' ) . "')",
  738. 'title' => "Sortuj wg nazwy pola",
  739. ], "namespace"),
  740. ],
  741. 'rows' => array_map(function ($field) use ($item, $thisGetLink, $sortByCol) {
  742. $tblItem = [];
  743. if ('sort' === $sortByCol && null !== $field['SORT_PRIO'] && !empty($field['idZasob'])) {
  744. $tblItem['@class'] = "ta-sortable-item";
  745. $tblItem['@class[sort]'] = "ta-sortable-item-handle";
  746. $tblItem['@data']['sort_prio'] = $field['SORT_PRIO'];
  747. $tblItem['@data']['id_zasob'] = $field['idZasob'];
  748. $field['SORT_PRIO'] = ":: {$field['SORT_PRIO']}";
  749. }
  750. $tblItem['sort'] = V::get('SORT_PRIO', null, $field);
  751. foreach ($field as $k => $v) {
  752. if ('SORT_PRIO' === $k) continue;
  753. $tblItem[$k] = $v;
  754. }
  755. $tblItem['namespace'] = UI::h('span', [], [
  756. UI::h('span', ['style' => "color:#aaa"], substr($field['namespace'], 0, strlen($field['objectNamespace']) + 1)),
  757. UI::h('span', ['style' => "color:#000"], substr($field['namespace'], strlen($field['objectNamespace']) + 1)),
  758. ]);
  759. $tblItem['idZasob'] = ($field['idZasob'] > 0)
  760. ? $field['idZasob']
  761. : (
  762. ($item['idZasob'] > 0)
  763. ? UI::hButtonAjax("+ do zasobów", 'addFieldToZasobyAjax', [
  764. 'class' => "btn btn-xs btn-primary",
  765. 'href' => $thisGetLink('addFieldToZasobyAjax'),
  766. 'data' => [
  767. 'namespace' => $item['namespace'],
  768. 'fieldNamespace' => $field['namespace'],
  769. ]
  770. ])
  771. : UI::h('span', ['title'=>"Brak Nr zasobu dla obiektu", 'class'=>"btn btn-xs btn-danger"], "Brak nr zasobu obiektu")
  772. )
  773. ;
  774. unset($tblItem['objectNamespace']);
  775. unset($tblItem['fieldNamespace']);
  776. return $tblItem;
  777. }, array_filter($item['field'], function ($field) { return $field['isActive']; }))
  778. ]);
  779. $removedFields = array_filter($item['field'], function ($field) { return !$field['isActive']; });
  780. if (!empty($removedFields)) {
  781. echo UI::h('details', [ 'style' => "margin-bottom:12px; padding:6px; background-color:#dedede; color:#000" ], [
  782. UI::h('summary', [ 'style' => "padding:0 3px; outline:none; cursor:pointer" ], "Pola w koszu (".count($removedFields).")"),
  783. UI::h('table', [ 'style' => "margin:6px 0 0 0; background-color:#fff; font-size:x-small", 'class' => "table table-bordered table-hover table-condensed" ], [
  784. UI::h('thead', [], [
  785. UI::h('tr', [], [
  786. UI::h('th', [], "#"),
  787. UI::h('th', [], "namespace"),
  788. UI::h('th', [], "xsdType"),
  789. UI::h('th', [], "xsdRestrictions"),
  790. UI::h('th', [], "appInfo"),
  791. UI::h('th', [], "minOccurs"),
  792. UI::h('th', [], "maxOccurs"),
  793. UI::h('th', [], "isActive"),
  794. ]),
  795. ]),
  796. UI::h('tbody', [], array_map(function ($field) use ($item, $thisGetLink) {
  797. return UI::h('tr', [], [
  798. UI::h('td', [], [
  799. UI::hButtonAjax("usuń", 'removeFieldFromTrashAjax', [
  800. 'class' => "btn btn-xs btn-danger",
  801. 'href' => $thisGetLink('removeFieldFromTrashAjax'),
  802. 'data' => [
  803. 'namespace' => $item['namespace'],
  804. 'fieldNamespace' => $field['namespace'],
  805. ]
  806. ])
  807. ]),
  808. UI::h('td', [], $field['fieldNamespace']),
  809. UI::h('td', [], $field['xsdType']),
  810. UI::h('td', [], $field['xsdRestrictions']),
  811. UI::h('td', [], $field['appInfo']),
  812. UI::h('td', [], $field['minOccurs']),
  813. UI::h('td', [], $field['maxOccurs']),
  814. UI::h('td', [], $field['isActive']),
  815. ]);
  816. }, $removedFields)),
  817. ]),
  818. ]);
  819. }
  820. UI::hButtonAjaxOnResponse('removeFieldFromTrashAjax', /* payload, n */ "
  821. if (!payload.type) return false
  822. jQuery.notify(payload.msg, payload.type)
  823. if ('success' == payload.type) {
  824. var trJqNode = jQuery(n).closest('tr')
  825. var tbodyJqNode = trJqNode.parent()
  826. var detailsJqNode = trJqNode.closest('details')
  827. trJqNode.remove()
  828. if (!tbodyJqNode.children().length) {
  829. detailsJqNode.remove()
  830. }
  831. }
  832. ");
  833. UI::hButtonAjaxOnResponse('addFieldToZasobyAjax', /* payload, n */ "
  834. if (!payload.type) return false
  835. if (payload.body && payload.body.id && payload.body.id > 0) { // if ('success' == payload.type) {
  836. n.parentNode.replaceChild(document.createTextNode(payload.body.id), n)
  837. }
  838. jQuery.notify(payload.msg, payload.type)
  839. ");
  840. UI::hButtonAjaxOnResponse('addAclObjectToZasobyAjax', /* payload, n */ "
  841. if (!payload.type) return false
  842. if ('success' === payload.type || 'info' === payload.type) {
  843. if (payload.body && payload.body.id && payload.body.id > 0) {
  844. n.parentNode.replaceChild(document.createTextNode(payload.body.id), n)
  845. } else {
  846. console.log('TODO: addAclObjectToZasobyAjax unknown response', payload);
  847. }
  848. window.location.reload()
  849. }
  850. ");
  851. UI::hButtonAjaxOnResponse('activateObjectAjax', /* payload, n */ "
  852. jQuery.notify(payload.msg, payload.type)
  853. if (!payload.type) return false
  854. if ('success' === payload.type || 'info' === payload.type) {
  855. if (payload.body && payload.body.isObjectActive && payload.body.isObjectActive > 0) {
  856. n.parentNode.replaceChild(document.createTextNode('Active'), n)
  857. } else {
  858. console.log('TODO: activateObjectAjax unknown response', payload);
  859. }
  860. }
  861. ");
  862. if ('sort' === $sortByCol) {
  863. echo UI::h('script', [], "
  864. jQuery(document).ready(function (){
  865. var tblNode$ = jQuery('#struct_table > tbody')
  866. var getOrder = function () {
  867. var orderIds = []
  868. jQuery('#struct_table > tbody').children('.ta-sortable-item').each(function (idx, trNode) {
  869. orderIds.push(jQuery(trNode).data('id_zasob'))
  870. })
  871. return orderIds
  872. }
  873. var sortOrder = getOrder()
  874. console.log('sortOrder - init', sortOrder)
  875. tblNode$.sortable({
  876. axis: 'y',
  877. handle: '.ta-sortable-item-handle',
  878. items: '.ta-sortable-item',
  879. update: function (event, ui) {
  880. sortOrder = getOrder()
  881. tblNode$.sortable('disable')
  882. tblNode$.find('.ta-sortable-item-handle').css({color:'silver'})
  883. console.log('TODO: disable sortable while ajax')
  884. // window.setTimeout(function () {
  885. // tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  886. // console.log('TODO: ajax fetch result')
  887. // tblNode$.sortable('enable')
  888. // tblNode$.sortable('cancel')
  889. // }, 1000)
  890. window.fetch(
  891. URI(window.location.href)
  892. .setSearch('_task', 'updateAntAclSortAjax')
  893. .setSearch('idZasobOrder', sortOrder)
  894. .build().toString(),
  895. {
  896. method: 'POST',
  897. headers: {
  898. 'Content-Type': 'application/x-www-form-urlencoded' // query string
  899. },
  900. credentials: 'same-origin',
  901. body: JSON.stringify({
  902. namespace: URI.parseQuery(window.location.search).namespace,
  903. sortBy: '{$sortByCol}',
  904. sortByDir: '{$sortByDir}',
  905. sortOrder: sortOrder,
  906. })
  907. }
  908. ).then(function(response) {
  909. return response.json()
  910. }).then(function(payload) {
  911. console.log('updateAntAclSortAjax response', payload);
  912. tblNode$.sortable('enable')
  913. if ('success' !== payload.type) {
  914. tblNode$.sortable('cancel')
  915. }
  916. tblNode$.sortable('enable')
  917. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  918. p5UI__notifyAjaxCallback({
  919. type: payload.type || 'error',
  920. msg: payload.msg || 'Request error'
  921. });
  922. if ('success' === payload.type) {
  923. window.location.reload(true)
  924. }
  925. }).catch(function(e) {
  926. tblNode$.sortable('enable')
  927. tblNode$.sortable('cancel')
  928. tblNode$.find('.ta-sortable-item-handle').css({color:'black'})
  929. p5UI__notifyAjaxCallback({
  930. type: 'error',
  931. msg: 'Request error ' + e
  932. });
  933. })
  934. }
  935. });
  936. });
  937. ");
  938. }
  939. if ($item['isObjectActive']) {
  940. echo UI::hButtonAjax("Dodaj podstawowy proces dla obiektu '{$item['namespace']}' - read only (TODO)", 'addObjectBaseProcesAjax', [
  941. 'class' => "btn btn-xs btn-default",
  942. 'href' => Router::getRoute('Storage')->getLink('addObjectBaseProcesAjax'),
  943. 'data' => [ 'namespace' => $item['namespace'] ]
  944. ]);
  945. UI::hButtonAjaxOnResponse('addObjectBaseProcesAjax', /* payload, n */ "
  946. jQuery.notify(payload.msg, payload.type)
  947. ");
  948. }
  949. DBG::nicePrint($item, '$item');
  950. }
  951. public function updateAntAclSortAjaxAction() {
  952. return Response::sendTryCatchJson(array($this, 'updateAntAclSortAjax'), $args = 'JSON_FROM_REQUEST_BODY');
  953. }
  954. public function updateAntAclSortAjax($args) {
  955. DBG::log($args, 'array', "args");
  956. $namespace = V::get('namespace', '', $args);
  957. if (empty($namespace)) throw new Exception("Missing param namespace");
  958. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  959. DBG::log($item, 'array', "\$item");
  960. $sortByArgName = 'sortBy';
  961. $sortByCol = V::get($sortByArgName, 'namespace', $args);
  962. $sortByDir = V::get("{$sortByArgName}Dir", 'asc', $args);
  963. if ('sort' !== $sortByCol) throw new Exception("Only sort by SORT_PRIO allowed to update");
  964. if (!in_array($sortByDir, ['asc', 'desc'])) throw new Exception("Wrong order by dir arg");
  965. if ('asc' !== $sortByDir) throw new Exception("Only sort asc is allowed"); // DBG
  966. $sortPrioIdsFromZasoby = DB::getPDO()->fetchAll("
  967. select z.ID, z.SORT_PRIO
  968. from CRM_LISTA_ZASOBOW z
  969. where z.PARENT_ID = :p_id
  970. order by z.SORT_PRIO asc, z.ID asc -- default order in Zasoby tree
  971. ", [
  972. ':p_id' => $item['idZasob']
  973. ]);
  974. DBG::log($sortPrioIdsFromZasoby, 'array', "\$sortPrioIdsFromZasoby");
  975. $idZasobCurrentOrder = array_map(function ($orderRow) {
  976. return (int)$orderRow['ID'];
  977. }, $sortPrioIdsFromZasoby);
  978. DBG::log($idZasobCurrentOrder, 'array', "\$idZasobCurrentOrder");
  979. DBG::log(array_diff_assoc($args['sortOrder'], $idZasobCurrentOrder), 'array', "array_diff_assoc(\$args['sortOrder'], \$idZasobCurrentOrder)");
  980. DBG::log(array_diff_assoc($idZasobCurrentOrder, $args['sortOrder']), 'array', "array_diff_assoc(\$idZasobCurrentOrder, \$args['sortOrder'])");
  981. $orderDiff = array_diff_assoc($args['sortOrder'], $idZasobCurrentOrder);
  982. foreach ($orderDiff as $sortPrio => $idZasob) {
  983. DB::getPDO()->update('CRM_LISTA_ZASOBOW', 'ID', $idZasob, [
  984. 'SORT_PRIO' => $sortPrio,
  985. ]);
  986. }
  987. return [
  988. 'type' => 'success',
  989. 'msg' => "OK",
  990. 'DBG__args' => $args
  991. ];
  992. }
  993. public function removeFieldFromTrashAjaxAction() {
  994. DBG::log($_REQUEST, 'array', '$_REQUEST');
  995. Response::sendTryCatchJson(array($this, 'removeFieldFromTrashAjax'), $_REQUEST);
  996. }
  997. public function removeFieldFromTrashAjax($args) {
  998. $namespace = V::get('namespace', '', $args);
  999. if (empty($namespace)) throw new HttpException("Missing namespace");
  1000. $fieldNamespace = V::get('fieldNamespace', '', $args);
  1001. if (empty($fieldNamespace)) throw new HttpException("Missing fieldNamespace");
  1002. $fieldItem = SchemaFactory::loadDefaultObject('SystemObjectField')->getItem($fieldNamespace);
  1003. if (!$fieldItem) throw new HttpException("Field not found '{$fieldNamespace}'", 404);
  1004. DBG::log($fieldItem, 'array', "\$fieldItem");
  1005. switch ($fieldItem['xsdType']) {
  1006. case 'p5:enum': throw new Exception("TODO: remove enum values first"); break; // CRM_#CACHE_ACL_OBJECT_FIELD_enum
  1007. default: {
  1008. if ('ref:' === substr($fieldItem['xsdType'], 0, 4)) { // OK, remove
  1009. } else throw new Exception("TODO: remove xsdType: {$fieldItem['xsdType']}");
  1010. }
  1011. }
  1012. DB::getPDO()->execSql("
  1013. DELETE from `CRM_#CACHE_ACL_OBJECT_FIELD`
  1014. where namespace = :namespace
  1015. and objectNamespace = :objectNamespace
  1016. and _rootTableName = :rootTableName
  1017. and isActive = 0
  1018. limit 1
  1019. ", [
  1020. 'namespace' => $fieldItem['namespace'],
  1021. 'objectNamespace' => $fieldItem['objectNamespace'],
  1022. 'rootTableName' => $fieldItem['_rootTableName'],
  1023. ]);
  1024. return [
  1025. 'type' => "success",
  1026. 'msg' => "Usunięto pole {$fieldItem['fieldNamespace']}",
  1027. ];
  1028. }
  1029. public function addFieldToZasobyAjaxAction() {
  1030. DBG::log($_REQUEST, 'array', '$_REQUEST');
  1031. Response::sendTryCatchJson(array($this, 'addFieldToZasobyAjax'), $_REQUEST);
  1032. }
  1033. public function addFieldToZasobyAjax($args) {
  1034. $namespace = V::get('namespace', '', $args);
  1035. if (empty($namespace)) throw new HttpException("Missing namespace");
  1036. $fieldNamespace = V::get('fieldNamespace', '', $args);
  1037. if (empty($fieldNamespace)) throw new HttpException("Missing fieldNamespace");
  1038. $fieldItem = SchemaFactory::loadDefaultObject('SystemObjectField')->getItem($fieldNamespace);
  1039. if (!$fieldItem) throw new HttpException("Field not found '{$fieldNamespace}'", 404);
  1040. DBG::log($fieldItem, 'array', "\$fieldItem");
  1041. if ($fieldItem['idZasob'] > 0) throw (new AlertSuccessException("Field already added to Zasoby '{$fieldItem['idZasob']}'"))->setBody([ 'id' => $fieldItem['idZasob'] ]);
  1042. $objectItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace);
  1043. if (!$objectItem) throw new HttpException("Object not found '{$namespace}'", 404);
  1044. DBG::log($objectItem, 'array', "\$objectItem");
  1045. if (!$objectItem['idZasob']) throw new Exception("Missing Object idZasob");
  1046. $zasobItem = DB::getPDO()->fetchFirst("
  1047. select zField.ID, zField.`DESC`, zField.`TYPE`, zField.PARENT_ID
  1048. from CRM_LISTA_ZASOBOW as zField
  1049. join CRM_LISTA_ZASOBOW as zTable on(zTable.ID = zField.PARENT_ID)
  1050. where zTable.`ID` = '{$objectItem['idZasob']}'
  1051. and zTable.`TYPE` = 'TABELA'
  1052. and zField.`DESC` = '{$fieldItem['fieldNamespace']}'
  1053. and zField.`TYPE` = 'KOMORKA'
  1054. ");
  1055. if ($zasobItem) {
  1056. SchemaFactory::loadDefaultObject('SystemObjectField')->updateItem([
  1057. 'namespace' => $fieldItem['namespace'],
  1058. 'idZasob' => $zasobItem['ID']
  1059. ]);
  1060. throw (new AlertSuccessException("Zasob już istnieje"))->setBody([ 'id' => $zasobItem['ID'] ]);
  1061. }
  1062. $newFieldItem = [
  1063. 'PARENT_ID' => $objectItem['idZasob'],
  1064. 'TYPE' => 'KOMORKA',
  1065. 'DESC' => $fieldItem['fieldNamespace'],
  1066. 'DESC_PL' => $fieldItem['fieldNamespace'],
  1067. ];
  1068. DBG::log($newFieldItem, 'array', "add new field item");
  1069. try {
  1070. $acl = User::getAcl()->getObjectAcl('default_db', 'crm_lista_zasobow');
  1071. } catch (Exception $e) {
  1072. throw new Exception("Brak dostępu do tabeli Zasoby");
  1073. }
  1074. $createdId = $acl->addItem($newFieldItem);
  1075. if (!$createdId) throw new Exception("Nie udało się utworzyć nowego rekordu!");
  1076. SchemaFactory::loadDefaultObject('SystemObjectField')->updateItem([
  1077. 'namespace' => $fieldItem['namespace'],
  1078. 'idZasob' => $createdId
  1079. ]);
  1080. throw (new AlertSuccessException("Utworzono pomyślnie rekord nr {$createdId}"))->setBody([ 'id' => $createdId ]);
  1081. }
  1082. }