Designer.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Holds the PhpMyAdmin\Database\Designer class
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. declare(strict_types=1);
  9. namespace PhpMyAdmin\Database;
  10. use PhpMyAdmin\DatabaseInterface;
  11. use PhpMyAdmin\Message;
  12. use PhpMyAdmin\Plugins;
  13. use PhpMyAdmin\Plugins\SchemaPlugin;
  14. use PhpMyAdmin\Relation;
  15. use PhpMyAdmin\Template;
  16. use PhpMyAdmin\Util;
  17. use PhpMyAdmin\Database\Designer\DesignerTable;
  18. use stdClass;
  19. /**
  20. * Set of functions related to database designer
  21. *
  22. * @package PhpMyAdmin
  23. */
  24. class Designer
  25. {
  26. /**
  27. * @var DatabaseInterface
  28. */
  29. private $dbi;
  30. /**
  31. * @var Relation
  32. */
  33. private $relation;
  34. /**
  35. * @var Template
  36. */
  37. public $template;
  38. /**
  39. * Designer constructor.
  40. *
  41. * @param DatabaseInterface $dbi DatabaseInterface object
  42. * @param Relation $relation Relation instance
  43. * @param Template $template Template instance
  44. */
  45. public function __construct(DatabaseInterface $dbi, Relation $relation, Template $template)
  46. {
  47. $this->dbi = $dbi;
  48. $this->relation = $relation;
  49. $this->template = $template;
  50. }
  51. /**
  52. * Function to get html for displaying the page edit/delete form
  53. *
  54. * @param string $db database name
  55. * @param string $operation 'edit' or 'delete' depending on the operation
  56. *
  57. * @return string html content
  58. */
  59. public function getHtmlForEditOrDeletePages($db, $operation)
  60. {
  61. $cfgRelation = $this->relation->getRelationsParam();
  62. return $this->template->render('database/designer/edit_delete_pages', [
  63. 'db' => $db,
  64. 'operation' => $operation,
  65. 'pdfwork' => $cfgRelation['pdfwork'],
  66. 'pages' => $this->getPageIdsAndNames($db),
  67. ]);
  68. }
  69. /**
  70. * Function to get html for displaying the page save as form
  71. *
  72. * @param string $db database name
  73. *
  74. * @return string html content
  75. */
  76. public function getHtmlForPageSaveAs($db)
  77. {
  78. $cfgRelation = $this->relation->getRelationsParam();
  79. return $this->template->render('database/designer/page_save_as', [
  80. 'db' => $db,
  81. 'pdfwork' => $cfgRelation['pdfwork'],
  82. 'pages' => $this->getPageIdsAndNames($db),
  83. ]);
  84. }
  85. /**
  86. * Retrieve IDs and names of schema pages
  87. *
  88. * @param string $db database name
  89. *
  90. * @return array array of schema page id and names
  91. */
  92. private function getPageIdsAndNames($db)
  93. {
  94. $result = [];
  95. $cfgRelation = $this->relation->getRelationsParam();
  96. if (! $cfgRelation['pdfwork']) {
  97. return $result;
  98. }
  99. $page_query = "SELECT `page_nr`, `page_descr` FROM "
  100. . Util::backquote($cfgRelation['db']) . "."
  101. . Util::backquote($cfgRelation['pdf_pages'])
  102. . " WHERE db_name = '" . $this->dbi->escapeString($db) . "'"
  103. . " ORDER BY `page_descr`";
  104. $page_rs = $this->relation->queryAsControlUser(
  105. $page_query,
  106. false,
  107. DatabaseInterface::QUERY_STORE
  108. );
  109. while ($curr_page = $this->dbi->fetchAssoc($page_rs)) {
  110. $result[intval($curr_page['page_nr'])] = $curr_page['page_descr'];
  111. }
  112. return $result;
  113. }
  114. /**
  115. * Function to get html for displaying the schema export
  116. *
  117. * @param string $db database name
  118. * @param int $page the page to be exported
  119. *
  120. * @return string
  121. */
  122. public function getHtmlForSchemaExport($db, $page)
  123. {
  124. /* Scan for schema plugins */
  125. /** @var SchemaPlugin[] $export_list */
  126. $export_list = Plugins::getPlugins(
  127. "schema",
  128. 'libraries/classes/Plugins/Schema/',
  129. null
  130. );
  131. /* Fail if we didn't find any schema plugin */
  132. if (empty($export_list)) {
  133. return Message::error(
  134. __('Could not load schema plugins, please check your installation!')
  135. )->getDisplay();
  136. }
  137. return $this->template->render('database/designer/schema_export', [
  138. 'db' => $db,
  139. 'page' => $page,
  140. 'export_list' => $export_list,
  141. ]);
  142. }
  143. /**
  144. * Returns array of stored values of Designer Settings
  145. *
  146. * @return array stored values
  147. */
  148. private function getSideMenuParamsArray()
  149. {
  150. $params = [];
  151. $cfgRelation = $this->relation->getRelationsParam();
  152. if ($cfgRelation['designersettingswork']) {
  153. $query = 'SELECT `settings_data` FROM '
  154. . Util::backquote($cfgRelation['db']) . '.'
  155. . Util::backquote($cfgRelation['designer_settings'])
  156. . ' WHERE ' . Util::backquote('username') . ' = "'
  157. . $GLOBALS['dbi']->escapeString($GLOBALS['cfg']['Server']['user'])
  158. . '";';
  159. $result = $this->dbi->fetchSingleRow($query);
  160. if (is_array($result)) {
  161. $params = json_decode((string) $result['settings_data'], true);
  162. }
  163. }
  164. return $params;
  165. }
  166. /**
  167. * Returns class names for various buttons on Designer Side Menu
  168. *
  169. * @return array class names of various buttons
  170. */
  171. public function returnClassNamesFromMenuButtons()
  172. {
  173. $classes_array = [];
  174. $params_array = $this->getSideMenuParamsArray();
  175. if (isset($params_array['angular_direct'])
  176. && $params_array['angular_direct'] == 'angular'
  177. ) {
  178. $classes_array['angular_direct'] = 'M_butt_Selected_down';
  179. } else {
  180. $classes_array['angular_direct'] = 'M_butt';
  181. }
  182. if (isset($params_array['snap_to_grid'])
  183. && $params_array['snap_to_grid'] == 'on'
  184. ) {
  185. $classes_array['snap_to_grid'] = 'M_butt_Selected_down';
  186. } else {
  187. $classes_array['snap_to_grid'] = 'M_butt';
  188. }
  189. if (isset($params_array['pin_text'])
  190. && $params_array['pin_text'] == 'true'
  191. ) {
  192. $classes_array['pin_text'] = 'M_butt_Selected_down';
  193. } else {
  194. $classes_array['pin_text'] = 'M_butt';
  195. }
  196. if (isset($params_array['relation_lines'])
  197. && $params_array['relation_lines'] == 'false'
  198. ) {
  199. $classes_array['relation_lines'] = 'M_butt_Selected_down';
  200. } else {
  201. $classes_array['relation_lines'] = 'M_butt';
  202. }
  203. if (isset($params_array['small_big_all'])
  204. && $params_array['small_big_all'] == 'v'
  205. ) {
  206. $classes_array['small_big_all'] = 'M_butt_Selected_down';
  207. } else {
  208. $classes_array['small_big_all'] = 'M_butt';
  209. }
  210. if (isset($params_array['side_menu'])
  211. && $params_array['side_menu'] == 'true'
  212. ) {
  213. $classes_array['side_menu'] = 'M_butt_Selected_down';
  214. } else {
  215. $classes_array['side_menu'] = 'M_butt';
  216. }
  217. return $classes_array;
  218. }
  219. /**
  220. * Get HTML to display tables on designer page
  221. *
  222. * @param string $db The database name from the request
  223. * @param DesignerTable[] $designerTables The designer tables
  224. * @param array $tab_pos tables positions
  225. * @param int $display_page page number of the selected page
  226. * @param array $tab_column table column info
  227. * @param array $tables_all_keys all indices
  228. * @param array $tables_pk_or_unique_keys unique or primary indices
  229. *
  230. * @return string html
  231. */
  232. public function getDatabaseTables(
  233. string $db,
  234. array $designerTables,
  235. array $tab_pos,
  236. $display_page,
  237. array $tab_column,
  238. array $tables_all_keys,
  239. array $tables_pk_or_unique_keys
  240. ) {
  241. $columns_type = [];
  242. foreach ($designerTables as $designerTable) {
  243. $table_name = $designerTable->getDbTableString();
  244. $limit = count($tab_column[$table_name]['COLUMN_ID']);
  245. for ($j = 0; $j < $limit; $j++) {
  246. $table_column_name = $table_name . '.' . $tab_column[$table_name]['COLUMN_NAME'][$j];
  247. if (isset($tables_pk_or_unique_keys[$table_column_name])) {
  248. $columns_type[$table_column_name] = 'designer/FieldKey_small';
  249. } else {
  250. $columns_type[$table_column_name] = 'designer/Field_small';
  251. if (false !== strpos($tab_column[$table_name]['TYPE'][$j], 'char')
  252. || false !== strpos($tab_column[$table_name]['TYPE'][$j], 'text')) {
  253. $columns_type[$table_column_name] .= '_char';
  254. } elseif (false !== strpos($tab_column[$table_name]['TYPE'][$j], 'int')
  255. || false !== strpos($tab_column[$table_name]['TYPE'][$j], 'float')
  256. || false !== strpos($tab_column[$table_name]['TYPE'][$j], 'double')
  257. || false !== strpos($tab_column[$table_name]['TYPE'][$j], 'decimal')) {
  258. $columns_type[$table_column_name] .= '_int';
  259. } elseif (false !== strpos($tab_column[$table_name]['TYPE'][$j], 'date')
  260. || false !== strpos($tab_column[$table_name]['TYPE'][$j], 'time')
  261. || false !== strpos($tab_column[$table_name]['TYPE'][$j], 'year')) {
  262. $columns_type[$table_column_name] .= '_date';
  263. }
  264. }
  265. }
  266. }
  267. return $this->template->render('database/designer/database_tables', [
  268. 'db' => $GLOBALS['db'],
  269. 'get_db' => $db,
  270. 'has_query' => isset($_REQUEST['query']),
  271. 'tab_pos' => $tab_pos,
  272. 'display_page' => $display_page,
  273. 'tab_column' => $tab_column,
  274. 'tables_all_keys' => $tables_all_keys,
  275. 'tables_pk_or_unique_keys' => $tables_pk_or_unique_keys,
  276. 'tables' => $designerTables,
  277. 'columns_type' => $columns_type,
  278. 'theme' => $GLOBALS['PMA_Theme'],
  279. ]);
  280. }
  281. /**
  282. * Returns HTML for Designer page
  283. *
  284. * @param string $db database in use
  285. * @param string $getDb database in url
  286. * @param DesignerTable[] $designerTables The designer tables
  287. * @param array $scriptTables array on foreign key support for each table
  288. * @param array $scriptContr initialization data array
  289. * @param DesignerTable[] $scriptDisplayField displayed tables in designer with their display fields
  290. * @param int $displayPage page number of the selected page
  291. * @param boolean $hasQuery whether this is visual query builder
  292. * @param string $selectedPage name of the selected page
  293. * @param array $paramsArray array with class name for various buttons on side menu
  294. * @param array|null $tabPos table positions
  295. * @param array $tabColumn table column info
  296. * @param array $tablesAllKeys all indices
  297. * @param array $tablesPkOrUniqueKeys unique or primary indices
  298. *
  299. * @return string html
  300. */
  301. public function getHtmlForMain(
  302. string $db,
  303. string $getDb,
  304. array $designerTables,
  305. array $scriptTables,
  306. array $scriptContr,
  307. array $scriptDisplayField,
  308. $displayPage,
  309. $hasQuery,
  310. $selectedPage,
  311. array $paramsArray,
  312. ?array $tabPos,
  313. array $tabColumn,
  314. array $tablesAllKeys,
  315. array $tablesPkOrUniqueKeys
  316. ): string {
  317. $cfgRelation = $this->relation->getRelationsParam();
  318. $columnsType = [];
  319. foreach ($designerTables as $designerTable) {
  320. $tableName = $designerTable->getDbTableString();
  321. $limit = count($tabColumn[$tableName]['COLUMN_ID']);
  322. for ($j = 0; $j < $limit; $j++) {
  323. $tableColumnName = $tableName . '.' . $tabColumn[$tableName]['COLUMN_NAME'][$j];
  324. if (isset($tablesPkOrUniqueKeys[$tableColumnName])) {
  325. $columnsType[$tableColumnName] = 'designer/FieldKey_small';
  326. } else {
  327. $columnsType[$tableColumnName] = 'designer/Field_small';
  328. if (false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'char')
  329. || false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'text')) {
  330. $columnsType[$tableColumnName] .= '_char';
  331. } elseif (false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'int')
  332. || false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'float')
  333. || false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'double')
  334. || false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'decimal')) {
  335. $columnsType[$tableColumnName] .= '_int';
  336. } elseif (false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'date')
  337. || false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'time')
  338. || false !== strpos($tabColumn[$tableName]['TYPE'][$j], 'year')) {
  339. $columnsType[$tableColumnName] .= '_date';
  340. }
  341. }
  342. }
  343. }
  344. $displayedFields = [];
  345. foreach ($scriptDisplayField as $designerTable) {
  346. if ($designerTable->getDisplayField() !== null) {
  347. $displayedFields[$designerTable->getTableName()] = $designerTable->getDisplayField();
  348. }
  349. }
  350. $designerConfig = new stdClass();
  351. $designerConfig->db = $db;
  352. $designerConfig->scriptTables = $scriptTables;
  353. $designerConfig->scriptContr = $scriptContr;
  354. $designerConfig->server = $GLOBALS['server'];
  355. $designerConfig->scriptDisplayField = $displayedFields;
  356. $designerConfig->displayPage = (int) $displayPage;
  357. $designerConfig->tablesEnabled = $cfgRelation['pdfwork'];
  358. return $this->template->render('database/designer/main', [
  359. 'db' => $db,
  360. 'get_db' => $getDb,
  361. 'designer_config' => json_encode($designerConfig),
  362. 'display_page' => (int) $displayPage,
  363. 'has_query' => $hasQuery,
  364. 'selected_page' => $selectedPage,
  365. 'params_array' => $paramsArray,
  366. 'theme' => $GLOBALS['PMA_Theme'],
  367. 'tab_pos' => $tabPos,
  368. 'tab_column' => $tabColumn,
  369. 'tables_all_keys' => $tablesAllKeys,
  370. 'tables_pk_or_unique_keys' => $tablesPkOrUniqueKeys,
  371. 'designerTables' => $designerTables,
  372. 'columns_type' => $columnsType,
  373. ]);
  374. }
  375. }