DesignerController.php 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. <?php
  2. declare(strict_types=1);
  3. namespace PhpMyAdmin\Controllers\Database;
  4. use PhpMyAdmin\Database\Designer;
  5. use PhpMyAdmin\Database\Designer\Common as DesignerCommon;
  6. use PhpMyAdmin\Response;
  7. use PhpMyAdmin\Template;
  8. use PhpMyAdmin\Url;
  9. use PhpMyAdmin\Util;
  10. use function htmlspecialchars;
  11. use function in_array;
  12. use function sprintf;
  13. class DesignerController extends AbstractController
  14. {
  15. /** @var Designer */
  16. private $databaseDesigner;
  17. /** @var DesignerCommon */
  18. private $designerCommon;
  19. /**
  20. * @param Response $response
  21. * @param string $db Database name
  22. */
  23. public function __construct(
  24. $response,
  25. Template $template,
  26. $db,
  27. Designer $databaseDesigner,
  28. DesignerCommon $designerCommon
  29. ) {
  30. parent::__construct($response, $template, $db);
  31. $this->databaseDesigner = $databaseDesigner;
  32. $this->designerCommon = $designerCommon;
  33. }
  34. public function index(): void
  35. {
  36. global $db, $script_display_field, $tab_column, $tables_all_keys, $tables_pk_or_unique_keys;
  37. global $success, $page, $message, $display_page, $selected_page, $tab_pos, $fullTableNames, $script_tables;
  38. global $script_contr, $params, $tables, $num_tables, $total_num_tables, $sub_part;
  39. global $tooltip_truename, $tooltip_aliasname, $pos, $classes_side_menu, $cfg, $err_url;
  40. if (isset($_POST['dialog'])) {
  41. if ($_POST['dialog'] === 'edit') {
  42. $html = $this->databaseDesigner->getHtmlForEditOrDeletePages($_POST['db'], 'editPage');
  43. } elseif ($_POST['dialog'] === 'delete') {
  44. $html = $this->databaseDesigner->getHtmlForEditOrDeletePages($_POST['db'], 'deletePage');
  45. } elseif ($_POST['dialog'] === 'save_as') {
  46. $html = $this->databaseDesigner->getHtmlForPageSaveAs($_POST['db']);
  47. } elseif ($_POST['dialog'] === 'export') {
  48. $html = $this->databaseDesigner->getHtmlForSchemaExport(
  49. $_POST['db'],
  50. $_POST['selected_page']
  51. );
  52. } elseif ($_POST['dialog'] === 'add_table') {
  53. // Pass the db and table to the getTablesInfo so we only have the table we asked for
  54. $script_display_field = $this->designerCommon->getTablesInfo($_POST['db'], $_POST['table']);
  55. $tab_column = $this->designerCommon->getColumnsInfo($script_display_field);
  56. $tables_all_keys = $this->designerCommon->getAllKeys($script_display_field);
  57. $tables_pk_or_unique_keys = $this->designerCommon->getPkOrUniqueKeys($script_display_field);
  58. $html = $this->databaseDesigner->getDatabaseTables(
  59. $_POST['db'],
  60. $script_display_field,
  61. [],
  62. -1,
  63. $tab_column,
  64. $tables_all_keys,
  65. $tables_pk_or_unique_keys
  66. );
  67. }
  68. if (! empty($html)) {
  69. $this->response->addHTML($html);
  70. }
  71. return;
  72. }
  73. if (isset($_POST['operation'])) {
  74. if ($_POST['operation'] === 'deletePage') {
  75. $success = $this->designerCommon->deletePage($_POST['selected_page']);
  76. $this->response->setRequestStatus($success);
  77. } elseif ($_POST['operation'] === 'savePage') {
  78. if ($_POST['save_page'] === 'same') {
  79. $page = $_POST['selected_page'];
  80. } elseif ($this->designerCommon->getPageExists($_POST['selected_value'])) {
  81. $this->response->addJSON(
  82. 'message',
  83. /* l10n: The user tries to save a page with an existing name in Designer */
  84. __(
  85. sprintf(
  86. 'There already exists a page named "%s" please rename it to something else.',
  87. htmlspecialchars($_POST['selected_value'])
  88. )
  89. )
  90. );
  91. $this->response->setRequestStatus(false);
  92. return;
  93. } else {
  94. $page = $this->designerCommon->createNewPage($_POST['selected_value'], $_POST['db']);
  95. $this->response->addJSON('id', $page);
  96. }
  97. $success = $this->designerCommon->saveTablePositions($page);
  98. $this->response->setRequestStatus($success);
  99. } elseif ($_POST['operation'] === 'setDisplayField') {
  100. [
  101. $success,
  102. $message,
  103. ] = $this->designerCommon->saveDisplayField(
  104. $_POST['db'],
  105. $_POST['table'],
  106. $_POST['field']
  107. );
  108. $this->response->setRequestStatus($success);
  109. $this->response->addJSON('message', $message);
  110. } elseif ($_POST['operation'] === 'addNewRelation') {
  111. [$success, $message] = $this->designerCommon->addNewRelation(
  112. $_POST['db'],
  113. $_POST['T1'],
  114. $_POST['F1'],
  115. $_POST['T2'],
  116. $_POST['F2'],
  117. $_POST['on_delete'],
  118. $_POST['on_update'],
  119. $_POST['DB1'],
  120. $_POST['DB2']
  121. );
  122. $this->response->setRequestStatus($success);
  123. $this->response->addJSON('message', $message);
  124. } elseif ($_POST['operation'] === 'removeRelation') {
  125. [$success, $message] = $this->designerCommon->removeRelation(
  126. $_POST['T1'],
  127. $_POST['F1'],
  128. $_POST['T2'],
  129. $_POST['F2']
  130. );
  131. $this->response->setRequestStatus($success);
  132. $this->response->addJSON('message', $message);
  133. } elseif ($_POST['operation'] === 'save_setting_value') {
  134. $success = $this->designerCommon->saveSetting($_POST['index'], $_POST['value']);
  135. $this->response->setRequestStatus($success);
  136. }
  137. return;
  138. }
  139. Util::checkParameters(['db']);
  140. $err_url = Util::getScriptNameForOption($cfg['DefaultTabDatabase'], 'database');
  141. $err_url .= Url::getCommon(['db' => $db], '&');
  142. if (! $this->hasDatabase()) {
  143. return;
  144. }
  145. $script_display_field = $this->designerCommon->getTablesInfo();
  146. $display_page = -1;
  147. $selected_page = null;
  148. $visualBuilderMode = isset($_GET['query']);
  149. if ($visualBuilderMode) {
  150. $display_page = $this->designerCommon->getDefaultPage($_GET['db']);
  151. } elseif (! empty($_GET['page'])) {
  152. $display_page = $_GET['page'];
  153. } else {
  154. $display_page = $this->designerCommon->getLoadingPage($_GET['db']);
  155. }
  156. if ($display_page != -1) {
  157. $selected_page = $this->designerCommon->getPageName($display_page);
  158. }
  159. $tab_pos = $this->designerCommon->getTablePositions($display_page);
  160. $fullTableNames = [];
  161. foreach ($script_display_field as $designerTable) {
  162. $fullTableNames[] = $designerTable->getDbTableString();
  163. }
  164. foreach ($tab_pos as $position) {
  165. if (in_array($position['dbName'] . '.' . $position['tableName'], $fullTableNames)) {
  166. continue;
  167. }
  168. $designerTables = $this->designerCommon->getTablesInfo($position['dbName'], $position['tableName']);
  169. foreach ($designerTables as $designerTable) {
  170. $script_display_field[] = $designerTable;
  171. }
  172. }
  173. $tab_column = $this->designerCommon->getColumnsInfo($script_display_field);
  174. $script_tables = $this->designerCommon->getScriptTabs($script_display_field);
  175. $tables_pk_or_unique_keys = $this->designerCommon->getPkOrUniqueKeys($script_display_field);
  176. $tables_all_keys = $this->designerCommon->getAllKeys($script_display_field);
  177. $classes_side_menu = $this->databaseDesigner->returnClassNamesFromMenuButtons();
  178. $script_contr = $this->designerCommon->getScriptContr($script_display_field);
  179. $params = ['lang' => $GLOBALS['lang']];
  180. if (isset($_GET['db'])) {
  181. $params['db'] = $_GET['db'];
  182. }
  183. $this->response->getFooter()->setMinimal();
  184. $header = $this->response->getHeader();
  185. $header->setBodyId('designer_body');
  186. $this->addScriptFiles([
  187. 'vendor/jquery/jquery.fullscreen.js',
  188. 'designer/database.js',
  189. 'designer/objects.js',
  190. 'designer/page.js',
  191. 'designer/history.js',
  192. 'designer/move.js',
  193. 'designer/init.js',
  194. ]);
  195. [
  196. $tables,
  197. $num_tables,
  198. $total_num_tables,
  199. $sub_part,,,
  200. $tooltip_truename,
  201. $tooltip_aliasname,
  202. $pos,
  203. ] = Util::getDbInfo($db, $sub_part ?? '');
  204. // Embed some data into HTML, later it will be read
  205. // by designer/init.js and converted to JS variables.
  206. $this->response->addHTML(
  207. $this->databaseDesigner->getHtmlForMain(
  208. $db,
  209. $_GET['db'],
  210. $script_display_field,
  211. $script_tables,
  212. $script_contr,
  213. $script_display_field,
  214. $display_page,
  215. $visualBuilderMode,
  216. $selected_page,
  217. $classes_side_menu,
  218. $tab_pos,
  219. $tab_column,
  220. $tables_all_keys,
  221. $tables_pk_or_unique_keys
  222. )
  223. );
  224. $this->response->addHTML('<div id="PMA_disable_floating_menubar"></div>');
  225. }
  226. }