diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3bcd6ee47f..100d3064b1 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1610,11 +1610,6 @@ parameters: count: 2 path: src/Controllers/Database/DesignerController.php - - - message: "#^Parameter \\#1 \\$db of method PhpMyAdmin\\\\Database\\\\Designer\\:\\:getDatabaseTables\\(\\) expects string, mixed given\\.$#" - count: 1 - path: src/Controllers/Database/DesignerController.php - - message: "#^Parameter \\#1 \\$db of method PhpMyAdmin\\\\Database\\\\Designer\\:\\:getHtmlForEditOrDeletePages\\(\\) expects string, mixed given\\.$#" count: 2 @@ -1650,6 +1645,11 @@ parameters: count: 1 path: src/Controllers/Database/DesignerController.php + - + message: "#^Parameter \\#1 \\$db of static method PhpMyAdmin\\\\Url\\:\\:getHiddenInputs\\(\\) expects array\\|string, mixed given\\.$#" + count: 1 + path: src/Controllers/Database/DesignerController.php + - message: "#^Parameter \\#1 \\$index of method PhpMyAdmin\\\\Database\\\\Designer\\\\Common\\:\\:saveSetting\\(\\) expects string, mixed given\\.$#" count: 1 @@ -1710,11 +1710,6 @@ parameters: count: 1 path: src/Controllers/Database/DesignerController.php - - - message: "#^Parameter \\#2 \\$getDb of method PhpMyAdmin\\\\Database\\\\Designer\\:\\:getHtmlForMain\\(\\) expects string, mixed given\\.$#" - count: 1 - path: src/Controllers/Database/DesignerController.php - - message: "#^Parameter \\#2 \\$table of method PhpMyAdmin\\\\Database\\\\Designer\\\\Common\\:\\:getTablesInfo\\(\\) expects string\\|null, mixed given\\.$#" count: 2 @@ -6965,11 +6960,6 @@ parameters: count: 1 path: src/Database/Designer/Common.php - - - message: "#^Only booleans are allowed in a negated boolean, bool\\|string given\\.$#" - count: 1 - path: src/Database/Designer/Common.php - - message: "#^Only booleans are allowed in an if condition, PhpMyAdmin\\\\Dbal\\\\ResultInterface\\|false given\\.$#" count: 2 diff --git a/resources/templates/database/designer/database_tables.twig b/resources/templates/database/designer/database_tables.twig index 8521ce1ab7..a5ff03a078 100644 --- a/resources/templates/database/designer/database_tables.twig +++ b/resources/templates/database/designer/database_tables.twig @@ -70,12 +70,14 @@ designerTable.getTableName()|escape('url'), tab_column[t_n][j].name|url_encode ] %} - {% if not designerTable.supportsForeignkeys() %} - {% set click_field_param = click_field_param|merge([tables_pk_or_unique_keys[tmp_column] is defined ? 1 : 0]) %} - {% else %} - {# if foreign keys are supported, it's not necessary that the - index is a primary key #} - {% set click_field_param = click_field_param|merge([tables_all_keys[tmp_column] is defined ? 1 : 0]) %} + {% if tables_all_keys[tmp_column] is defined %} + {% if not designerTable.supportsForeignkeys() %} + {% set click_field_param = click_field_param|merge([tables_all_keys[tmp_column] ? 1 : 0]) %} + {% else %} + {# if foreign keys are supported, it's not necessary that the + index is a primary key #} + {% set click_field_param = click_field_param|merge([1]) %} + {% endif %} {% endif %} {% set click_field_param = click_field_param|merge([db]) %} + + {% endif %} diff --git a/resources/templates/modals/build_query.twig b/resources/templates/modals/build_query.twig deleted file mode 100644 index b32fe296b3..0000000000 --- a/resources/templates/modals/build_query.twig +++ /dev/null @@ -1,21 +0,0 @@ - diff --git a/src/Controllers/Database/DesignerController.php b/src/Controllers/Database/DesignerController.php index f0d60fa2ed..541430f35c 100644 --- a/src/Controllers/Database/DesignerController.php +++ b/src/Controllers/Database/DesignerController.php @@ -21,6 +21,7 @@ use PhpMyAdmin\Util; use function __; use function htmlspecialchars; use function in_array; +use function json_encode; use function sprintf; class DesignerController extends AbstractController @@ -39,6 +40,7 @@ class DesignerController extends AbstractController { $GLOBALS['message'] ??= null; $GLOBALS['errorUrl'] ??= null; + $GLOBALS['text_dir'] ??= null; $db = $request->getParsedBodyParam('db'); $table = $request->getParsedBodyParam('table'); @@ -62,17 +64,19 @@ class DesignerController extends AbstractController $scriptDisplayField = $this->designerCommon->getTablesInfo($db, $table); $tableColumn = $this->designerCommon->getColumnsInfo($scriptDisplayField); $tablesAllKeys = $this->designerCommon->getAllKeys($scriptDisplayField); - $tablesPkOrUniqueKeys = $this->designerCommon->getPkOrUniqueKeys($scriptDisplayField); + $columnsType = $this->databaseDesigner->getColumnTypes($tableColumn, $tablesAllKeys); - $html = $this->databaseDesigner->getDatabaseTables( - $db, - $scriptDisplayField, - [], - -1, - $tableColumn, - $tablesAllKeys, - $tablesPkOrUniqueKeys, - ); + $html = $this->template->render('database/designer/database_tables', [ + 'db' => Current::$database, + 'text_dir' => $GLOBALS['text_dir'], + 'has_query' => isset($_REQUEST['query']), + 'tab_pos' => [], + 'display_page' => -1, + 'tab_column' => $tableColumn, + 'tables_all_keys' => $tablesAllKeys, + 'tables' => $scriptDisplayField, + 'columns_type' => $columnsType, + ]); } if ($html !== '') { @@ -210,10 +214,8 @@ class DesignerController extends AbstractController $tableColumn = $this->designerCommon->getColumnsInfo($scriptDisplayField); $scriptTables = $this->designerCommon->getScriptTabs($scriptDisplayField); - $tablesPkOrUniqueKeys = $this->designerCommon->getPkOrUniqueKeys($scriptDisplayField); $tablesAllKeys = $this->designerCommon->getAllKeys($scriptDisplayField); $classesSideMenu = $this->databaseDesigner->returnClassNamesFromMenuButtons(); - $scriptContr = $this->designerCommon->getScriptContr($scriptDisplayField); $this->response->setMinimalFooter(); @@ -222,26 +224,36 @@ class DesignerController extends AbstractController $this->addScriptFiles(['designer/init.js']); + $columnsType = $this->databaseDesigner->getColumnTypes($tableColumn, $tablesAllKeys); + + $designerConfig = $this->databaseDesigner->getDesignerConfig( + Current::$database, + $scriptDisplayField, + $scriptTables, + $scriptContr, + $displayPage, + ); + + $mainHtml = $this->template->render('database/designer/main', [ + 'db' => Current::$database, + 'text_dir' => $GLOBALS['text_dir'], + 'hidden_input_fields' => Url::getHiddenInputs($request->getQueryParam('db')), + 'designer_config' => json_encode($designerConfig), + 'display_page' => $displayPage, + 'has_query' => $visualBuilderMode, + 'visual_builder' => $visualBuilderMode, + 'selected_page' => $selectedPage, + 'params_array' => $classesSideMenu, + 'tab_pos' => $tablePositions, + 'tab_column' => $tableColumn, + 'tables_all_keys' => $tablesAllKeys, + 'designerTables' => $scriptDisplayField, + 'columns_type' => $columnsType, + ]); + // Embed some data into HTML, later it will be read // by designer/init.js and converted to JS variables. - $this->response->addHTML( - $this->databaseDesigner->getHtmlForMain( - Current::$database, - $request->getQueryParam('db'), - $scriptDisplayField, - $scriptTables, - $scriptContr, - $scriptDisplayField, - $displayPage, - $visualBuilderMode, - $selectedPage, - $classesSideMenu, - $tablePositions, - $tableColumn, - $tablesAllKeys, - $tablesPkOrUniqueKeys, - ), - ); + $this->response->addHTML($mainHtml); $this->response->addHTML('
'); } diff --git a/src/Database/Designer.php b/src/Database/Designer.php index 78446b8f25..0caf3cbd3a 100644 --- a/src/Database/Designer.php +++ b/src/Database/Designer.php @@ -6,7 +6,6 @@ namespace PhpMyAdmin\Database; use PhpMyAdmin\Config; use PhpMyAdmin\ConfigStorage\Relation; -use PhpMyAdmin\Current; use PhpMyAdmin\Database\Designer\ColumnInfo; use PhpMyAdmin\Database\Designer\DesignerTable; use PhpMyAdmin\DatabaseInterface; @@ -20,7 +19,6 @@ use function __; use function intval; use function is_array; use function json_decode; -use function json_encode; use function str_contains; /** @@ -168,77 +166,33 @@ class Designer */ public function returnClassNamesFromMenuButtons(): array { - $classesArray = []; $paramsArray = $this->getSideMenuParamsArray(); + $selectedButton = 'M_butt_Selected_down'; + $normalButton = 'M_butt'; - if (isset($paramsArray['angular_direct']) && $paramsArray['angular_direct'] === 'angular') { - $classesArray['angular_direct'] = 'M_butt_Selected_down'; - } else { - $classesArray['angular_direct'] = 'M_butt'; - } - - if (isset($paramsArray['snap_to_grid']) && $paramsArray['snap_to_grid'] === 'on') { - $classesArray['snap_to_grid'] = 'M_butt_Selected_down'; - } else { - $classesArray['snap_to_grid'] = 'M_butt'; - } - - if (isset($paramsArray['pin_text']) && $paramsArray['pin_text'] === 'true') { - $classesArray['pin_text'] = 'M_butt_Selected_down'; - } else { - $classesArray['pin_text'] = 'M_butt'; - } - - if (isset($paramsArray['relation_lines']) && $paramsArray['relation_lines'] === 'false') { - $classesArray['relation_lines'] = 'M_butt_Selected_down'; - } else { - $classesArray['relation_lines'] = 'M_butt'; - } - - if (isset($paramsArray['small_big_all']) && $paramsArray['small_big_all'] === 'v') { - $classesArray['small_big_all'] = 'M_butt_Selected_down'; - } else { - $classesArray['small_big_all'] = 'M_butt'; - } - - if (isset($paramsArray['side_menu']) && $paramsArray['side_menu'] === 'true') { - $classesArray['side_menu'] = 'M_butt_Selected_down'; - } else { - $classesArray['side_menu'] = 'M_butt'; - } - - return $classesArray; + return [ + 'angular_direct' => ($paramsArray['angular_direct'] ?? '') === 'angular' ? $selectedButton : $normalButton, + 'snap_to_grid' => ($paramsArray['snap_to_grid'] ?? '') === 'on' ? $selectedButton : $normalButton, + 'pin_text' => ($paramsArray['pin_text'] ?? '') === 'true' ? $selectedButton : $normalButton, + 'relation_lines' => ($paramsArray['relation_lines'] ?? '') === 'false' ? $selectedButton : $normalButton, + 'small_big_all' => ($paramsArray['small_big_all'] ?? '') === 'v' ? $selectedButton : $normalButton, + 'side_menu' => ($paramsArray['side_menu'] ?? '') === 'true' ? $selectedButton : $normalButton, + ]; } /** - * Get HTML to display tables on designer page + * @param list[] $tableColumnsInfo table column info + * @param array $tablesAllKeys unique or primary indices * - * @param string $db The database name from the request - * @param DesignerTable[] $designerTables The designer tables - * @param mixed[] $tabPos tables positions - * @param int $displayPage page number of the selected page - * @param list[] $tableColumnsInfo table column info - * @param mixed[] $tablesAllKeys all indices - * @param mixed[] $tablesPkOrUniqueKeys unique or primary indices - * - * @return string html + * @return array */ - public function getDatabaseTables( - string $db, - array $designerTables, - array $tabPos, - int $displayPage, - array $tableColumnsInfo, - array $tablesAllKeys, - array $tablesPkOrUniqueKeys, - ): string { - $GLOBALS['text_dir'] ??= null; - + public function getColumnTypes(array $tableColumnsInfo, array $tablesAllKeys): array + { $columnsType = []; foreach ($tableColumnsInfo as $tableName => $columnsInfo) { foreach ($columnsInfo as $columnInfo) { $tableColumnName = $tableName . '.' . $columnInfo->name; - if (isset($tablesPkOrUniqueKeys[$tableColumnName])) { + if (isset($tablesAllKeys[$tableColumnName]) && $tablesAllKeys[$tableColumnName]) { $columnsType[$tableColumnName] = 'designer/FieldKey_small'; } else { $columnsType[$tableColumnName] = 'designer/Field_small'; @@ -265,93 +219,25 @@ class Designer } } - return $this->template->render('database/designer/database_tables', [ - 'db' => Current::$database, - 'text_dir' => $GLOBALS['text_dir'], - 'get_db' => $db, - 'has_query' => isset($_REQUEST['query']), - 'tab_pos' => $tabPos, - 'display_page' => $displayPage, - 'tab_column' => $tableColumnsInfo, - 'tables_all_keys' => $tablesAllKeys, - 'tables_pk_or_unique_keys' => $tablesPkOrUniqueKeys, - 'tables' => $designerTables, - 'columns_type' => $columnsType, - ]); + return $columnsType; } /** - * Returns HTML for Designer page - * - * @param string $db database in use - * @param string $getDb database in url - * @param DesignerTable[] $designerTables The designer tables - * @param mixed[] $scriptTables array on foreign key support for each table - * @param mixed[] $scriptContr initialization data array - * @param DesignerTable[] $scriptDisplayField displayed tables in designer with their display fields - * @param int $displayPage page number of the selected page - * @param bool $visualBuilderMode whether this is visual query builder - * @param string|null $selectedPage name of the selected page - * @param mixed[] $paramsArray array with class name for various buttons on side menu - * @param mixed[] $tablePositions table positions - * @param list[] $tableColumnsInfo table column info - * @param mixed[] $tablesAllKeys all indices - * @param mixed[] $tablesPkOrUniqueKeys unique or primary indices - * - * @return string html + * @param DesignerTable[] $designerTables The designer tables + * @param mixed[] $scriptTables array on foreign key support for each table + * @param mixed[] $scriptContr initialization data array */ - public function getHtmlForMain( + public function getDesignerConfig( string $db, - string $getDb, array $designerTables, array $scriptTables, array $scriptContr, - array $scriptDisplayField, int $displayPage, - bool $visualBuilderMode, - string|null $selectedPage, - array $paramsArray, - array $tablePositions, - array $tableColumnsInfo, - array $tablesAllKeys, - array $tablesPkOrUniqueKeys, - ): string { - $GLOBALS['text_dir'] ??= null; - + ): stdClass { $relationParameters = $this->relation->getRelationParameters(); - $columnsType = []; - foreach ($tableColumnsInfo as $tableName => $columnsInfo) { - foreach ($columnsInfo as $columnInfo) { - $tableColumnName = $tableName . '.' . $columnInfo->name; - if (isset($tablesPkOrUniqueKeys[$tableColumnName])) { - $columnsType[$tableColumnName] = 'designer/FieldKey_small'; - } else { - $columnsType[$tableColumnName] = 'designer/Field_small'; - if ( - str_contains($columnInfo->type, 'char') - || str_contains($columnInfo->type, 'text') - ) { - $columnsType[$tableColumnName] .= '_char'; - } elseif ( - str_contains($columnInfo->type, 'int') - || str_contains($columnInfo->type, 'float') - || str_contains($columnInfo->type, 'double') - || str_contains($columnInfo->type, 'decimal') - ) { - $columnsType[$tableColumnName] .= '_int'; - } elseif ( - str_contains($columnInfo->type, 'date') - || str_contains($columnInfo->type, 'time') - || str_contains($columnInfo->type, 'year') - ) { - $columnsType[$tableColumnName] .= '_date'; - } - } - } - } $displayedFields = []; - foreach ($scriptDisplayField as $designerTable) { + foreach ($designerTables as $designerTable) { if ($designerTable->getDisplayField() === null) { continue; } @@ -368,22 +254,6 @@ class Designer $designerConfig->displayPage = $displayPage; $designerConfig->tablesEnabled = $relationParameters->pdfFeature !== null; - return $this->template->render('database/designer/main', [ - 'db' => $db, - 'text_dir' => $GLOBALS['text_dir'], - 'get_db' => $getDb, - 'designer_config' => json_encode($designerConfig), - 'display_page' => $displayPage, - 'has_query' => $visualBuilderMode, - 'visual_builder' => $visualBuilderMode, - 'selected_page' => $selectedPage, - 'params_array' => $paramsArray, - 'tab_pos' => $tablePositions, - 'tab_column' => $tableColumnsInfo, - 'tables_all_keys' => $tablesAllKeys, - 'tables_pk_or_unique_keys' => $tablesPkOrUniqueKeys, - 'designerTables' => $designerTables, - 'columns_type' => $columnsType, - ]); + return $designerConfig; } } diff --git a/src/Database/Designer/Common.php b/src/Database/Designer/Common.php index 89dedd1819..cddebc72ab 100644 --- a/src/Database/Designer/Common.php +++ b/src/Database/Designer/Common.php @@ -175,27 +175,14 @@ class Common return $retval; } - /** - * Returns UNIQUE and PRIMARY indices - * - * @param DesignerTable[] $designerTables The designer tables - * - * @return mixed[] unique or primary indices - */ - public function getPkOrUniqueKeys(array $designerTables): array - { - return $this->getAllKeys($designerTables, true); - } - /** * Returns all indices * * @param DesignerTable[] $designerTables The designer tables - * @param bool $uniqueOnly whether to include only unique ones * - * @return mixed[] indices + * @return array */ - public function getAllKeys(array $designerTables, bool $uniqueOnly = false): array + public function getAllKeys(array $designerTables): array { $keys = []; @@ -203,13 +190,10 @@ class Common $schema = $designerTable->getDatabaseName(); // for now, take into account only the first index segment foreach (Index::getFromTable($this->dbi, $designerTable->getTableName(), $schema) as $index) { - if ($uniqueOnly && ! $index->isUnique()) { - continue; - } - $columns = $index->getColumns(); foreach (array_keys($columns) as $columnName) { - $keys[$schema . '.' . $designerTable->getTableName() . '.' . $columnName] = 1; + $key = $schema . '.' . $designerTable->getTableName() . '.' . $columnName; + $keys[$key] = ! $index->getNonUnique(); } } }