diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 404cc381e5..07f46e26d6 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -8283,30 +8283,12 @@ parameters: count: 1 path: src/Plugins.php - - - message: '#^Cannot cast mixed to string\.$#' - identifier: cast.string - count: 2 - path: src/Plugins.php - - message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#' identifier: empty.notAllowed count: 1 path: src/Plugins.php - - - message: '#^Loose comparison via "\!\=" is not allowed\.$#' - identifier: notEqual.notAllowed - count: 1 - path: src/Plugins.php - - - - message: '#^Loose comparison via "\=\=" is not allowed\.$#' - identifier: equal.notAllowed - count: 2 - path: src/Plugins.php - - message: ''' #^Call to deprecated method getInstance\(\) of class PhpMyAdmin\\Config\: @@ -10563,6 +10545,18 @@ parameters: count: 1 path: src/Profiling.php + - + message: '#^Loose comparison via "\=\=" is not allowed\.$#' + identifier: equal.notAllowed + count: 1 + path: src/Properties/Options/Items/RadioPropertyItem.php + + - + message: '#^Loose comparison via "\=\=" is not allowed\.$#' + identifier: equal.notAllowed + count: 1 + path: src/Properties/Options/Items/SelectPropertyItem.php + - message: '#^Loose comparison via "\=\=" is not allowed\.$#' identifier: equal.notAllowed @@ -16368,12 +16362,6 @@ parameters: count: 1 path: tests/unit/PluginsTest.php - - - message: '#^You should use assertCount\(\$expectedCount, \$variable\) instead of assertSame\(\$expectedCount, \$variable\-\>count\(\)\)\.$#' - identifier: phpunit.assertCount - count: 1 - path: tests/unit/Properties/Options/OptionsPropertyGroupTest.php - - message: ''' #^Call to deprecated method getInstance\(\) of class PhpMyAdmin\\Config\: diff --git a/psalm-baseline.xml b/psalm-baseline.xml index a1e9da5cc8..0ff2d14756 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -5589,43 +5589,15 @@ - - - - - settings[$section][$opt]]]> + settings[$pluginType->value][$opt]]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> getName()]]> - getForce()]]> - getForce()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> - getName()]]> getName()]]> - settings[$section][$opt])]]> + settings[$pluginType->value][$opt])]]> @@ -7213,6 +7185,54 @@ fetchValue('SELECT @@have_profiling')]]> + + + getForce()]]> + getForce()]]> + getName()]]> + getName()]]> + getName()]]> + getName()]]> + + + + + getName()]]> + getName()]]> + + + + + getName()]]> + getName()]]> + getName()]]> + getName()]]> + + + + + getName()]]> + getName()]]> + getName()]]> + getName()]]> + + + + + getName()]]> + getName()]]> + getName()]]> + getName()]]> + + + + + getName()]]> + getName()]]> + getName()]]> + getName()]]> + + diff --git a/src/Controllers/Database/ImportController.php b/src/Controllers/Database/ImportController.php index f5ac290186..5ab583eeb7 100644 --- a/src/Controllers/Database/ImportController.php +++ b/src/Controllers/Database/ImportController.php @@ -20,6 +20,7 @@ use PhpMyAdmin\Import\Import; use PhpMyAdmin\Import\ImportSettings; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Routing\Route; use PhpMyAdmin\Util; @@ -93,9 +94,9 @@ final readonly class ImportController implements InvocableController $hiddenInputs = [$idKey => $uploadId, 'import_type' => 'database', 'db' => Current::$database]; $choice = Plugins::getChoice($importList, $this->getFormat($request->getParam('format'))); - $options = Plugins::getOptions('Import', $importList); + $options = Plugins::getOptions(PluginType::Import, $importList); $skipQueriesDefault = $this->getSkipQueries($request->getParam('skip_queries')); - $isAllowInterruptChecked = Plugins::checkboxCheck('Import', 'allow_interrupt'); + $isAllowInterruptChecked = Plugins::checkboxCheck(PluginType::Import, 'allow_interrupt'); $maxUploadSize = Util::getUploadSizeInBytes(); $this->response->render('database/import/index', [ diff --git a/src/Controllers/Server/ImportController.php b/src/Controllers/Server/ImportController.php index e471358274..238d81a7af 100644 --- a/src/Controllers/Server/ImportController.php +++ b/src/Controllers/Server/ImportController.php @@ -18,6 +18,7 @@ use PhpMyAdmin\Import\Import; use PhpMyAdmin\Import\ImportSettings; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Routing\Route; use PhpMyAdmin\Util; @@ -78,9 +79,9 @@ final readonly class ImportController implements InvocableController $hiddenInputs = [$idKey => $uploadId, 'import_type' => 'server']; $choice = Plugins::getChoice($importList, $this->getFormat($request->getParam('format'))); - $options = Plugins::getOptions('Import', $importList); + $options = Plugins::getOptions(PluginType::Import, $importList); $skipQueriesDefault = $this->getSkipQueries($request->getParam('skip_queries')); - $isAllowInterruptChecked = Plugins::checkboxCheck('Import', 'allow_interrupt'); + $isAllowInterruptChecked = Plugins::checkboxCheck(PluginType::Import, 'allow_interrupt'); $maxUploadSize = Util::getUploadSizeInBytes(); $this->response->render('server/import/index', [ diff --git a/src/Controllers/Table/ImportController.php b/src/Controllers/Table/ImportController.php index 7d98c8bf02..d78a350a7a 100644 --- a/src/Controllers/Table/ImportController.php +++ b/src/Controllers/Table/ImportController.php @@ -21,6 +21,7 @@ use PhpMyAdmin\Import\Import; use PhpMyAdmin\Import\ImportSettings; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Routing\Route; use PhpMyAdmin\Url; @@ -122,9 +123,9 @@ final readonly class ImportController implements InvocableController ]; $choice = Plugins::getChoice($importList, $this->getFormat($request->getParam('format'))); - $options = Plugins::getOptions('Import', $importList); + $options = Plugins::getOptions(PluginType::Import, $importList); $skipQueriesDefault = $this->getSkipQueries($request->getParam('skip_queries')); - $isAllowInterruptChecked = Plugins::checkboxCheck('Import', 'allow_interrupt'); + $isAllowInterruptChecked = Plugins::checkboxCheck(PluginType::Import, 'allow_interrupt'); $maxUploadSize = Util::getUploadSizeInBytes(); $this->response->render('table/import/index', [ diff --git a/src/Database/Designer.php b/src/Database/Designer.php index 68d89cb1eb..7ff2d52b2c 100644 --- a/src/Database/Designer.php +++ b/src/Database/Designer.php @@ -12,6 +12,7 @@ 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; @@ -118,7 +119,7 @@ class Designer } $choice = Plugins::getChoice($exportList, $this->getFormat($formatParam, $exportTypeParam)); - $options = Plugins::getOptions('Schema', $exportList); + $options = Plugins::getOptions(PluginType::Schema, $exportList); return $this->template->render('database/designer/schema_export', [ 'db' => $db, diff --git a/src/Export/Options.php b/src/Export/Options.php index aaf7deca16..21918fcde8 100644 --- a/src/Export/Options.php +++ b/src/Export/Options.php @@ -13,6 +13,7 @@ use PhpMyAdmin\Encoding; use PhpMyAdmin\Plugins; use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Plugins\ExportType; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\Query\Utilities; use PhpMyAdmin\Table\Table; use PhpMyAdmin\Util; @@ -178,7 +179,7 @@ final readonly class Options 'hidden_inputs' => $hiddenInputs, 'export_method' => $_POST['quick_or_custom'] ?? $config->config->Export->method, 'plugins_choice' => $dropdown, - 'options' => Plugins::getOptions('Export', $exportList), + 'options' => Plugins::getOptions(PluginType::Export, $exportList), 'can_convert_kanji' => Encoding::canConvertKanji(), 'exec_time_limit' => $config->settings['ExecTimeLimit'], 'rows' => $rows, diff --git a/src/Plugins.php b/src/Plugins.php index c4b98f734c..9b945195f1 100644 --- a/src/Plugins.php +++ b/src/Plugins.php @@ -16,17 +16,11 @@ use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Plugins\ExportType; use PhpMyAdmin\Plugins\ImportPlugin; use PhpMyAdmin\Plugins\Plugin; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\Plugins\SchemaPlugin; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup; use PhpMyAdmin\Properties\Options\Groups\OptionsPropertySubgroup; -use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem; -use PhpMyAdmin\Properties\Options\Items\DocPropertyItem; use PhpMyAdmin\Properties\Options\Items\HiddenPropertyItem; -use PhpMyAdmin\Properties\Options\Items\MessageOnlyPropertyItem; -use PhpMyAdmin\Properties\Options\Items\NumberPropertyItem; -use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem; -use PhpMyAdmin\Properties\Options\Items\SelectPropertyItem; -use PhpMyAdmin\Properties\Options\Items\TextPropertyItem; use PhpMyAdmin\Properties\Options\OptionsPropertyGroup; use PhpMyAdmin\Properties\Options\OptionsPropertyItem; use PhpMyAdmin\Properties\Options\OptionsPropertyOneItem; @@ -36,9 +30,6 @@ use Throwable; use function __; use function class_exists; use function count; -use function htmlspecialchars; -use function in_array; -use function is_array; use function is_string; use function is_subclass_of; use function mb_strtolower; @@ -201,21 +192,18 @@ class Plugins * Returns html input tag option 'checked' if plugin $opt * should be set by config or request * - * @param string $section name of config section in - * \PhpMyAdmin\Config::getInstance()->settings[$section] for plugin - * @param string $opt name of option - * @psalm-param 'Export'|'Import'|'Schema' $section + * @param string $opt name of option * * @return string html input tag option 'checked' */ - public static function checkboxCheck(string $section, string $opt): string + public static function checkboxCheck(PluginType $pluginType, string $opt): string { // If the form is being repopulated using $_GET data, that is priority if ( isset($_GET[$opt]) || ! isset($_GET['repopulate']) && ((ImportSettings::$timeoutPassed && isset($_REQUEST[$opt])) - || ! empty(Config::getInstance()->settings[$section][$opt])) + || ! empty(Config::getInstance()->settings[$pluginType->value][$opt])) ) { return ' checked'; } @@ -226,14 +214,12 @@ class Plugins /** * Returns default value for option $opt * - * @param string $section name of config section in - * \PhpMyAdmin\Config::getInstance()->settings[$section] for plugin - * @param string $opt name of option - * @psalm-param 'Export'|'Import'|'Schema' $section + * @param PluginType $pluginType type of the plugin + * @param string $opt name of option * * @return string default value for option $opt */ - public static function getDefault(string $section, string $opt): string + public static function getDefault(PluginType $pluginType, string $opt): string { if (isset($_GET[$opt]) && is_string($_GET[$opt])) { // If the form is being repopulated using $_GET data, that is priority @@ -245,8 +231,8 @@ class Plugins } $config = Config::getInstance(); - if (isset($config->settings[$section][$opt])) { - return (string) $config->settings[$section][$opt]; + if (isset($config->settings[$pluginType->value][$opt])) { + return (string) $config->settings[$pluginType->value][$opt]; } return ''; @@ -278,22 +264,20 @@ class Plugins /** * Returns single option in a list element * - * @param string $section name of config section in $cfg[$section] for plugin * @param string $pluginName unique plugin name * @param OptionsPropertyItem $propertyGroup options property main group instance * @param bool $isSubgroup if this group is a subgroup - * @psalm-param 'Export'|'Import'|'Schema' $section * * @return string table row with option */ private static function getOneOption( Plugin $plugin, - string $section, + PluginType $pluginType, string $pluginName, OptionsPropertyItem $propertyGroup, bool $isSubgroup = false, ): string { - $ret = "\n"; + $ret = ''; $properties = null; if (! $isSubgroup) { @@ -302,7 +286,7 @@ class Plugins $properties = [$propertyGroup]; } else { // for main groups - $ret .= '
'; + $ret .= "\n" . '
'; $text = null; if (method_exists($propertyGroup, 'getText')) { @@ -313,7 +297,7 @@ class Plugins $ret .= '
' . $plugin->getTranslatedText($text) . '
'; } - $ret .= '
    '; + $ret .= '
      ' . "\n"; } } @@ -325,17 +309,15 @@ class Plugins } } - $propertyClass = null; if ($properties !== null) { foreach ($properties as $propertyItem) { - $propertyClass = $propertyItem::class; // if the property is a subgroup, we deal with it recursively if ($propertyItem instanceof OptionsPropertySubgroup) { // for subgroups // each subgroup can have a header, which may also be a form element $subgroupHeader = $propertyItem->getSubgroupHeader(); if ($subgroupHeader !== null) { - $ret .= self::getOneOption($plugin, $section, $pluginName, $subgroupHeader); + $ret .= self::getOneOption($plugin, $pluginType, $pluginName, $subgroupHeader); } $ret .= '
      • getDoc(); - if (is_array($doc)) { - if (count($doc) === 3) { - $ret .= MySQLDocumentation::show($doc[1], false, null, null, $doc[2]); - } elseif (count($doc) === 1) { - $ret .= MySQLDocumentation::showDocumentation('faq', $doc[0]); - } else { - $ret .= MySQLDocumentation::show($doc[1]); - } - } - } - - // Close the list element after $doc link is displayed - if ( - in_array($propertyClass, [ - BoolPropertyItem::class, - MessageOnlyPropertyItem::class, - SelectPropertyItem::class, - TextPropertyItem::class, - ], true) - ) { - $ret .= ''; - } - - return $ret . "\n"; - } - - /** - * Get HTML for properties items - * - * @param string $section name of config section in $cfg[$section] for plugin - * @param string $pluginName unique plugin name - * @param OptionsPropertyItem $propertyItem Property item - * @psalm-param 'Export'|'Import'|'Schema' $section - */ - public static function getHtmlForProperty( - Plugin $plugin, - string $section, - string $pluginName, - OptionsPropertyItem $propertyItem, - ): string { - $ret = ''; - $propertyClass = $propertyItem::class; - switch ($propertyClass) { - case BoolPropertyItem::class: - $ret .= '
      • ' . "\n"; - $ret .= '
        ' . "\n"; - $ret .= 'getName(), - ); - - if ($propertyItem->getForce() != null) { - // Same code is also few lines lower, update both if needed - $ret .= ' onclick="if (!this.checked && ' - . '(!document.getElementById(\'checkbox_' . $pluginName - . '_' . $propertyItem->getForce() . '\') ' - . '|| !document.getElementById(\'checkbox_' - . $pluginName . '_' . $propertyItem->getForce() - . '\').checked)) ' - . 'return false; else return true;"'; - } - - $ret .= '>'; - $ret .= '
        '; - break; - case DocPropertyItem::class: - echo DocPropertyItem::class; - break; - case HiddenPropertyItem::class: - $ret .= '
      • '; - break; - case MessageOnlyPropertyItem::class: - $ret .= '
      • ' . "\n"; - $ret .= $plugin->getTranslatedText($propertyItem->getText() ?? ''); - break; - case RadioPropertyItem::class: - /** @var RadioPropertyItem $pitem */ - $pitem = $propertyItem; - - $default = htmlspecialchars($plugin->getTranslatedText(self::getDefault( - $section, - $pluginName . '_' . $pitem->getName(), - ))); - - $ret .= '
      • '; - - foreach ($pitem->getValues() as $key => $val) { - $ret .= '
        getName() . '_' . $key . '">' - . $plugin->getTranslatedText((string) $val) . '
        '; - } - - $ret .= '
      • '; - - break; - case SelectPropertyItem::class: - /** @var SelectPropertyItem $pitem */ - $pitem = $propertyItem; - $ret .= '
      • ' . "\n"; - $ret .= ''; - $ret .= ''; - break; - case TextPropertyItem::class: - /** @var TextPropertyItem $pitem */ - $pitem = $propertyItem; - $ret .= '
      • ' . "\n"; - $ret .= ''; - $ret .= 'getSize() !== 0 - ? ' size="' . $pitem->getSize() . '"' - : '') - . ($pitem->getLen() !== 0 - ? ' maxlength="' . $pitem->getLen() . '"' - : '') - . '>'; - break; - case NumberPropertyItem::class: - $ret .= '
      • ' . "\n"; - $ret .= ''; - $ret .= ''; - break; - default: - break; + $ret .= '
' . "\n"; } return $ret; } + private static function getHtmlForProperty( + Plugin $plugin, + PluginType $pluginType, + string $pluginName, + OptionsPropertyItem $propertyItem, + ): string { + if ($propertyItem instanceof OptionsPropertyOneItem) { + return $propertyItem->getHtml($plugin, $pluginType, $pluginName) . "\n"; + } + + return ''; + } + /** * Returns html div with editable options for plugin * - * @param string $section name of config section in $cfg[$section] - * @param ExportPlugin[]|ImportPlugin[]|SchemaPlugin[] $list array with plugin instances - * @psalm-param 'Export'|'Import'|'Schema' $section + * @param ExportPlugin[]|ImportPlugin[]|SchemaPlugin[] $list array with plugin instances * * @return string html fieldset with plugin options */ - public static function getOptions(string $section, array $list): string + public static function getOptions(PluginType $pluginType, array $list): string { $ret = ''; // Options for plugins that support them @@ -592,7 +397,7 @@ class Plugins } } - $ret .= self::getOneOption($plugin, $section, $pluginName, $propertyMainGroup); + $ret .= self::getOneOption($plugin, $pluginType, $pluginName, $propertyMainGroup); } } @@ -605,4 +410,22 @@ class Plugins return $ret; } + + public static function getDocumentationLinkHtml(OptionsPropertyOneItem $propertyGroup): string + { + $doc = $propertyGroup->getDoc(); + if ($doc === '') { + return ''; + } + + if (is_string($doc)) { + return MySQLDocumentation::showDocumentation('faq', $doc); + } + + if (count($doc) === 2) { + return MySQLDocumentation::show($doc[0], anchor: $doc[1]); + } + + return MySQLDocumentation::show($doc[0]); + } } diff --git a/src/Plugins/Export/ExportSql.php b/src/Plugins/Export/ExportSql.php index c346f6c5fa..e358d04816 100644 --- a/src/Plugins/Export/ExportSql.php +++ b/src/Plugins/Export/ExportSql.php @@ -223,7 +223,7 @@ class ExportSql extends ExportPlugin __('Enclose export in a transaction'), ); $leaf->setDoc( - ['programs', 'mysqldump', 'option_mysqldump_single-transaction'], + ['mysqldump', 'option_mysqldump_single-transaction'], ); $generalOptions->addProperty($leaf); @@ -233,7 +233,7 @@ class ExportSql extends ExportPlugin __('Disable foreign key checks'), ); $leaf->setDoc( - ['manual_MySQL_Database_Administration', 'server-system-variables', 'sysvar_foreign_key_checks'], + ['server-system-variables', 'sysvar_foreign_key_checks'], ); $generalOptions->addProperty($leaf); @@ -433,7 +433,7 @@ class ExportSql extends ExportPlugin __('INSERT DELAYED statements'), ); $leaf->setDoc( - ['manual_MySQL_Database_Administration', 'insert_delayed'], + ['insert_delayed'], ); $subgroup->addProperty($leaf); @@ -442,7 +442,7 @@ class ExportSql extends ExportPlugin __('INSERT IGNORE statements'), ); $leaf->setDoc( - ['manual_MySQL_Database_Administration', 'insert'], + ['insert'], ); $subgroup->addProperty($leaf); $dataOptions->addProperty($subgroup); @@ -2572,7 +2572,7 @@ class ExportSql extends ExportPlugin ); $leaf->setValues($values); $leaf->setDoc( - ['manual_MySQL_Database_Administration', 'Server_SQL_mode'], + ['sql-mode'], ); $generalOptions->addProperty($leaf); } diff --git a/src/Plugins/Import/ImportSql.php b/src/Plugins/Import/ImportSql.php index 899daf5735..b862317ac0 100644 --- a/src/Plugins/Import/ImportSql.php +++ b/src/Plugins/Import/ImportSql.php @@ -63,7 +63,7 @@ class ImportSql extends ImportPlugin ); $leaf->setValues($values); $leaf->setDoc( - ['manual_MySQL_Database_Administration', 'Server_SQL_mode'], + ['sql-mode'], ); $generalOptions->addProperty($leaf); $leaf = new BoolPropertyItem( @@ -71,7 +71,7 @@ class ImportSql extends ImportPlugin __('Do not use AUTO_INCREMENT for zero values'), ); $leaf->setDoc( - ['manual_MySQL_Database_Administration', 'Server_SQL_mode', 'sqlmode_no_auto_value_on_zero'], + ['sql-mode', 'sqlmode_no_auto_value_on_zero'], ); $generalOptions->addProperty($leaf); diff --git a/src/Plugins/PluginType.php b/src/Plugins/PluginType.php new file mode 100644 index 0000000000..387824d9a1 --- /dev/null +++ b/src/Plugins/PluginType.php @@ -0,0 +1,12 @@ +'; + $ret .= '
'; + $ret .= 'getName(), + ); + + if ($this->getForce() !== null) { + $ret .= ' onclick="if (!this.checked && ' + . '(!document.getElementById(\'checkbox_' . $pluginName + . '_' . $this->getForce() . '\') ' + . '|| !document.getElementById(\'checkbox_' + . $pluginName . '_' . $this->getForce() + . '\').checked)) ' + . 'return false; else return true;"'; + } + + $ret .= '>'; + $ret .= '
'; + $ret .= Plugins::getDocumentationLinkHtml($this); + + return $ret; + } } diff --git a/src/Properties/Options/Items/DocPropertyItem.php b/src/Properties/Options/Items/DocPropertyItem.php deleted file mode 100644 index d03eaddf45..0000000000 --- a/src/Properties/Options/Items/DocPropertyItem.php +++ /dev/null @@ -1,14 +0,0 @@ -'; + } } diff --git a/src/Properties/Options/Items/MessageOnlyPropertyItem.php b/src/Properties/Options/Items/MessageOnlyPropertyItem.php index 1f8ed8b657..3d85b4e9d0 100644 --- a/src/Properties/Options/Items/MessageOnlyPropertyItem.php +++ b/src/Properties/Options/Items/MessageOnlyPropertyItem.php @@ -4,6 +4,9 @@ declare(strict_types=1); namespace PhpMyAdmin\Properties\Options\Items; +use PhpMyAdmin\Plugins; +use PhpMyAdmin\Plugins\Plugin; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\Properties\Options\OptionsPropertyOneItem; /** @@ -11,4 +14,12 @@ use PhpMyAdmin\Properties\Options\OptionsPropertyOneItem; */ class MessageOnlyPropertyItem extends OptionsPropertyOneItem { + public function getHtml(Plugin $plugin, PluginType $pluginType, string $pluginName): string + { + $ret = '
  • '; + $ret .= $plugin->getTranslatedText($this->getText() ?? ''); + $ret .= Plugins::getDocumentationLinkHtml($this); + + return $ret; + } } diff --git a/src/Properties/Options/Items/NumberPropertyItem.php b/src/Properties/Options/Items/NumberPropertyItem.php index 5722232964..2ba3ca8d04 100644 --- a/src/Properties/Options/Items/NumberPropertyItem.php +++ b/src/Properties/Options/Items/NumberPropertyItem.php @@ -4,11 +4,36 @@ declare(strict_types=1); namespace PhpMyAdmin\Properties\Options\Items; +use PhpMyAdmin\Plugins; +use PhpMyAdmin\Plugins\Plugin; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\Properties\Options\OptionsPropertyOneItem; +use function htmlspecialchars; + /** * Single property item class of type number */ class NumberPropertyItem extends OptionsPropertyOneItem { + public function getHtml(Plugin $plugin, PluginType $pluginType, string $pluginName): string + { + $ret = '
  • '; + $ret .= ''; + $ret .= ''; + + return $ret; + } } diff --git a/src/Properties/Options/Items/RadioPropertyItem.php b/src/Properties/Options/Items/RadioPropertyItem.php index fb06a7546e..1b79f50a8a 100644 --- a/src/Properties/Options/Items/RadioPropertyItem.php +++ b/src/Properties/Options/Items/RadioPropertyItem.php @@ -4,11 +4,41 @@ declare(strict_types=1); namespace PhpMyAdmin\Properties\Options\Items; +use PhpMyAdmin\Plugins; +use PhpMyAdmin\Plugins\Plugin; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\Properties\Options\OptionsPropertyOneItem; +use function htmlspecialchars; + /** * Single property item class of type radio */ class RadioPropertyItem extends OptionsPropertyOneItem { + public function getHtml(Plugin $plugin, PluginType $pluginType, string $pluginName): string + { + $default = htmlspecialchars($plugin->getTranslatedText(Plugins::getDefault( + $pluginType, + $pluginName . '_' . $this->getName(), + ))); + + $ret = '
  • '; + + foreach ($this->getValues() as $key => $val) { + $ret .= '
    getName() . '_' . $key . '">' + . $plugin->getTranslatedText($val) . '
    '; + } + + return $ret; + } } diff --git a/src/Properties/Options/Items/SelectPropertyItem.php b/src/Properties/Options/Items/SelectPropertyItem.php index c88a16f38c..cb9d5a2e4c 100644 --- a/src/Properties/Options/Items/SelectPropertyItem.php +++ b/src/Properties/Options/Items/SelectPropertyItem.php @@ -4,11 +4,44 @@ declare(strict_types=1); namespace PhpMyAdmin\Properties\Options\Items; +use PhpMyAdmin\Plugins; +use PhpMyAdmin\Plugins\Plugin; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\Properties\Options\OptionsPropertyOneItem; +use function htmlspecialchars; + /** * Single property item class of type select */ class SelectPropertyItem extends OptionsPropertyOneItem { + public function getHtml(Plugin $plugin, PluginType $pluginType, string $pluginName): string + { + $ret = '
  • '; + $ret .= ''; + $ret .= ''; + $ret .= Plugins::getDocumentationLinkHtml($this); + + return $ret; + } } diff --git a/src/Properties/Options/Items/TextPropertyItem.php b/src/Properties/Options/Items/TextPropertyItem.php index c87d0c0648..59df3f6daf 100644 --- a/src/Properties/Options/Items/TextPropertyItem.php +++ b/src/Properties/Options/Items/TextPropertyItem.php @@ -4,11 +4,42 @@ declare(strict_types=1); namespace PhpMyAdmin\Properties\Options\Items; +use PhpMyAdmin\Plugins; +use PhpMyAdmin\Plugins\Plugin; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\Properties\Options\OptionsPropertyOneItem; +use function htmlspecialchars; + /** * Single property item class of type text */ class TextPropertyItem extends OptionsPropertyOneItem { + public function getHtml(Plugin $plugin, PluginType $pluginType, string $pluginName): string + { + $ret = '
  • '; + $ret .= ''; + $ret .= 'getSize() !== 0 + ? ' size="' . $this->getSize() . '"' + : '') + . ($this->getLen() !== 0 + ? ' maxlength="' . $this->getLen() . '"' + : '') + . '>'; + $ret .= Plugins::getDocumentationLinkHtml($this); + + return $ret; + } } diff --git a/src/Properties/Options/OptionsPropertyOneItem.php b/src/Properties/Options/OptionsPropertyOneItem.php index 40a4fc4e3e..874fb13c36 100644 --- a/src/Properties/Options/OptionsPropertyOneItem.php +++ b/src/Properties/Options/OptionsPropertyOneItem.php @@ -7,13 +7,16 @@ declare(strict_types=1); namespace PhpMyAdmin\Properties\Options; +use PhpMyAdmin\Plugins\Plugin; +use PhpMyAdmin\Plugins\PluginType; + /** * Parents only single property items (not groups). * Defines possible options and getters and setters for them. */ abstract class OptionsPropertyOneItem extends OptionsPropertyItem { - /** @var mixed[] */ + /** @var string[] */ private array $values = []; /** @var string|string[] */ @@ -27,7 +30,7 @@ abstract class OptionsPropertyOneItem extends OptionsPropertyItem /** * Gets the values * - * @return mixed[] + * @return string[] */ public function getValues(): array { @@ -37,7 +40,7 @@ abstract class OptionsPropertyOneItem extends OptionsPropertyItem /** * Sets the values * - * @param mixed[] $values values + * @param string[] $values values */ public function setValues(array $values): void { @@ -83,4 +86,6 @@ abstract class OptionsPropertyOneItem extends OptionsPropertyItem { $this->size = $size; } + + abstract public function getHtml(Plugin $plugin, PluginType $pluginType, string $pluginName): string; } diff --git a/src/Util.php b/src/Util.php index 3b4520e9e2..3dece556ef 100644 --- a/src/Util.php +++ b/src/Util.php @@ -193,8 +193,7 @@ class Util } } - $url = 'https://dev.mysql.com/doc/refman/' - . $mysql . '/' . $lang . '/' . $link . '.html'; + $url = 'https://dev.mysql.com/doc/refman/' . $mysql . '/' . $lang . '/' . $link . '.html'; if ($anchor !== '') { $url .= '#' . $anchor; } diff --git a/tests/unit/Controllers/Table/ExportControllerTest.php b/tests/unit/Controllers/Table/ExportControllerTest.php index 0672d692cd..a72c39b0f1 100644 --- a/tests/unit/Controllers/Table/ExportControllerTest.php +++ b/tests/unit/Controllers/Table/ExportControllerTest.php @@ -21,6 +21,7 @@ use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\I18n\LanguageManager; use PhpMyAdmin\Plugins; use PhpMyAdmin\Plugins\ExportType; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; use PhpMyAdmin\Tests\Stubs\ResponseRenderer; @@ -75,7 +76,7 @@ class ExportControllerTest extends AbstractTestCase ], 'export_method' => 'quick', 'plugins_choice' => Plugins::getChoice($exportList, 'sql'), - 'options' => Plugins::getOptions('Export', $exportList), + 'options' => Plugins::getOptions(PluginType::Export, $exportList), 'can_convert_kanji' => false, 'exec_time_limit' => 300, 'rows' => [ diff --git a/tests/unit/Controllers/Table/ImportControllerTest.php b/tests/unit/Controllers/Table/ImportControllerTest.php index 93c7851a6a..4cb1c00d6c 100644 --- a/tests/unit/Controllers/Table/ImportControllerTest.php +++ b/tests/unit/Controllers/Table/ImportControllerTest.php @@ -19,6 +19,7 @@ use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Import\ImportSettings; use PhpMyAdmin\Plugins; use PhpMyAdmin\Plugins\Import\Upload\UploadNoplugin; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; use PhpMyAdmin\Tests\Stubs\ResponseRenderer; @@ -48,7 +49,7 @@ class ImportControllerTest extends AbstractTestCase ImportSettings::$importType = 'table'; $importList = Plugins::getImport(); $choice = Plugins::getChoice($importList, 'xml'); - $options = Plugins::getOptions('Import', $importList); + $options = Plugins::getOptions(PluginType::Import, $importList); $template = new Template($config); $userPreferences = new UserPreferences($dbi, new Relation($dbi, $config), $template, $config, new Clock()); diff --git a/tests/unit/Export/OptionsTest.php b/tests/unit/Export/OptionsTest.php index 13cdc7f57c..779188ca2a 100644 --- a/tests/unit/Export/OptionsTest.php +++ b/tests/unit/Export/OptionsTest.php @@ -18,6 +18,7 @@ use PhpMyAdmin\Export\TemplateModel; use PhpMyAdmin\I18n\LanguageManager; use PhpMyAdmin\Plugins; use PhpMyAdmin\Plugins\ExportType; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\Template; use PhpMyAdmin\Tests\AbstractTestCase; use PhpMyAdmin\Theme\ThemeManager; @@ -110,7 +111,7 @@ class OptionsTest extends AbstractTestCase ], 'export_method' => $config->config->Export->method, 'plugins_choice' => $dropdown, - 'options' => Plugins::getOptions('Export', $exportList), + 'options' => Plugins::getOptions(PluginType::Export, $exportList), 'can_convert_kanji' => Encoding::canConvertKanji(), 'exec_time_limit' => $config->settings['ExecTimeLimit'], 'rows' => [], diff --git a/tests/unit/PluginsTest.php b/tests/unit/PluginsTest.php index 24212b307f..209fef6baa 100644 --- a/tests/unit/PluginsTest.php +++ b/tests/unit/PluginsTest.php @@ -20,6 +20,7 @@ use PhpMyAdmin\Plugins\ExportPlugin; use PhpMyAdmin\Plugins\ExportType; use PhpMyAdmin\Plugins\Import\ImportSql; use PhpMyAdmin\Plugins\ImportPlugin; +use PhpMyAdmin\Plugins\PluginType; use PhpMyAdmin\Plugins\Schema\SchemaPdf; use PhpMyAdmin\Plugins\SchemaPlugin; use PhpMyAdmin\Tests\Stubs\ResponseRenderer; @@ -66,13 +67,12 @@ class PluginsTest extends AbstractTestCase self::assertContainsOnlyInstancesOf(SchemaPlugin::class, $plugins); } - /** @psalm-param 'Export'|'Import'|'Schema' $section */ #[DataProvider('providerForTestGetDefault')] public function testGetDefault( string $expected, string|int|null $actualConfig, string|null $actualGet, - string $section, + PluginType $pluginType, string $option, bool|null $timeoutPassed, ): void { @@ -85,30 +85,30 @@ class PluginsTest extends AbstractTestCase $_GET[$option] = $actualGet; } - Config::getInstance()->settings[$section][$option] = $actualConfig; - $default = Plugins::getDefault($section, $option); + Config::getInstance()->settings[$pluginType->value][$option] = $actualConfig; + $default = Plugins::getDefault($pluginType, $option); self::assertSame($expected, $default); } - /** @return array */ + /** @return array */ public static function providerForTestGetDefault(): array { return [ - ['xml', 'xml', null, 'Export', 'format', null], - ['xml', 'sql', 'xml', 'Export', 'format', null], - ['xml', null, 'xml', 'Export', 'format', null], - ['', null, null, 'Export', 'format', null], + ['xml', 'xml', null, PluginType::Export, 'format', null], + ['xml', 'sql', 'xml', PluginType::Export, 'format', null], + ['xml', null, 'xml', PluginType::Export, 'format', null], + ['', null, null, PluginType::Export, 'format', null], [ 'strLatexStructure strTest strLatexContinued', 'strLatexStructure strTest strLatexContinued', null, - 'Export', + PluginType::Export, 'latex_structure_continued_caption', null, ], - ['xml', 'sql', 'xml', 'Export', 'format', true], - ['sql', 'sql', 'xml', 'Export', 'format', false], - ['30', 30, null, 'Import', 'skip_queries', null], + ['xml', 'sql', 'xml', PluginType::Export, 'format', true], + ['sql', 'sql', 'xml', PluginType::Export, 'format', false], + ['30', 30, null, PluginType::Import, 'skip_queries', null], ]; } @@ -151,38 +151,35 @@ class PluginsTest extends AbstractTestCase ContainerBuilder::$container = $this->getContainerForGetOptions($this->createDatabaseInterface($dbiDummy)); ImportSettings::$importType = 'table'; - $options = Plugins::getOptions('Import', Plugins::getImport()); + $options = Plugins::getOptions(PluginType::Import, Plugins::getImport()); $dbiDummy->assertAllQueriesConsumed(); // phpcs:disable Generic.Files.LineLength.TooLong $expected = <<<'HTML'

    CSV

    -
    • -
      -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
      -
  • +
      +
    • +
    • +
    • +
    • +
    • +
    • +
    • +
    • +

    CSV using LOAD DATA

    -
    • -
      -
    • -
    • -
    • -
    • -
    • -
    • -
      -
    • -
      -
    +
      +
    • +
    • +
    • +
    • +
    • +
    • +
    • +
    • +

    ESRI Shape File

    This format has no options

    @@ -190,22 +187,19 @@ class PluginsTest extends AbstractTestCase

    MediaWiki Table

    This format has no options

    OpenDocument Spreadsheet

    -
    • -
      -
    • -
      -
    • -
      -
    • -
      -
    +
      +
    • +
    • +
    • +
    • +

    SQL

    -
    • -
    • -
      -
    +
      +
    • Documentation +
    • Documentation +

    XML

    This format has no options

    @@ -221,225 +215,212 @@ class PluginsTest extends AbstractTestCase { ContainerBuilder::$container = $this->getContainerForGetOptions($this->createDatabaseInterface()); - $options = Plugins::getOptions('Export', Plugins::getExport(ExportType::Table, true)); + $options = Plugins::getOptions(PluginType::Export, Plugins::getExport(ExportType::Table, true)); // phpcs:disable Generic.Files.LineLength.TooLong $expected = <<<'HTML'

    CodeGen

    -
    • -
    +
      +
    • +
    • +

    CSV

    -
    • -
    • -
    • -
    • -
    • -
    • -
      -
    • -
      -
    +
      +
    • +
    • +
    • +
    • +
    • +
    • +
    • +
    • +

    CSV for MS Excel

    -
    • -
    • -
      -
    • -
      -
    • -
    +
      +
    • +
    • +
    • +
    • +
    • +

    JSON

    -
    • -
      -
    • -
      -
    +
      +
    • +
    • +
    • +

    LaTeX

    -
    • -
      -
    +
      +
    • +
    -
    Dump table
    +
    Dump table
      +
    • +
    -
    Object creation options
    • -
    • -
    • -
    • -
      -
    +
    Object creation options
      +
    • Documentation +
    • Documentation +
    • Documentation +
    • +
    -
    Data dump options
    • -
      -
    • -
    • -
    • -
    • -
    +
    Data dump options
      +
    • +
    • Documentation +
    • Documentation +
    • Documentation +
    • +

    MediaWiki Table

    Dump table
      -
    • +
      • -
    • -
    • -
      -
    • -
      -
    + +
  • +
  • +
  • Microsoft Word 2000

    -
    Dump table
    +
    Dump table
      +
    • +
    -
    Data dump options
    • -
    • -
      -
    +
    Data dump options
      +
    • +
    • +

    OpenDocument Spreadsheet

    -
    • -
    • -
      -
    +
      +
    • +
    • +
    • +

    OpenDocument Text

    -
    Dump table
    +
    Dump table
      +
    • +
    -
    Object creation options
    • -
      -
    +
    Object creation options
      +
    • +
    -
    Data dump options
    • -
      -
    • -
    +
    Data dump options
      +
    • +
    • +

    PDF

    -
    • -
    +
      +
    • +
    -
    Dump table
    +
    Dump table
      +
    • +

    PHP array

    -
    +
      +
    • +

    This format has no options

    SQL

      -
    • -
      -
    • +
      • -
      • -
      • -
        -
    • -
    • -
      -
    • -
      -
    • -
      -
    • -
      -
    • - -
    • +
    • +
    • +
    +
  • Documentation +
  • Documentation +
  • +
  • +
  • Documentation +
    • -
  • +
    Object creation options
      -
    • - Add statements:
    • +
    • Add statements:
      • -
      • -
        -
        -
      • -
        -
      • +
      • +
        • -
        • -
          -
        • -
          -
      • - -
      • -
        -
      • +
      • +
      • +
      +
      • -
      • -
        -
      • -
        -
      • -
        -
    • -
    • -
      -
    • -
      -
    -
  • -
    -
  • +
  • +
  • +
  • + +
  • +
  • + +
  • +
  • -
    Data creation options
    • -
      -
      +
      Data creation options
        +
      • -
        • -
        • -
          -
        • -
          -
      • -
      • - -
      • - Syntax to use when inserting data:
      • +
      • Documentation +
      • Documentation +
      +
    • +
    • Syntax to use when inserting data:
      • -
    • -
    • -
    • -
      -
    • -
      -
    +
  • + +
  • +
  • +
  • +

    Texy! text

    -
    Dump table
    +
    Dump table
      +
    • +
    -
    Data dump options
    • -
      -
    • -
  • +
    Data dump options
      +
    • +
    • +

    TOON

    -
    • -
    • -
    +
      +
    • +
    • +
    • +

    YAML

    -
    +
      +
    • +

    This format has no options

    @@ -452,56 +433,47 @@ class PluginsTest extends AbstractTestCase public function testGetOptionsForSchema(): void { ContainerBuilder::$container = $this->getContainerForGetOptions($this->createDatabaseInterface()); - $options = Plugins::getOptions('Schema', Plugins::getSchema()); + $options = Plugins::getOptions(PluginType::Schema, Plugins::getSchema()); // phpcs:disable Generic.Files.LineLength.TooLong $expected = <<<'HTML'

    Dia

    -
    • -
      -
    • -
      -
    • -
    • -
    +
      +
    • +
    • +
    • +
    • +

    EPS

    -
    • -
      -
    • -
      -
    • -
      -
    • -
    +
      +
    • +
    • +
    • +
    • +

    PDF

    -
    • -
      -
    • -
      -
    • -
      -
    • -
    • -
    • -
      -
    • -
      -
    • -
    +
      +
    • +
    • +
    • +
    • +
    • +
    • +
    • +
    • +

    SVG

    -
    • -
      -
    • -
      -
    • -
      -
    +
      +
    • +
    • +
    • +
    diff --git a/tests/unit/Properties/Options/OptionsPropertyGroupTest.php b/tests/unit/Properties/Options/OptionsPropertyGroupTest.php index 290a909ddc..69ce07a288 100644 --- a/tests/unit/Properties/Options/OptionsPropertyGroupTest.php +++ b/tests/unit/Properties/Options/OptionsPropertyGroupTest.php @@ -61,6 +61,6 @@ class OptionsPropertyGroupTest extends AbstractTestCase $this->stub->addProperty($propertyItem); $propertyItem2 = new BoolPropertyItem(); $this->stub->addProperty($propertyItem2); - self::assertSame(2, $this->stub->count()); + self::assertCount(2, $this->stub); } } diff --git a/tests/unit/Properties/Options/OptionsPropertyOneItemTest.php b/tests/unit/Properties/Options/OptionsPropertyOneItemTest.php index d2d5ad1236..9f126006d9 100644 --- a/tests/unit/Properties/Options/OptionsPropertyOneItemTest.php +++ b/tests/unit/Properties/Options/OptionsPropertyOneItemTest.php @@ -21,7 +21,7 @@ class OptionsPropertyOneItemTest extends AbstractTestCase { parent::setUp(); - $this->stub = $this->getMockBuilder(OptionsPropertyOneItem::class)->onlyMethods([])->getMock(); + $this->stub = $this->getMockBuilder(OptionsPropertyOneItem::class)->onlyMethods(['getHtml'])->getMock(); } /** @@ -31,10 +31,10 @@ class OptionsPropertyOneItemTest extends AbstractTestCase */ public function testGetSetValues(): void { - $this->stub->setValues([1, 2]); + $this->stub->setValues(['1', '2']); self::assertSame( - [1, 2], + ['1', '2'], $this->stub->getValues(), ); }