IndexesController.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <?php
  2. declare(strict_types=1);
  3. namespace PhpMyAdmin\Controllers\Table;
  4. use PhpMyAdmin\DatabaseInterface;
  5. use PhpMyAdmin\DbTableExists;
  6. use PhpMyAdmin\Html\Generator;
  7. use PhpMyAdmin\Index;
  8. use PhpMyAdmin\Message;
  9. use PhpMyAdmin\Query\Compatibility;
  10. use PhpMyAdmin\Query\Generator as QueryGenerator;
  11. use PhpMyAdmin\Response;
  12. use PhpMyAdmin\Template;
  13. use PhpMyAdmin\Url;
  14. use PhpMyAdmin\Util;
  15. use function count;
  16. use function is_array;
  17. use function json_decode;
  18. /**
  19. * Displays index edit/creation form and handles it.
  20. */
  21. class IndexesController extends AbstractController
  22. {
  23. /** @var DatabaseInterface */
  24. private $dbi;
  25. /**
  26. * @param Response $response
  27. * @param string $db Database name.
  28. * @param string $table Table name.
  29. * @param DatabaseInterface $dbi
  30. */
  31. public function __construct($response, Template $template, $db, $table, $dbi)
  32. {
  33. parent::__construct($response, $template, $db, $table);
  34. $this->dbi = $dbi;
  35. }
  36. public function index(): void
  37. {
  38. global $db, $table, $url_params, $cfg, $err_url;
  39. if (! isset($_POST['create_edit_table'])) {
  40. Util::checkParameters(['db', 'table']);
  41. $url_params = ['db' => $db, 'table' => $table];
  42. $err_url = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table');
  43. $err_url .= Url::getCommon($url_params, '&');
  44. DbTableExists::check();
  45. }
  46. if (isset($_POST['index'])) {
  47. if (is_array($_POST['index'])) {
  48. // coming already from form
  49. $index = new Index($_POST['index']);
  50. } else {
  51. $index = $this->dbi->getTable($this->db, $this->table)->getIndex($_POST['index']);
  52. }
  53. } else {
  54. $index = new Index();
  55. }
  56. if (isset($_POST['do_save_data'])) {
  57. $this->doSaveData($index, false);
  58. return;
  59. }
  60. $this->displayForm($index);
  61. }
  62. public function indexRename(): void
  63. {
  64. global $db, $table, $url_params, $cfg, $err_url;
  65. if (! isset($_POST['create_edit_table'])) {
  66. Util::checkParameters(['db', 'table']);
  67. $url_params = ['db' => $db, 'table' => $table];
  68. $err_url = Util::getScriptNameForOption($cfg['DefaultTabTable'], 'table');
  69. $err_url .= Url::getCommon($url_params, '&');
  70. DbTableExists::check();
  71. }
  72. if (isset($_POST['index'])) {
  73. if (is_array($_POST['index'])) {
  74. // coming already from form
  75. $index = new Index($_POST['index']);
  76. } else {
  77. $index = $this->dbi->getTable($this->db, $this->table)->getIndex($_POST['index']);
  78. }
  79. } else {
  80. $index = new Index();
  81. }
  82. if (isset($_POST['do_save_data'])) {
  83. $this->doSaveData($index, true);
  84. return;
  85. }
  86. $this->displayRenameForm($index);
  87. }
  88. /**
  89. * Display the rename form to rename an index
  90. *
  91. * @param Index $index An Index instance.
  92. */
  93. public function displayRenameForm(Index $index): void
  94. {
  95. $this->dbi->selectDb($GLOBALS['db']);
  96. $formParams = [
  97. 'db' => $this->db,
  98. 'table' => $this->table,
  99. ];
  100. if (isset($_POST['old_index'])) {
  101. $formParams['old_index'] = $_POST['old_index'];
  102. } elseif (isset($_POST['index'])) {
  103. $formParams['old_index'] = $_POST['index'];
  104. }
  105. $this->addScriptFiles(['indexes.js']);
  106. $this->render('table/index_rename_form', [
  107. 'index' => $index,
  108. 'form_params' => $formParams,
  109. ]);
  110. }
  111. /**
  112. * Display the form to edit/create an index
  113. *
  114. * @param Index $index An Index instance.
  115. */
  116. public function displayForm(Index $index): void
  117. {
  118. $this->dbi->selectDb($GLOBALS['db']);
  119. $add_fields = 0;
  120. if (isset($_POST['index']) && is_array($_POST['index'])) {
  121. // coming already from form
  122. if (isset($_POST['index']['columns']['names'])) {
  123. $add_fields = count($_POST['index']['columns']['names'])
  124. - $index->getColumnCount();
  125. }
  126. if (isset($_POST['add_fields'])) {
  127. $add_fields += $_POST['added_fields'];
  128. }
  129. } elseif (isset($_POST['create_index'])) {
  130. $add_fields = $_POST['added_fields'];
  131. }
  132. // Get fields and stores their name/type
  133. if (isset($_POST['create_edit_table'])) {
  134. $fields = json_decode($_POST['columns'], true);
  135. $index_params = [
  136. 'Non_unique' => $_POST['index']['Index_choice'] === 'UNIQUE'
  137. ? '0' : '1',
  138. ];
  139. $index->set($index_params);
  140. $add_fields = count($fields);
  141. } else {
  142. $fields = $this->dbi->getTable($this->db, $this->table)
  143. ->getNameAndTypeOfTheColumns();
  144. }
  145. $form_params = [
  146. 'db' => $this->db,
  147. 'table' => $this->table,
  148. ];
  149. if (isset($_POST['create_index'])) {
  150. $form_params['create_index'] = 1;
  151. } elseif (isset($_POST['old_index'])) {
  152. $form_params['old_index'] = $_POST['old_index'];
  153. } elseif (isset($_POST['index'])) {
  154. $form_params['old_index'] = $_POST['index'];
  155. }
  156. $this->addScriptFiles(['indexes.js']);
  157. $this->render('table/index_form', [
  158. 'fields' => $fields,
  159. 'index' => $index,
  160. 'form_params' => $form_params,
  161. 'add_fields' => $add_fields,
  162. 'create_edit_table' => isset($_POST['create_edit_table']),
  163. 'default_sliders_state' => $GLOBALS['cfg']['InitialSlidersState'],
  164. ]);
  165. }
  166. /**
  167. * Process the data from the edit/create index form,
  168. * run the query to build the new index
  169. * and moves back to /table/sql
  170. *
  171. * @param Index $index An Index instance.
  172. * @param bool $renameMode Rename the Index mode
  173. */
  174. public function doSaveData(Index $index, bool $renameMode): void
  175. {
  176. global $containerBuilder;
  177. $error = false;
  178. $sql_query = '';
  179. if ($renameMode && Compatibility::isCompatibleRenameIndex($this->dbi->getVersion())) {
  180. $oldIndexName = $_POST['old_index'];
  181. if ($oldIndexName === 'PRIMARY') {
  182. if ($index->getName() === '') {
  183. $index->setName('PRIMARY');
  184. } elseif ($index->getName() !== 'PRIMARY') {
  185. $error = Message::error(
  186. __('The name of the primary key must be "PRIMARY"!')
  187. );
  188. }
  189. }
  190. $sql_query = QueryGenerator::getSqlQueryForIndexRename(
  191. $this->db,
  192. $this->table,
  193. $oldIndexName,
  194. $index->getName()
  195. );
  196. } else {
  197. $sql_query = $this->dbi->getTable($this->db, $this->table)
  198. ->getSqlQueryForIndexCreateOrEdit($index, $error);
  199. }
  200. // If there is a request for SQL previewing.
  201. if (isset($_POST['preview_sql'])) {
  202. $this->response->addJSON(
  203. 'sql_data',
  204. $this->template->render('preview_sql', ['query_data' => $sql_query])
  205. );
  206. } elseif (! $error) {
  207. $this->dbi->query($sql_query);
  208. $response = Response::getInstance();
  209. if ($response->isAjax()) {
  210. $message = Message::success(
  211. __('Table %1$s has been altered successfully.')
  212. );
  213. $message->addParam($this->table);
  214. $this->response->addJSON(
  215. 'message',
  216. Generator::getMessage($message, $sql_query, 'success')
  217. );
  218. $indexes = Index::getFromTable($this->table, $this->db);
  219. $indexesDuplicates = Index::findDuplicates($this->table, $this->db);
  220. $this->response->addJSON(
  221. 'index_table',
  222. $this->template->render('indexes', [
  223. 'url_params' => [
  224. 'db' => $this->db,
  225. 'table' => $this->table,
  226. ],
  227. 'indexes' => $indexes,
  228. 'indexes_duplicates' => $indexesDuplicates,
  229. ])
  230. );
  231. } else {
  232. /** @var StructureController $controller */
  233. $controller = $containerBuilder->get(StructureController::class);
  234. $controller->index();
  235. }
  236. } else {
  237. $this->response->setRequestStatus(false);
  238. $this->response->addJSON('message', $error);
  239. }
  240. }
  241. }