OBJ.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. <?php
  2. /*
  3. * json files in schema/gui/core/
  4. * default_db-{tbl_name}.json - config for raw table - no 'parent_object' defined
  5. * {object_name}.json - config for object - require 'parent_object' (another object or default_db-* raw table object)
  6. # Instance table:
  7. `{tbl_name}__INSTANCE_CLOSURE`: `PRIMARY_KEY`, `INSTANCE`(przodek), `PARENT_INSTANCE`(przodek), `PARENT_DEPTH`(głębokość)
  8. ## sql - fetch rows with instance:
  9. ```sql
  10. select t.*
  11. , (select inst.INSTANCE
  12. from {tbl_name}__INSTANCE_CLOSURE inst
  13. where inst.PRIMARY_KEY = t.{primary_key}
  14. order by inst.PARENT_DEPTH DESC limit 1) as _instance
  15. from {tbl_name} t
  16. ```
  17. ## sql - fetch all
  18. ```sql
  19. select t.*
  20. from {tbl_name} t
  21. right join {tbl_name}__INSTANCE_CLOSURE inst on(t.{primary_key} = inst.PRIMARY_KEY)
  22. ```
  23. # Ref tables:
  24. `{tbl_name}__REF__{target_table_name}`: `PRIMARY_KEY`, `REMOTE_PRIMARY_KEY`
  25. ## sql - make ref connection
  26. ```sql
  27. insert into `{tbl_name}__REF__{target_table_name}` (`PRIMARY_KEY`, `REMOTE_PRIMARY_KEY`)
  28. -- TODO: save action to _HIST table
  29. ```
  30. # Hist table:
  31. `{tbl_name}__ACTIVITY_LOG`:
  32. - `ID` int PRIMARY auto_increment - used in update to check conflicts
  33. - `PRIMARY_KEY` - same type as root table primary key
  34. - `ACTION_USER` varchar(20)
  35. - `ACTION_DATE` datetime
  36. - `ACTION_TYPE` enum('CREATE', 'UPDATE', 'DELETE')
  37. - `LOG` text - json with action details
  38. - `ERRORS` text - json with errors
  39. */
  40. class OBJ {
  41. public static function getName($json) {
  42. if (empty($json['name'])) throw new Exception("Struct error - name not defined in " . json_encode($json));
  43. return (is_array($json['name']))? end($json['name']) : $json['name'];
  44. }
  45. public static function getLabel($json) {
  46. if (empty($json['label'])) return null;
  47. return (is_array($json['label']))? end($json['label']) : $json['label'];
  48. }
  49. // @returns array of parent object names
  50. public static function getParentList($json) {
  51. if (empty($json['parent_object'])) return array();
  52. return (!is_array($json['parent_object']))? array($json['parent_object']) : array_reverse($json['parent_object']);
  53. }
  54. public static function getFields($json) {
  55. if (empty($json['fields'])) throw new Exception("Struct error - object has no fields");
  56. return $json['fields'];
  57. }
  58. public static function getTableFields($json) {
  59. if (empty($json['fields'])) throw new Exception("Struct error - object has no fields");
  60. $fields = array();
  61. foreach ($json['fields'] as $fldName => $fldConf) {
  62. switch ($fldConf['type']) {
  63. case 'int': $fields[] = $fldName; break;
  64. case 'string': $fields[] = $fldName; break;
  65. // TODO: more field types
  66. }
  67. }
  68. return $fields;
  69. }
  70. public static function getStorageName($json) {
  71. if (empty($json['db_source'])) throw new Exception("Struct error - object has no source defined");
  72. return $json['db_source'];
  73. }
  74. public static function getMainTableName($json) {
  75. if (empty($json['db_table'])) throw new Exception("Struct error - object has no table name defined");
  76. return $json['db_table'];
  77. }
  78. public static function getPrimaryKeyType($json) {
  79. // [keys] => Array(
  80. // [PRIMARY] => Array(
  81. // [fields] => ID
  82. // [auto_increment] => 1
  83. if (empty($json['keys'])) throw new Exception("Struct error - object has no keys defined");
  84. if (empty($json['keys']['PRIMARY'])) throw new Exception("Struct error - object has no PRIMARY key defined");
  85. if (empty($json['keys']['PRIMARY']['fields'])) throw new Exception("Struct error - object PRIMARY key has no fields defined");
  86. if (is_array($json['keys']['PRIMARY']['fields'])) throw new Exception("Not implemented - multiple fields primary key");
  87. $primaryKey = $json['keys']['PRIMARY']['fields'];
  88. if (empty($json['fields'][$primaryKey])) throw new Exception("Struct error - object priary key field not defined in fields list");
  89. $type = V::get('type', '', $json['fields'][$primaryKey]);
  90. if (empty($type)) throw new Exception("Struct error - object primary field type not defined");
  91. if ('int' != $type) throw new Exception("Not implemented - primary key field type is no int");
  92. return $type;
  93. }
  94. public static function getCoreObjectFromFile($objectName) {
  95. $objectFileName = str_replace("/", '-', $objectName);
  96. $filePath = APP_PATH_SCHEMA . "/gui/core/{$objectFileName}.json";
  97. if (!file_exists($filePath)) throw new Exception("File not exists {$filePath}", 404);
  98. $json = file_get_contents($filePath);
  99. DBG::_('DBG', '>1', "{$objectName} filePath", $filePath, __CLASS__, __FUNCTION__, __LINE__);
  100. DBG::_('DBG', '>1', "{$objectName} file content", $json, __CLASS__, __FUNCTION__, __LINE__);
  101. $json = @json_decode($json, $assoc = true);
  102. DBG::_('DBG', '>1', "{$objectName} json_last_error()", json_last_error(), __CLASS__, __FUNCTION__, __LINE__);
  103. if (null == $json && 0 !== json_last_error()) throw new Exception("Parse json error for object '{$objectName}': " . json_last_error());
  104. if (empty($json['parent_object'])) return $json;
  105. $jsonParent = array();
  106. $parent = (is_array($json['parent_object']))? end($json['parent_object']) : $json['parent_object'];
  107. $jsonParent = self::getCoreObjectFromFile($parent);
  108. return array_merge_recursive($jsonParent, $json);
  109. }
  110. public static function getCoreObjectList() {
  111. $objectList = array();
  112. $files = glob(APP_PATH_SCHEMA . "/gui/core/*.json", GLOB_NOSORT);
  113. //DBG::_(true, true, "files", $files, __CLASS__, __FUNCTION__, __LINE__);
  114. foreach ($files as $filePath) {
  115. $fileName = basename($filePath);
  116. $objName = substr($fileName, 0, -5);// remove ext '.json'
  117. $objectList[] = $objName;
  118. }
  119. return $objectList;
  120. }
  121. public static function checkInstall($json) {
  122. self::checkInstanceTable($json);
  123. self::checkRefTables($json);
  124. self::checkActivityLogTable($json);
  125. }
  126. public static function checkInstanceTable($json) {
  127. $mainTableName = self::getMainTableName($json);
  128. $instanceTableName = "{$mainTableName}__INSTANCE_CLOSURE";
  129. $primaryKeyType = "int(11)";// TODO: fetch from main table - default int(11)
  130. $storageName = self::getStorageName($json);
  131. $storagePdo = DB::getStorage($storageName);
  132. try {
  133. $mainTableStruct = $storagePdo->getTableStruct($mainTableName);
  134. } catch (Exception $e) {
  135. throw $e;
  136. // TODO: if (404 != $e->getCode()) -> CREATE BASE TABLE -- mv to TODO: checkMainTableInstall($json)
  137. }
  138. try {
  139. $instanceTableStruct = DB::getStorage()->getTableStruct($instanceTableName);
  140. } catch (Exception $e) {
  141. if (404 != $e->getCode()) throw $e;
  142. $instanceTableStruct = null;
  143. }
  144. $sqlCreate = "
  145. CREATE TABLE IF NOT EXISTS `{$instanceTableName}` (
  146. `PRIMARY_KEY` {$primaryKeyType} NOT NULL,
  147. `INSTANCE` varchar(124) NOT NULL,
  148. `PARENT_INSTANCE` varchar(124) DEFAULT NULL,
  149. `PARENT_DEPTH` int(11) NOT NULL,
  150. KEY `PRIMARY_KEY` (`PRIMARY_KEY`)
  151. ) ENGINE=MyISAM DEFAULT CHARSET=latin2
  152. ";
  153. DBG::_('DBG', '>2', "mainTableStruct", $mainTableStruct, __CLASS__, __FUNCTION__, __LINE__);
  154. DBG::_('DBG', '>2', "instanceTableStruct", $instanceTableStruct, __CLASS__, __FUNCTION__, __LINE__);
  155. DBG::_('DBG', '>2', "sqlCreate", $sqlCreate, __CLASS__, __FUNCTION__, __LINE__);
  156. if (!$instanceTableStruct) {
  157. DB::getPDO()->exec($sqlCreate);
  158. }
  159. try {
  160. $instanceTableStruct = DB::getStorage()->getTableStruct($instanceTableName);
  161. } catch (Exception $e) {
  162. throw new Exception("Wystąpiły błędy podczas tworzenie tabeli instancji dla {$mainTableName}");
  163. }
  164. DBG::_('DBG', '>2', "OK instance table exists - instanceTableStruct", $instanceTableStruct, __CLASS__, __FUNCTION__, __LINE__);
  165. }
  166. public static function checkRefTables($json) {
  167. // TODO: should go recurse or create on demand? - create on demand
  168. $objectName = self::getName($json);
  169. $mainTableName = self::getMainTableName($json);
  170. $objectPrimaryKeyType = self::getPrimaryKeyType($json);
  171. if (empty($json['fields'])) return;
  172. $toCreateRefTables = array();// ref table name => target primary key type
  173. foreach ($json['fields'] as $fldName => $fld) {
  174. if ('ref' != V::get('type', '', $fld)) continue;
  175. // [ref_LOCAL_EMAIL] => Array(
  176. // [label] => Adresy email lokalnej poczty
  177. // [type] => ref
  178. // [ref_config] => Array(
  179. // [name] => user__ref__local_email
  180. // [target] => local_email
  181. $refConf = V::get('ref_config', '', $fld);
  182. if (!$refConf) throw new Exception("Struct error - ref config not defined for field {$objectName}/{$fldName}");
  183. $refTarget = V::get('target', '', $refConf);
  184. if (!$refConf) throw new Exception("Struct error - ref target not defined for field {$objectName}/{$fldName}");
  185. $jsonTarget = OBJ::getCoreObjectFromFile($refTarget);
  186. $targetMainTableName = self::getMainTableName($jsonTarget);
  187. $refTableName = "{$mainTableName}__REF__{$targetMainTableName}";
  188. $targetPrimaryKeyType = self::getPrimaryKeyType($jsonTarget);
  189. DBG::_('DBG', '>1', "create table `{$refTableName}` ( `PRIMARY_KEY` {$objectPrimaryKeyType}, `REMOTE_PRIMARY_KEY` {$targetPrimaryKeyType}) ", null, __CLASS__, __FUNCTION__, __LINE__);
  190. $toCreateRefTables[ $refTableName ] = $targetPrimaryKeyType;
  191. }
  192. foreach ($toCreateRefTables as $refTableName => $targetPrimaryKeyType) {
  193. // `{tbl_name}__REF__{target_table_name}`: `PRIMARY_KEY`, `REMOTE_PRIMARY_KEY`
  194. $sqlCreate = "
  195. CREATE TABLE IF NOT EXISTS `{$refTableName}` (
  196. `PRIMARY_KEY` {$objectPrimaryKeyType} NOT NULL,
  197. `REMOTE_PRIMARY_KEY` {$targetPrimaryKeyType} NOT NULL,
  198. KEY `PRIMARY_KEY` (`PRIMARY_KEY`),
  199. KEY `REMOTE_PRIMARY_KEY` (`REMOTE_PRIMARY_KEY`)
  200. ) ENGINE=MyISAM DEFAULT CHARSET=latin2
  201. ";
  202. DB::getPDO()->exec($sqlCreate);
  203. try {
  204. $refTableStruct = DB::getStorage()->getTableStruct($refTableName);
  205. } catch (Exception $e) {
  206. throw new Exception("Wystąpiły błędy podczas tworzenie tabeli ref {$refTableName}");
  207. }
  208. }
  209. }
  210. public static function checkActivityLogTable($json) {
  211. // `{tbl_name}__ACTIVITY_LOG`:
  212. // - `ID` int PRIMARY auto_increment - used in update to check conflicts
  213. // - `PRIMARY_KEY` - same type as root table primary key
  214. // - `ACTION_USER` varchar(20)
  215. // - `ACTION_DATE` datetime
  216. // - `ACTION_TYPE` enum('CREATE', 'UPDATE', 'DELETE')
  217. // - `LOG` text - json with action details
  218. // - `ERRORS` text - json with errors
  219. $mainTableName = self::getMainTableName($json);
  220. $histTableName = "{$mainTableName}__ACTIVITY_LOG";
  221. $primaryKeyType = self::getPrimaryKeyType($json);// default "int";
  222. $storageName = self::getStorageName($json);
  223. $storagePdo = DB::getStorage($storageName);
  224. $mainTableStruct = $storagePdo->getTableStruct($mainTableName);
  225. try {
  226. $histTableStruct = DB::getStorage()->getTableStruct($histTableName);
  227. } catch (Exception $e) {
  228. if (404 != $e->getCode()) throw $e;
  229. $histTableStruct = null;
  230. }
  231. $sqlCreate = "
  232. CREATE TABLE IF NOT EXISTS `{$histTableName}` (
  233. `ID` int(11) NOT NULL AUTO_INCREMENT,
  234. `PRIMARY_KEY` {$primaryKeyType} NOT NULL,
  235. `ACTION_USER` varchar(20) NOT NULL,
  236. `ACTION_DATE` datetime NOT NULL,
  237. `ACTION_TYPE` enum('CREATE','UPDATE','DELETE') NOT NULL,
  238. `LOG` text NOT NULL,
  239. `ERRORS` text NOT NULL,
  240. PRIMARY KEY (`ID`),
  241. KEY `PRIMARY_KEY` (`PRIMARY_KEY`)
  242. ) ENGINE=MyISAM DEFAULT CHARSET=latin2
  243. ";
  244. DBG::_('DBG', '>2', "mainTableStruct", $mainTableStruct, __CLASS__, __FUNCTION__, __LINE__);
  245. DBG::_('DBG', '>2', "instanceTableStruct", $histTableStruct, __CLASS__, __FUNCTION__, __LINE__);
  246. DBG::_('DBG', '>2', "sqlCreate", $sqlCreate, __CLASS__, __FUNCTION__, __LINE__);
  247. if (!$histTableStruct) {
  248. DB::getPDO()->exec($sqlCreate);
  249. }
  250. try {
  251. $histTableStruct = DB::getStorage()->getTableStruct($histTableName);
  252. } catch (Exception $e) {
  253. throw new Exception("Wystąpiły błędy podczas tworzenie tabeli hist dla {$mainTableName}");
  254. }
  255. DBG::_('DBG', '>2', "OK hist table exists - histTableStruct", $histTableStruct, __CLASS__, __FUNCTION__, __LINE__);
  256. }
  257. public static function parseAll() {
  258. DBG::activate();
  259. $mapInheritance = array();
  260. $objList = self::getCoreObjectList();
  261. foreach ($objList as $objName) {
  262. $json = self::getCoreObjectFromFile($objName);
  263. $parentList = OBJ::getParentList($json);
  264. DBG::_(true, true, "obj({$objName}) parentList:", $parentList, __CLASS__, __FUNCTION__, __LINE__);
  265. if (!empty($parentList)) {
  266. /*
  267. obj(stanowisko) parentList = Array(
  268. [0] => group
  269. [1] => zasob
  270. [2] => default_db/crm_lista_zasobow
  271. */
  272. $rootTable = array_pop($parentList);
  273. if (!array_key_exists($rootTable, $mapInheritance)) $mapInheritance[$rootTable] = array();
  274. array_unshift($parentList, $objName);
  275. foreach ($parentList as $parentName) {
  276. if (!in_array($parentName, $mapInheritance[$rootTable])) $mapInheritance[$rootTable][] = $parentName;
  277. }
  278. }
  279. DBG::_(true, true, "mapInheritance:", $mapInheritance, __CLASS__, __FUNCTION__, __LINE__);
  280. }
  281. }
  282. }