phpmyadmin/src/Database/Designer.php
Kamil Tekiela 1afc49ab53 Improve type hint
Signed-off-by: Kamil Tekiela <tekiela246@gmail.com>
2026-03-08 14:35:16 +00:00

270 lines
9.3 KiB
PHP

<?php
declare(strict_types=1);
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\Dbal\DatabaseInterface;
use PhpMyAdmin\Message;
use PhpMyAdmin\Plugins;
use PhpMyAdmin\Plugins\PluginType;
use PhpMyAdmin\Template;
use PhpMyAdmin\Util;
use stdClass;
use function __;
use function is_string;
use function json_decode;
use function str_contains;
/**
* Set of functions related to database designer
*/
class Designer
{
public function __construct(
private readonly DatabaseInterface $dbi,
private readonly Relation $relation,
public readonly Template $template,
private readonly Config $config,
) {
}
/**
* Function to get html for displaying the page edit/delete form
*
* @param string $db database name
* @param string $operation 'edit' or 'delete' depending on the operation
*
* @return string html content
*/
public function getHtmlForEditOrDeletePages(string $db, string $operation): string
{
$relationParameters = $this->relation->getRelationParameters();
return $this->template->render('database/designer/edit_delete_pages', [
'db' => $db,
'operation' => $operation,
'pdfwork' => $relationParameters->pdfFeature !== null,
'pages' => $this->getPageIdsAndNames($db),
]);
}
/**
* Function to get html for displaying the page save as form
*
* @param string $db database name
*
* @return string html content
*/
public function getHtmlForPageSaveAs(string $db): string
{
$relationParameters = $this->relation->getRelationParameters();
return $this->template->render('database/designer/page_save_as', [
'db' => $db,
'pdfwork' => $relationParameters->pdfFeature !== null,
'pages' => $this->getPageIdsAndNames($db),
]);
}
/**
* Retrieve IDs and names of schema pages
*
* @param string $db database name
*
* @return array<string|null> array of schema page id and names
*/
private function getPageIdsAndNames(string $db): array
{
$pdfFeature = $this->relation->getRelationParameters()->pdfFeature;
if ($pdfFeature === null) {
return [];
}
$pageQuery = 'SELECT `page_nr`, `page_descr` FROM '
. Util::backquote($pdfFeature->database) . '.'
. Util::backquote($pdfFeature->pdfPages)
. ' WHERE db_name = ' . $this->dbi->quoteString($db)
. ' ORDER BY `page_descr`';
$pageRs = $this->dbi->tryQueryAsControlUser($pageQuery);
if (! $pageRs) {
return [];
}
return $pageRs->fetchAllKeyPair();
}
/**
* Function to get html for displaying the schema export
*
* @param string $db database name
* @param int $page the page to be exported
*/
public function getHtmlForSchemaExport(string $db, int $page, mixed $formatParam, mixed $exportTypeParam): string
{
$exportList = Plugins::getSchema();
/* Fail if we didn't find any schema plugin */
if ($exportList === []) {
return Message::error(
__('Could not load schema plugins, please check your installation!'),
)->getDisplay();
}
$choice = Plugins::getChoice($exportList, $this->getFormat($formatParam, $exportTypeParam));
$options = Plugins::getOptions(PluginType::Schema, $exportList);
return $this->template->render('database/designer/schema_export', [
'db' => $db,
'page' => $page,
'plugins_choice' => $choice,
'options' => $options,
]);
}
private function getFormat(mixed $formatParam, mixed $exportTypeParam): string
{
if (is_string($exportTypeParam) && $exportTypeParam !== '') {
return $exportTypeParam;
}
if (is_string($formatParam) && $formatParam !== '') {
return $formatParam;
}
return $this->config->settings['Schema']['format'];
}
/**
* Returns array of stored values of Designer Settings
*
* @return mixed[] stored values
*/
private function getSideMenuParamsArray(): array
{
$params = [];
$databaseDesignerSettingsFeature = $this->relation->getRelationParameters()->databaseDesignerSettingsFeature;
if ($databaseDesignerSettingsFeature !== null) {
$query = 'SELECT `settings_data` FROM '
. Util::backquote($databaseDesignerSettingsFeature->database) . '.'
. Util::backquote($databaseDesignerSettingsFeature->designerSettings)
. ' WHERE ' . Util::backquote('username') . ' = '
. $this->dbi->quoteString($this->config->selectedServer['user'])
. ';';
$result = $this->dbi->fetchSingleRow($query);
if ($result !== []) {
$params = json_decode((string) $result['settings_data'], true);
}
}
return $params;
}
/**
* Returns class names for various buttons on Designer Side Menu
*
* @return array<string, string> class names of various buttons
*/
public function returnClassNamesFromMenuButtons(): array
{
$paramsArray = $this->getSideMenuParamsArray();
$selectedButton = 'M_butt_Selected_down';
$normalButton = 'M_butt';
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,
];
}
/**
* @param array<string, list<ColumnInfo>> $tableColumnsInfo table column info
* @param array<string, bool> $tablesAllKeys unique or primary indices
*
* @return array<string, string>
*/
public function getColumnTypes(array $tableColumnsInfo, array $tablesAllKeys): array
{
$columnsType = [];
foreach ($tableColumnsInfo as $tableName => $columnsInfo) {
foreach ($columnsInfo as $columnInfo) {
$tableColumnName = $tableName . '.' . $columnInfo->name;
if (isset($tablesAllKeys[$tableColumnName]) && $tablesAllKeys[$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';
}
}
}
}
return $columnsType;
}
/**
* @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 getDesignerConfig(
string $db,
array $designerTables,
array $scriptTables,
array $scriptContr,
int $displayPage,
): stdClass {
$relationParameters = $this->relation->getRelationParameters();
$displayedFields = [];
foreach ($designerTables as $designerTable) {
if ($designerTable->getDisplayField() === null) {
continue;
}
$displayedFields[$designerTable->getTableName()] = $designerTable->getDisplayField();
}
$designerConfig = new stdClass();
$designerConfig->db = $db;
$designerConfig->scriptTables = $scriptTables;
$designerConfig->scriptContr = $scriptContr;
$designerConfig->server = Current::$server;
$designerConfig->scriptDisplayField = $displayedFields;
$designerConfig->displayPage = $displayPage;
$designerConfig->tablesEnabled = $relationParameters->pdfFeature !== null;
return $designerConfig;
}
}