AclReinstall.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. <?php
  2. Lib::loadClass('RouteBase');
  3. Lib::loadClass('Router');
  4. Lib::loadClass('Response');
  5. Lib::loadClass('UI');
  6. Lib::loadClass('SchemaFactory');
  7. Lib::loadClass('RefConfig');
  8. Lib::loadClass('Type_Field');
  9. class Route_Storage_AclReinstall extends RouteBase {
  10. public function handleAuth() {
  11. if (!User::logged()) {
  12. User::authByRequest();
  13. }
  14. }
  15. public function defaultAction() {
  16. UI::gora();
  17. UI::startContainer();
  18. try {
  19. $namespace = V::get('namespace', '', $_GET);
  20. if (empty($namespace)) throw new Exception("Missing param namespace");
  21. echo UI::h('h3', [], $namespace);
  22. echo UI::h('p', [], [
  23. UI::h('a', [
  24. 'href' => Router::getRoute('Storage_AclStruct')->getLink('', [ 'namespace' => $namespace ]),
  25. 'class' => "btn btn-md btn-link",
  26. ], "<i class=\"glyphicon glyphicon-arrow-left\"></i> Wróć do struktury"),
  27. " | ",
  28. UI::h('a', [
  29. 'href' => $this->getLink('viewXsdSource', [ 'namespace' => $namespace ]),
  30. 'class' => "btn btn-md btn-link",
  31. 'target' => "_blank",
  32. ], "Otwórz plik xsd (źródłowy)"),
  33. ]);
  34. if ('reinstall' == V::get('_postTask', '', $_POST)) {
  35. $this->reinstallAcl($namespace);
  36. return;
  37. }
  38. echo UI::hButtonPost("Reinstall", [
  39. 'data' => [
  40. '_postTask' => 'reinstall'
  41. ],
  42. 'class' => 'btn btn-md btn-danger',
  43. 'title' => "Reinstall structure"
  44. ]);
  45. echo '<hr>';
  46. try {
  47. $this->printReinstallPreview($namespace);
  48. } catch (Exception $e) {
  49. DBG::log($e);
  50. UI::alert('danger', $e->getMessage());
  51. }
  52. } catch (Exception $e) {
  53. UI::alert('danger', "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage());
  54. DBG::log($e);
  55. }
  56. UI::endContainer();
  57. UI::dol();
  58. }
  59. public function printReinstallPreview($namespace) {
  60. $objectItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => "*,field" ]);
  61. DBG::log($objectItem, 'array', '$objectItem preview');
  62. switch ($objectItem['_type']) {
  63. case 'AntAcl': $this->printReinstallAntAclPreview($objectItem); break;
  64. case 'TableAcl': $this->printReinstallTableAclPreview($objectItem); break;
  65. case 'StorageAcl': $this->printReinstallStorageAclPreview($objectItem); break;
  66. default: throw new Exception("TODO: Not Implemented type '{$objectItem['_type']}'");
  67. }
  68. }
  69. public function printReinstallAntAclPreview($item) {
  70. Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
  71. $antAclPath = Schema_SystemObjectFieldStorageAcl::getAntAclXsdBasePath($item['typeName']);
  72. if (!file_exists("{$antAclPath}/build.xml")) throw new Exception("Ant build file not exists");
  73. Lib::loadClass('XML');
  74. $xsdType = XML::getXsdTypeFromXsdSchema("{$antAclPath}/{$item['name']}.xsd", $namespace = $item['namespace'], $name = $item['name']);
  75. DBG::nicePrint($item, '$item');
  76. DBG::nicePrint($xsdType, '$xsdType');
  77. echo '<hr>';
  78. echo UI::h('h3', [], "Lista zmian:");
  79. echo ($item['primaryKey'] != $xsdType['primaryKey'])
  80. ? UI::h('p', [ 'style' => "" ], "@primaryKey - zmiana z '{$item['primaryKey']}' na '{$xsdType['primaryKey']}'")
  81. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "@primaryKey - bez zmian");
  82. if (empty($xsdType['struct'])) throw new Exception("Field list not found for '{$item['namespace']}'");
  83. foreach ($xsdType['struct'] as $fieldName => $x) {
  84. $listEnum = [];
  85. if (!empty($x['restrictions']['enumeration'])) {
  86. $listEnum = $x['restrictions']['enumeration'];
  87. unset($x['restrictions']['enumeration']);
  88. }
  89. if (!empty($listEnum)) {
  90. DBG::log($listEnum, 'array', "\$listEnum for field '{$fieldName}'");
  91. }
  92. }
  93. $old = [
  94. 'fields' => array_map(function ($field) { return $field['fieldNamespace']; }, $item['field']),
  95. ];
  96. $new = [
  97. 'fields' => array_keys($xsdType['struct']),
  98. ];
  99. sort($old['fields']);
  100. sort($new['fields']);
  101. $diffFieldsToCreate = array_diff($new['fields'], $old['fields']);
  102. $diffFieldsToRemove = array_diff($old['fields'], $new['fields']);
  103. $sameFields = array_intersect($new['fields'], $old['fields']);
  104. echo (!empty($diffFieldsToCreate))
  105. ? UI::h('details', [ 'open' => "open" ], [
  106. UI::h('summary', [], "Pola do dodania (".count($diffFieldsToCreate)."):"),
  107. UI::h('ul', [], array_map(function ($fieldName) {
  108. return UI::h('li', [], $fieldName);
  109. }, $diffFieldsToCreate)),
  110. ])
  111. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Brak pól do dodania");
  112. echo (!empty($diffFieldsToRemove))
  113. ? UI::h('details', [ 'open' => "open", 'style' => "margin:4px 0; color:#8a6d3b; background-color:#fcf8e3; border:1px solid #faebcc;" ], [
  114. UI::h('summary', [ 'style' => "padding:4px; outline:none; cursor:pointer" ], "Pola do usunięcia (".count($diffFieldsToRemove)."):"),
  115. UI::h('ul', [], array_map(function ($fieldName) {
  116. return UI::h('li', [], $fieldName);
  117. }, $diffFieldsToRemove)),
  118. ])
  119. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Brak pól do usunięcia");
  120. foreach ($sameFields as $fieldName) {
  121. // UI::alert('warning', "TODO: is field changed? '{$fieldName}'");
  122. $oldField = array_filter($item['field'], function ($field) use ($fieldName) { return ( $fieldName === $field['fieldNamespace'] ); });
  123. $oldField = ($oldField) ? reset($oldField) : null;
  124. // DBG::nicePrint($oldField, "\$oldField '$fieldName'");
  125. $newField = $xsdType['struct'][$fieldName];
  126. // DBG::nicePrint($newField, "\$newField '$fieldName'");
  127. $fieldDiff = [];
  128. if ($newField['type'] !== $oldField['xsdType']) $fieldDiff[] = 'xsdType';
  129. if ($newField['minOccurs'] != $oldField['minOccurs']) $fieldDiff[] = 'minOccurs';
  130. if ($newField['maxOccurs'] != $oldField['maxOccurs']) $fieldDiff[] = 'maxOccurs';
  131. if (json_encode($newField['restrictions']) !== $oldField['xsdRestrictions']) $fieldDiff[] = 'xsdRestrictions';
  132. if (json_encode($newField['appInfo']) !== $oldField['appInfo']) $fieldDiff[] = 'appInfo';
  133. if (RefConfig::isRefField($item['namespace'], $fieldName)) {
  134. $typeNewField = Type_Field::build($newField);
  135. $typeOldField = Type_Field::build($oldField);
  136. if (RefConfig::needUpdate($item['namespace'], $oldField['fieldNamespace'], $typeNewField, $typeOldField)) {
  137. $fieldDiff[] = 'RefConfig';
  138. }
  139. }
  140. echo (!empty($fieldDiff))
  141. ? UI::h('p', [ 'style' => "" ], "Pole '{$fieldName}' - zmiany: " . implode(", ", $fieldDiff))
  142. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Pole '{$fieldName}' - bez zmian");
  143. }
  144. }
  145. public function printReinstallTableAclPreview($item) {
  146. throw new Exception("TODO: Podgląd zmian dla tabeli {$item['namespace']} ...");
  147. }
  148. public function printReinstallStorageAclPreview($item) {
  149. DBG::nicePrint($item, '$item');
  150. $acl = SchemaFactory::loadDefaultObject($item['name']);
  151. DBG::nicePrint($acl, '$acl');
  152. $xsdType = [
  153. 'primaryKey' => $acl->getPrimaryKeyField(),
  154. 'struct' => $acl->getFieldsWithXsdTypes()
  155. ];
  156. DBG::nicePrint($xsdType, '$xsdType');
  157. echo '<hr>';
  158. echo UI::h('h3', [], "Lista zmian:");
  159. echo ($item['primaryKey'] != $xsdType['primaryKey'])
  160. ? UI::h('p', [ 'style' => "" ], "@primaryKey - zmiana z '{$item['primaryKey']}' na '{$xsdType['primaryKey']}'")
  161. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "@primaryKey - bez zmian");
  162. if (empty($xsdType['struct'])) throw new Exception("Field list not found for '{$item['namespace']}'");
  163. foreach ($xsdType['struct'] as $fieldName => $x) {
  164. $listEnum = [];
  165. if (!empty($x['restrictions']['enumeration'])) {
  166. $listEnum = $x['restrictions']['enumeration'];
  167. unset($x['restrictions']['enumeration']);
  168. }
  169. if (!empty($listEnum)) {
  170. DBG::log($listEnum, 'array', "\$listEnum for field '{$fieldName}'");
  171. }
  172. }
  173. $old = [
  174. 'fields' => array_map(function ($field) { return $field['fieldNamespace']; }, $item['field']),
  175. ];
  176. $new = [
  177. 'fields' => array_keys($xsdType['struct']),
  178. ];
  179. sort($old['fields']);
  180. sort($new['fields']);
  181. $diffFieldsToCreate = array_diff($new['fields'], $old['fields']);
  182. $diffFieldsToRemove = array_diff($old['fields'], $new['fields']);
  183. $sameFields = array_intersect($new['fields'], $old['fields']);
  184. echo (!empty($diffFieldsToCreate))
  185. ? UI::h('details', [ 'open' => "open" ], [
  186. UI::h('summary', [], "Pola do dodania (".count($diffFieldsToCreate)."):"),
  187. UI::h('ul', [], array_map(function ($fieldName) {
  188. return UI::h('li', [], $fieldName);
  189. }, $diffFieldsToCreate)),
  190. ])
  191. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Brak pól do dodania");
  192. echo (!empty($diffFieldsToRemove))
  193. ? UI::h('details', [ 'open' => "open", 'style' => "margin:4px 0; color:#8a6d3b; background-color:#fcf8e3; border:1px solid #faebcc;" ], [
  194. UI::h('summary', [ 'style' => "padding:4px; outline:none; cursor:pointer" ], "Pola do usunięcia (".count($diffFieldsToRemove)."):"),
  195. UI::h('ul', [], array_map(function ($fieldName) {
  196. return UI::h('li', [], $fieldName);
  197. }, $diffFieldsToRemove)),
  198. ])
  199. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Brak pól do usunięcia");
  200. foreach ($sameFields as $fieldName) {
  201. // UI::alert('warning', "TODO: is field changed? '{$fieldName}'");
  202. $oldField = array_filter($item['field'], function ($field) use ($fieldName) { return ( $fieldName === $field['fieldNamespace'] ); });
  203. $oldField = ($oldField) ? reset($oldField) : null;
  204. // DBG::nicePrint($oldField, "\$oldField '$fieldName'");
  205. $newField = $xsdType['struct'][$fieldName];
  206. // DBG::nicePrint($newField, "\$newField '$fieldName'");
  207. $fieldDiff = [];
  208. if ($newField['type'] !== $oldField['xsdType']) $fieldDiff[] = 'xsdType';
  209. if ($newField['minOccurs'] != $oldField['minOccurs']) $fieldDiff[] = 'minOccurs';
  210. if ($newField['maxOccurs'] != $oldField['maxOccurs']) $fieldDiff[] = 'maxOccurs';
  211. if (json_encode($newField['restrictions']) !== $oldField['xsdRestrictions']) $fieldDiff[] = 'xsdRestrictions';
  212. if (json_encode($newField['appInfo']) !== $oldField['appInfo']) $fieldDiff[] = 'appInfo';
  213. echo (!empty($fieldDiff))
  214. ? UI::h('p', [ 'style' => "" ], "Pole '{$fieldName}' - zmiany: " . implode(", ", $fieldDiff))
  215. : UI::h('p', [ 'style' => "font-style:italic; color:silver" ], "Pole '{$fieldName}' - bez zmian");
  216. }
  217. }
  218. public function viewXsdSourceAction() {
  219. try {
  220. $namespace = V::get('namespace', '', $_GET);
  221. if (empty($namespace)) throw new Exception("Missing param namespace");
  222. $objectItem = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => "*,field" ]);
  223. switch ($objectItem['_type']) {
  224. case 'AntAcl': $this->viewXsdSource($objectItem); break;
  225. // case 'TableAcl': $this->viewXsdSource($objectItem); break;
  226. default: throw new Exception("TODO: Not Implemented type '{$objectItem['_type']}'");
  227. }
  228. } catch (Exception $e) {
  229. DBG::log($e);
  230. echo "Error #" . $e->getCode() . "|" . $e->getLine() . ": " . $e->getMessage();
  231. }
  232. }
  233. function viewXsdSource($objectItem) {
  234. if (empty($objectItem)) throw new Exception("Missing objectItem in viewXsdSource");
  235. DBG::log($objectItem, "viewXsdSource \$objectItem");
  236. Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
  237. $antAclPath = Schema_SystemObjectFieldStorageAcl::getAntAclXsdBasePath($objectItem['typeName']);
  238. if (!file_exists("{$antAclPath}/build.xml")) throw new Exception("Ant build file not exists");
  239. DBG::log(str_replace(APP_PATH_ROOT, '~', $antAclPath), "viewXsdSource \$antAclPath");
  240. $xsdFile = "{$antAclPath}/{$objectItem['name']}.xsd";
  241. if (!file_exists($xsdFile)) throw new Exception("Xsd file not exists");
  242. DBG::log(str_replace(APP_PATH_ROOT, '~', $xsdFile), "viewXsdSource \$xsdFile");
  243. header('Content-Type: application/xml; charset=utf-8');
  244. $fd = fopen($xsdFile, 'r');
  245. fpassthru($fd);
  246. exit;
  247. }
  248. function reinstallAcl($namespace) {
  249. Lib::loadClass('Schema_SystemObjectFieldStorageAcl');
  250. $objFieldAcl = new Schema_SystemObjectFieldStorageAcl();
  251. $objFieldAcl->updateCache($namespace);
  252. try {
  253. $dbgInfo = [
  254. 'idInstance' => ACL::getInstanceId($namespace),
  255. 'rootInstance' => ACL::getRootNamespace($namespace),
  256. 'conf' => ACL::fetchInstanceConfig($namespace),
  257. // 'table' => ACL::getInstanceTable($namespace), // Object structure not installed 'default_db/{tableName}'
  258. ];
  259. DBG::nicePrint($dbgInfo, "dbg");
  260. } catch (Exception $e) {
  261. UI::alert('warning', $e->getMessage());
  262. }
  263. $item = SchemaFactory::loadDefaultObject('SystemObject')->getItem($namespace, [ 'propertyName' => '*,field' ]);
  264. $childRefList = RefConfig::getChildRefFullList($namespace);
  265. DBG::nicePrint($childRefList, '$childRefList');
  266. DBG::nicePrint($item, '$item');
  267. $activeFields = array_filter($item['field'], function ($field) {
  268. return ($field['isActive'] > 0);
  269. });
  270. $fieldNsList = array_map(function ($field) {
  271. return $field['fieldNamespace'];
  272. }, $activeFields);
  273. DBG::nicePrint($fieldNsList, '$fieldNsList');
  274. if ('AntAcl' === $item['_type']) { // fix ref config status (turn on/off)
  275. foreach ($childRefList as $refConfig) { // [ namespace, A_STATUS ]
  276. if ($refConfig->status !== 'DELETED' && !in_array($refConfig->childName, $fieldNsList)) {
  277. UI::alert('danger', "remove ref config for '{$refConfig->childName}' ...");
  278. if (!$refConfig->id) throw new Exception("Missing ref config ID");
  279. RefConfig::remove($refConfig);
  280. }
  281. else if ($refConfig->status !== 'DELETED' && in_array($refConfig->childName, $fieldNsList)) {
  282. UI::alert('info', "ref config for '{$refConfig->childName}' active - OK");
  283. }
  284. else if ($refConfig->status === 'DELETED' && in_array($refConfig->childName, $fieldNsList)) {
  285. UI::alert('warning', "activate ref config for '{$refConfig->childName}' ...");
  286. if (!$refConfig->id) throw new Exception("Missing ref config ID");
  287. RefConfig::reactivate($refConfig);
  288. }
  289. else if ($refConfig->status === 'DELETED' && !in_array($refConfig->childName, $fieldNsList)) {
  290. UI::alert('info', "ref config for '{$refConfig->childName}' removed - OK");
  291. }
  292. else {
  293. UI::alert('danger', "Not implemented action for '{$refConfig->childName}'");
  294. }
  295. }
  296. // TODO: create missing refConfig - field is not in $childRefList
  297. }
  298. if ('AntAcl' === $item['_type']) { // fix ref tables by appInfo
  299. $refFields = array_filter($item['field'], function ($field) {
  300. return ('ref:' === substr($field['xsdType'], 0, 4));
  301. });
  302. DBG::log($refFields, 'array', "DBG \$refFields");
  303. foreach ($refFields as $field) {
  304. $typeNewField = Type_Field::build($field);
  305. // if (RefConfig::needUpdate($item['namespace'], $oldField['fieldNamespace'], $typeNewField, $typeOldField))
  306. try {
  307. RefConfig::update($item['namespace'], $field['fieldNamespace'], $typeNewField);
  308. } catch (Exception $e) {
  309. // TODO: deactivate RefConfig if error
  310. DBG::log($e);
  311. UI::alert('danger', $e->getMessage());
  312. }
  313. }
  314. }
  315. {
  316. if ('AntAcl' === $item['_type']) {
  317. $dbName = DB::getPDO()->getDatabaseName();
  318. $sqlFunBody = ACL::generateIsInstanceFunctionBody($namespace, $item);
  319. DBG::nicePrint($sqlFunBody, "\$sqlFunBody");
  320. $idInstance = ACL::getInstanceId($namespace);
  321. DB::getPDO()->execSql(" DROP FUNCTION IF EXISTS `{$dbName}`.`isInstance_{$idInstance}` ");
  322. // CREATE
  323. // [DEFINER = { user | CURRENT_USER }]
  324. // FUNCTION sp_name ([func_parameter[,...]])
  325. // RETURNS type
  326. // [characteristic ...] routine_body
  327. DB::getPDO()->execSql("
  328. CREATE DEFINER=`root`@`localhost`
  329. FUNCTION `{$dbName}`.`isInstance_{$idInstance}` ( pk INT(11) )
  330. RETURNS TINYINT(1)
  331. {$sqlFunBody}
  332. ");
  333. }
  334. }
  335. }
  336. }