ITopConsultant.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. <?php
  2. //
  3. // ITop consultant home page
  4. // tool box
  5. // object model analysis
  6. // DB integrity check and repair
  7. //
  8. function sexyclass($sClass, $sBaseArgs)
  9. {
  10. return "Class <a href=\"?$sBaseArgs&todo=showclass&class=$sClass\">$sClass</a>";
  11. }
  12. function sexyclasslist($aClasses, $sBaseArgs)
  13. {
  14. if (count($aClasses) == 0) return "";
  15. $aRes = array();
  16. foreach($aClasses as $sClass)
  17. {
  18. $aRes[] = sexyclass($sClass, $sBaseArgs);
  19. }
  20. return ("'".implode("', '", $aRes)."'");
  21. }
  22. function ShowClass($sClass, $sBaseArgs)
  23. {
  24. if (!MetaModel::IsValidClass($sClass))
  25. {
  26. echo "Invalid class, expecting a value in {".sexyclasslist(MetaModel::GetClasses(), $sBaseArgs)."}<br/>\n";
  27. return;
  28. }
  29. // en recursif jusque "": MetaModel::GetParentPersistentClass($sClass)
  30. $aProps["Root class"] = MetaModel::GetRootClass($sClass);
  31. $aProps["Parent classes"] = sexyclasslist(MetaModel::EnumParentClasses($sClass), $sBaseArgs);
  32. $aProps["Child classes"] = sexyclasslist(MetaModel::EnumChildClasses($sClass), $sBaseArgs);
  33. $aProps["Subclasses (children + pure PHP)"] = sexyclasslist(MetaModel::GetSubclasses($sClass), $sBaseArgs);
  34. $aProps["Description"] = MetaModel::GetClassDescription($sClass);
  35. $aProps["Autoincrement id?"] = MetaModel::IsAutoIncrementKey($sClass);
  36. $aProps["Key label"] = MetaModel::GetKeyLabel($sClass);
  37. $aProps["Name attribute"] = MetaModel::GetNameAttributeCode($sClass);
  38. $aProps["Reconciliation keys"] = implode(", ", MetaModel::GetReconcKeys($sClass));
  39. $aProps["DB key column"] = MetaModel::DBGetKey($sClass);
  40. $aProps["DB class column"] = MetaModel::DBGetClassField($sClass);
  41. $aProps["Is standalone?"] = MetaModel::IsStandaloneClass($sClass);
  42. foreach (MetaModel::ListAttributeDefs($sClass) as $oAttDef)
  43. {
  44. $aAttProps = array();
  45. $aAttProps["Direct field"] = $oAttDef->IsDirectField();
  46. $aAttProps["External key"] = $oAttDef->IsExternalKey();
  47. $aAttProps["External field"] = $oAttDef->IsExternalField();
  48. $aAttProps["Link set"] = $oAttDef->IsLinkSet();
  49. $aAttProps["Code"] = $oAttDef->GetCode();
  50. $aAttProps["Label"] = $oAttDef->GetLabel();
  51. $aAttProps["Description"] = $oAttDef->GetDescription();
  52. $oValDef = $oAttDef->GetValuesDef();
  53. if (is_object($oValDef))
  54. {
  55. //$aAttProps["Allowed values"] = $oValDef->Describe();
  56. $aAttProps["Allowed values"] = "... object of class ".get_class($oValDef);
  57. }
  58. else
  59. {
  60. $aAttProps["Allowed values"] = "";
  61. }
  62. // MetaModel::IsAttributeInZList($sClass, $sListCode, $sAttCodeOrFltCode)
  63. }
  64. // $aProps["Description"] = MetaModel::DBGetTable($sClass, $sAttCode = null)
  65. $aAttributes = array();
  66. foreach (MetaModel::GetClassFilterDefs($sClass) as $oFilterDef)
  67. {
  68. $aAttProps = array();
  69. $aAttProps["Label"] = $oFilterDef->GetLabel();
  70. $aOpDescs = array();
  71. foreach ($oFilterDef->GetOperators() as $sOpCode => $sOpDescription)
  72. {
  73. $sIsTheLooser = ($sOpCode == $oFilterDef->GetLooseOperator()) ? " (loose search)" : "";
  74. $aOpDescs[] = "$sOpCode ($sOpDescription)$sIsTheLooser";
  75. }
  76. $aAttProps["Operators"] = implode(" / ", $aOpDescs);
  77. $aAttributes[] = $aAttProps;
  78. }
  79. $aProps["Filters"] = MyHelpers::make_table_from_assoc_array($aAttributes);
  80. foreach ($aProps as $sKey => $sDesc)
  81. {
  82. echo "<h4>$sKey</h4>\n";
  83. echo "<p>$sDesc</p>\n";
  84. }
  85. }
  86. function ShowBizModel($sBaseArgs)
  87. {
  88. echo "<ul>\n";
  89. foreach(MetaModel::GetClasses() as $sClass)
  90. {
  91. echo "<li>".sexyclass($sClass, $sBaseArgs)."</li>\n";
  92. }
  93. echo "</ul>\n";
  94. }
  95. function ShowZLists($sBaseArgs)
  96. {
  97. $aData = array();
  98. // 1 row per class, header made after the first row keys
  99. //
  100. foreach(MetaModel::GetClasses() as $sClass)
  101. {
  102. $aRow = array();
  103. $aRow["_"] = $sClass;
  104. foreach (MetaModel::EnumZLists() as $sListCode)
  105. {
  106. $aRow[$sListCode] = implode(", ", MetaModel::GetZListItems($sClass, $sListCode));
  107. }
  108. $aData[] = $aRow;
  109. }
  110. echo MyHelpers::make_table_from_assoc_array($aData);
  111. }
  112. function ShowDatabaseInfo()
  113. {
  114. $aTables = array();
  115. foreach (CMDBSource::EnumTables() as $sTable)
  116. {
  117. $aTableData = array();
  118. $aTableData["Name"] = $sTable;
  119. $aTableDesc = CMDBSource::GetTableInfo($sTable);
  120. $aTableData["Fields"] = MyHelpers::make_table_from_assoc_array($aTableDesc["Fields"]);
  121. $aTables[$sTable] = $aTableData;
  122. }
  123. echo MyHelpers::make_table_from_assoc_array($aTables);
  124. }
  125. function CreateDB()
  126. {
  127. $sRes = "<p>Creating the DB...</p>\n";
  128. if (MetaModel::DBExists(false))
  129. {
  130. $sRes .= "<p>It appears that the DB already exists (at least one table).</p>\n";
  131. }
  132. else
  133. {
  134. MetaModel::DBCreate();
  135. $sRes .= "<p>Done!</p>\n";
  136. }
  137. return $sRes;
  138. }
  139. function DebugQuery($sConfigFile)
  140. {
  141. $sQuery = ReadParam("oql");
  142. if (empty($sQuery))
  143. {
  144. $sQueryTemplate = "SELECT Foo AS f JOIN Dummy AS D ON d.spirit = f.id WHERE f.age * d.height > TO_DAYS(NOW()) OR d.alive";
  145. }
  146. else
  147. {
  148. $sQueryTemplate = $sQuery;
  149. }
  150. echo "<form>\n";
  151. echo "<input type=\"hidden\" name=\"todo\" value=\"debugquery\">\n";
  152. echo "<input type=\"hidden\" name=\"config\" value=\"$sConfigFile\">\n";
  153. echo "<textarea name=\"oql\" rows=\"10\" cols=\"120\" name=\"csvdata\" wrap=\"soft\">$sQueryTemplate</textarea>\n";
  154. echo "<input type=\"submit\" name=\"foo\">\n";
  155. echo "</form>\n";
  156. if (empty($sQuery)) return;
  157. echo "<h1>Testing query</h1>\n";
  158. echo "<p>$sQuery</p>\n";
  159. echo "<h1>Follow up the query build</h1>\n";
  160. MetaModel::StartDebugQuery();
  161. $oFlt = DBObjectSearch::FromOQL($sQuery);
  162. echo "<p>To OQL: ".$oFlt->ToOQL()."</p>";
  163. $sSQL = MetaModel::MakeSelectQuery($oFlt);
  164. MetaModel::StopDebugQuery();
  165. echo "<h1>Explain</h1>\n";
  166. echo "<table border=\"1\">\n";
  167. foreach (CMDBSource::ExplainQuery($sSQL) as $aRow)
  168. {
  169. echo " <tr>\n";
  170. echo " <td>".implode('</td><td>', $aRow)."</td>\n";
  171. echo " </tr>\n";
  172. }
  173. echo "</table>\n";
  174. echo "<h1>Results</h1>\n";
  175. $oSet = new CMDBObjectSet($oFlt);
  176. echo $oSet; // __toString()
  177. }
  178. function DumpDatabase()
  179. {
  180. $aData = MetaModel::DBDump();
  181. foreach ($aData as $sTable => $aRows)
  182. {
  183. echo "<h1>".htmlentities($sTable)."</h1>\n";
  184. if (count($aRows) == 0)
  185. {
  186. echo "<p>no data</p>\n";
  187. }
  188. else
  189. {
  190. echo "<p>".count($aRows)." row(s)</p>\n";
  191. // Table header
  192. echo "<table border=\"1\">\n";
  193. echo "<tr>\n";
  194. foreach (reset($aRows) as $key => $value)
  195. {
  196. echo "<th>".htmlentities($key)."</th>";
  197. }
  198. echo "</tr>\n";
  199. // Table body
  200. foreach ($aRows as $aRow)
  201. {
  202. echo "<tr>\n";
  203. foreach ($aRow as $key => $value)
  204. {
  205. echo "<td>".htmlentities($value)."</td>";
  206. }
  207. echo "</tr>\n";
  208. }
  209. echo "</table>\n";
  210. }
  211. }
  212. }
  213. /////////////////////////////////////////////////////////////////////////////////////
  214. // Helper functions
  215. /////////////////////////////////////////////////////////////////////////////////////
  216. function printMenu($sConfigFile)
  217. {
  218. $sClassCount = count(MetaModel::GetClasses());
  219. $bHasDB = MetaModel::DBExists(false); // no need to be complete to consider that something already exists
  220. $sUrl = "?config=".urlencode($sConfigFile);
  221. echo "<div style=\"background-color:eeeeee; padding:10px;\">\n";
  222. echo "<h2>phpMyORM integration sandbox</h2>\n";
  223. echo "<h4>Target database: $sConfigFile</h4>\n";
  224. echo "<p>$sClassCount classes referenced in the model</p>\n";
  225. echo "<ul>";
  226. echo " <li><a href=\"$sUrl&todo=checkdictionary\">Dictionary</a></li>";
  227. echo " <li><a href=\"$sUrl&todo=checkmodel\">Biz model consistency</a></li>";
  228. echo " <li><a href=\"$sUrl&todo=showzlists\">Show ZLists</a></li>";
  229. echo " <li><a href=\"$sUrl&todo=showbizmodel\">Browse business model</a></li>";
  230. if ($bHasDB)
  231. {
  232. echo " <li><a href=\"$sUrl&todo=checkmodeltodb\">Concordance between Biz model and DB format</a></li>";
  233. echo " <li><a href=\"$sUrl&todo=checkdb\">DB integrity check</a></li>";
  234. echo " <li><a href=\"$sUrl&todo=userrightssetup\">Setup userrights (init DB)</a></li>";
  235. echo " <li><a href=\"$sUrl&todo=checkall\">Check business model, DB format and data integrity</a></li>";
  236. echo " <li><a href=\"$sUrl&todo=showtables\">Show Tables</a></li>";
  237. echo " <li><a href=\"$sUrl&todo=debugquery\">Test an OQL query (debug)</a></li>";
  238. echo " <li><a href=\"$sUrl&todo=dumpdb\">Dump database</a></li>";
  239. // echo " <li>".htmlentities($sUrl)."&amp;<b>todo=execsql</b>&amp;<b>sql=xxx</b>, to execute a specific sql request</li>";
  240. }
  241. else
  242. {
  243. echo " <li><a href=\"$sUrl&todo=createdb\">Create the DB</a></li>";
  244. }
  245. echo "</ul>";
  246. echo "</div>\n";
  247. }
  248. function printConfigList()
  249. {
  250. echo "<h2>phpMyORM integration sandbox</h2>\n";
  251. echo "<h4>Configuration sumary</h4>\n";
  252. $sBasePath = '..';
  253. $aConfigs = array();
  254. foreach(scandir($sBasePath) as $sFile)
  255. {
  256. if (preg_match('/^config-.+\\.php$/', $sFile)) $aConfigs[] = $sFile;
  257. }
  258. $aConfigDetails = array();
  259. foreach ($aConfigs as $sConfigFile)
  260. {
  261. $sRealPath = $sBasePath.'/'.$sConfigFile;
  262. $oConfig = new Config($sRealPath);
  263. $sAppModules = implode(', ', $oConfig->GetAppModules());
  264. $sDataModels = implode(', ', $oConfig->GetDataModels());
  265. $sAddons = implode(', ', $oConfig->GetAddons());
  266. $sDBSubname = (strlen($oConfig->GetDBSubname()) > 0) ? '('.$oConfig->GetDBSubname().')' : '';
  267. $sUrl = "?config=".urlencode($sRealPath);
  268. $sHLink = "<a href=\"$sUrl\">Manage <b>$sConfigFile</b></a></br>\n";
  269. $aConfigDetails[] = array('Config'=>$sHLink, 'Application'=>$sAppModules, 'Data models'=>$sDataModels, 'Addons'=>$sAddons, 'Database'=>$oConfig->GetDBHost().'/'.$oConfig->GetDBName().$sDBSubname.' as '.$oConfig->GetDBUser());
  270. }
  271. echo MyHelpers::make_table_from_assoc_array($aConfigDetails);
  272. }
  273. function ReadParam($sName, $defaultValue = "")
  274. {
  275. return isset($_REQUEST[$sName]) ? $_REQUEST[$sName] : $defaultValue;
  276. }
  277. function ReadMandatoryParam($sName)
  278. {
  279. $value = ReadParam($sName, null);
  280. if (is_null($value))
  281. {
  282. echo "<p>Missing mandatory argument <b>$sName</b></p>";
  283. exit;
  284. }
  285. return $value;
  286. }
  287. function DisplayDBFormatIssues($aErrors, $aSugFix, $sRepairUrl = "", $sSQLStatementArgName = "")
  288. {
  289. $aSQLFixes = array(); // each and every SQL repair statement
  290. if (count($aErrors) > 0)
  291. {
  292. echo "<div style=\"width:100%;padding:10px;background:#FFAAAA;display:;\">";
  293. echo "<h1>Wrong Database format</h1>\n";
  294. echo "<p>The current database is not consistent with the given business model. Please investigate.</p>\n";
  295. foreach ($aErrors as $sClass => $aTarget)
  296. {
  297. echo "<p>Wrong declaration (or DB format ?) for class <b>$sClass</b></p>\n";
  298. echo "<ul class=\"treeview\">\n";
  299. $i = 0;
  300. foreach ($aTarget as $sTarget => $aMessages)
  301. {
  302. echo "<p>Wrong declaration for attribute <b>$sTarget</b></p>\n";
  303. $sMsg = implode(' AND ', $aMessages);
  304. if (!empty($sRepairUrl))
  305. {
  306. $aSQLFixes = array_merge($aSQLFixes, $aSugFix[$sClass][$sTarget]);
  307. $sSQLFixes = implode('; ', $aSugFix[$sClass][$sTarget]);
  308. $sUrl = "$sRepairUrl&$sSQLStatementArgName=".urlencode($sSQLFixes);
  309. echo "<li>$sMsg (<a href=\"$sUrl\" title=\"".htmlentities($sSQLFixes)."\" target=\"_blank\">fix it now!</a>)</li>\n";
  310. }
  311. else
  312. {
  313. echo "<li>$sMsg (".htmlentities($sSQLFixes).")</li>\n";
  314. }
  315. $i++;
  316. }
  317. echo "</ul>\n";
  318. }
  319. if (count($aSQLFixes) > 1)
  320. {
  321. MetaModel::DBShowApplyForm($sRepairUrl, $sSQLStatementArgName, $aSQLFixes);
  322. }
  323. echo "<p>Aborting...</p>\n";
  324. echo "</div>\n";
  325. exit;
  326. }
  327. }
  328. /////////////////////////////////////////////////////////////////////////////////////////////////
  329. //
  330. // M a i n P r o g r a m
  331. //
  332. /////////////////////////////////////////////////////////////////////////////////////////////////
  333. require_once('../core/cmdbobject.class.inc.php');
  334. $sConfigFile = ReadParam("config", '');
  335. if (empty($sConfigFile))
  336. {
  337. printConfigList();
  338. exit;
  339. }
  340. MetaModel::Startup($sConfigFile, true); // allow missing DB
  341. $sBaseArgs = "config=".urlencode($sConfigFile);
  342. $sTodo = ReadParam("todo", "");
  343. if ($sTodo == 'execsql')
  344. {
  345. $sSql = ReadMandatoryParam("sql");
  346. $aSql = explode("##SEP##", $sSql);
  347. $sConfirm = ReadParam("confirm");
  348. if (empty($sConfirm) || ($sConfirm != "Yes"))
  349. {
  350. echo "<form method=\"post\" action=\"?$sBaseArgs\">\n";
  351. echo "<input type=\"hidden\" name=\"todo\" value=\"execsql\">\n";
  352. echo "<input type=\"hidden\" name=\"sql\" value=\"".htmlentities($sSql)."\">\n";
  353. if (count($aSql) == 1)
  354. {
  355. echo "Do you confirm that you want to execute this command: <b>".htmlentities($aSql[0])."</b> ?</br>\n";
  356. }
  357. else
  358. {
  359. $sAllQueries = "<li>".implode("</li>\n<li>", $aSql)."</li>\n";
  360. echo "Please confirm that you want to execute these commands: <ul style=\"font-size: smaller;\">".$sAllQueries."</ul>\n";
  361. }
  362. echo "<input type=\"submit\" name=\"confirm\" value=\"Yes\">\n";
  363. echo "</form>\n";
  364. }
  365. else
  366. {
  367. foreach ($aSql as $sOneSingleSql)
  368. {
  369. echo "Executing command: <b>$sOneSingleSql</b></br>\n";
  370. CMDBSource::Query($sOneSingleSql);
  371. echo "... done!</br>\n";
  372. }
  373. }
  374. }
  375. else
  376. {
  377. $sBaseUrl = "?$sBaseArgs&todo=execsql";
  378. switch ($sTodo)
  379. {
  380. case "createdb":
  381. // do NOT print the menu, because it will change...
  382. break;
  383. default:
  384. printMenu($sConfigFile);
  385. }
  386. switch ($sTodo)
  387. {
  388. case "showtables":
  389. ShowDatabaseInfo();
  390. break;
  391. case "showbizmodel":
  392. ShowBizModel($sBaseArgs);
  393. break;
  394. case "showclass":
  395. $sClass = ReadMandatoryParam("class");
  396. ShowClass($sClass, $sBaseArgs);
  397. break;
  398. case "showzlists":
  399. ShowZLists($sBaseArgs);
  400. break;
  401. case "debugquery":
  402. DebugQuery($sConfigFile);
  403. break;
  404. case "createdb":
  405. $sRes = CreateDB();
  406. // As the menu depends on the existence of the DB, we have to do display it right after the job is done
  407. printMenu($sConfigFile);
  408. echo $sRes;
  409. break;
  410. case "checkdictionary":
  411. echo "Dictionary template...</br>\n";
  412. echo "<pre>\n";
  413. echo MetaModel::MakeDictionaryTemplate();
  414. echo "</pre>\n";
  415. break;
  416. case "checkmodel":
  417. echo "Check definitions...</br>\n";
  418. MetaModel::CheckDefinitions();
  419. echo "done...</br>\n";
  420. break;
  421. case "checkmodeltodb":
  422. echo "Check DB format...</br>\n";
  423. list($aErrors, $aSugFix) = MetaModel::DBCheckFormat();
  424. DisplayDBFormatIssues($aErrors, $aSugFix, $sBaseUrl, $sSQLStatementArgName = "sql");
  425. echo "done...</br>\n";
  426. break;
  427. case "checkdb":
  428. echo "Check DB integrity...</br>\n";
  429. MetaModel::DBCheckIntegrity($sBaseUrl, "sql");
  430. echo "done...</br>\n";
  431. break;
  432. case "dumpdb":
  433. echo "Dump DB data...</br>\n";
  434. DumpDatabase();
  435. echo "done...</br>\n";
  436. break;
  437. case "userrightssetup":
  438. echo "Setup user rights module (init DB)...</br>\n";
  439. UserRights::Setup();
  440. echo "done...</br>\n";
  441. break;
  442. case "checkall":
  443. echo "Check definitions...</br>\n";
  444. MetaModel::CheckDefinitions();
  445. echo "done...</br>\n";
  446. echo "Check DB format...</br>\n";
  447. list($aErrors, $aSugFix) = MetaModel::DBCheckFormat();
  448. DisplayDBFormatIssues($aErrors, $aSugFix, $sBaseUrl, $sSQLStatementArgName = "sql");
  449. echo "done...</br>\n";
  450. echo "Check DB integrity...</br>\n";
  451. MetaModel::DBCheckIntegrity($sBaseUrl, "sql");
  452. echo "done...</br>\n";
  453. break;
  454. }
  455. }
  456. ?>