Merge pull request #16984 from mauriciofauth/get-plugins
Refactor `PhpMyAdmin\Plugins::getPlugins` method
This commit is contained in:
commit
ef81c79aec
@ -58,6 +58,7 @@
|
||||
"symfony/expression-language": "^5.2.3",
|
||||
"symfony/polyfill-ctype": "^1.17.0",
|
||||
"symfony/polyfill-mbstring": "^1.17.0",
|
||||
"symfony/polyfill-php80": "^1.16",
|
||||
"twig/twig": "^3.0.1",
|
||||
"webmozart/assert": "^1.10",
|
||||
"williamdes/mariadb-mysql-kbs": "^1.2"
|
||||
|
||||
@ -4,10 +4,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin;
|
||||
|
||||
use FilesystemIterator;
|
||||
use PhpMyAdmin\Html\MySQLDocumentation;
|
||||
use PhpMyAdmin\Plugins\AuthenticationPlugin;
|
||||
use PhpMyAdmin\Plugins\ExportPlugin;
|
||||
use PhpMyAdmin\Plugins\ImportPlugin;
|
||||
use PhpMyAdmin\Plugins\Plugin;
|
||||
use PhpMyAdmin\Plugins\SchemaPlugin;
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertySubgroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
|
||||
@ -22,6 +24,8 @@ use PhpMyAdmin\Properties\Options\OptionsPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
use PhpMyAdmin\Properties\Plugins\PluginPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\SchemaPluginProperties;
|
||||
use SplFileInfo;
|
||||
use Throwable;
|
||||
|
||||
use function __;
|
||||
use function array_pop;
|
||||
@ -30,19 +34,16 @@ use function count;
|
||||
use function explode;
|
||||
use function get_class;
|
||||
use function htmlspecialchars;
|
||||
use function is_file;
|
||||
use function mb_strlen;
|
||||
use function mb_strpos;
|
||||
use function mb_strtolower;
|
||||
use function mb_strtoupper;
|
||||
use function mb_substr;
|
||||
use function method_exists;
|
||||
use function opendir;
|
||||
use function preg_match;
|
||||
use function preg_match_all;
|
||||
use function readdir;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function str_starts_with;
|
||||
use function strcasecmp;
|
||||
use function strcmp;
|
||||
use function strtolower;
|
||||
@ -83,10 +84,11 @@ class Plugins
|
||||
*/
|
||||
public static function getExport(string $type, bool $singleTable): array
|
||||
{
|
||||
return self::getPlugins('export', 'libraries/classes/Plugins/Export/', [
|
||||
'export_type' => $type,
|
||||
'single_table' => $singleTable,
|
||||
]);
|
||||
global $plugin_param;
|
||||
|
||||
$plugin_param = ['export_type' => $type, 'single_table' => $singleTable];
|
||||
|
||||
return self::getPlugins('Export');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,7 +98,11 @@ class Plugins
|
||||
*/
|
||||
public static function getImport(string $type): array
|
||||
{
|
||||
return self::getPlugins('import', 'libraries/classes/Plugins/Import/', $type);
|
||||
global $plugin_param;
|
||||
|
||||
$plugin_param = $type;
|
||||
|
||||
return self::getPlugins('Import');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,89 +110,54 @@ class Plugins
|
||||
*/
|
||||
public static function getSchema(): array
|
||||
{
|
||||
return self::getPlugins('schema', 'libraries/classes/Plugins/Schema/', null);
|
||||
return self::getPlugins('Schema');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all plugin information from directory $plugins_dir
|
||||
* Reads all plugin information
|
||||
*
|
||||
* @param string $plugin_type the type of the plugin (import, export, etc)
|
||||
* @param string $plugins_dir directory with plugins
|
||||
* @param array|string|null $plugin_param parameter to plugin by which they can
|
||||
* decide whether they can work
|
||||
* @param string $type the type of the plugin (import, export, etc)
|
||||
*
|
||||
* @return array list of plugin instances
|
||||
*/
|
||||
private static function getPlugins(string $plugin_type, string $plugins_dir, $plugin_param): array
|
||||
private static function getPlugins(string $type): array
|
||||
{
|
||||
global $skip_import;
|
||||
|
||||
$GLOBALS['plugin_param'] = $plugin_param;
|
||||
|
||||
$fullFsPathPluginDir = ROOT_PATH . $plugins_dir;
|
||||
|
||||
$handle = @opendir($fullFsPathPluginDir);
|
||||
if (! $handle) {
|
||||
try {
|
||||
$files = new FilesystemIterator(ROOT_PATH . 'libraries/classes/Plugins/' . $type);
|
||||
} catch (Throwable $e) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$plugin_list = [];
|
||||
$plugins = [];
|
||||
|
||||
$namespace = 'PhpMyAdmin\\' . str_replace('/', '\\', mb_substr($plugins_dir, 18));
|
||||
$class_type = mb_strtoupper($plugin_type[0], 'UTF-8')
|
||||
. mb_strtolower(mb_substr($plugin_type, 1), 'UTF-8');
|
||||
|
||||
$prefix_class_name = $namespace . $class_type;
|
||||
|
||||
while ($file = @readdir($handle)) {
|
||||
// In some situations, Mac OS creates a new file for each file
|
||||
// (for example ._csv.php) so the following regexp
|
||||
// matches a file which does not start with a dot but ends
|
||||
// with ".php"
|
||||
if (
|
||||
! is_file($fullFsPathPluginDir . $file)
|
||||
|| ! preg_match(
|
||||
'@^' . $class_type . '([^\.]+)\.php$@i',
|
||||
$file,
|
||||
$matches
|
||||
)
|
||||
) {
|
||||
/** @var SplFileInfo $fileInfo */
|
||||
foreach ($files as $fileInfo) {
|
||||
if (! $fileInfo->isReadable() || ! $fileInfo->isFile() || $fileInfo->getExtension() !== 'php') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var bool $skip_import */
|
||||
$skip_import = false;
|
||||
|
||||
include_once $fullFsPathPluginDir . $file;
|
||||
|
||||
if ($skip_import) {
|
||||
if (! str_starts_with($fileInfo->getFilename(), $type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class_name = $prefix_class_name . $matches[1];
|
||||
$plugin = new $class_name();
|
||||
if ($plugin->getProperties() === null) {
|
||||
$class = sprintf('PhpMyAdmin\\Plugins\\%s\\%s', $type, $fileInfo->getBasename('.php'));
|
||||
if (! class_exists($class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$plugin_list[] = $plugin;
|
||||
$plugin = new $class();
|
||||
if (! ($plugin instanceof Plugin) || ! $plugin->isAvailable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$plugins[] = $plugin;
|
||||
}
|
||||
|
||||
usort(
|
||||
$plugin_list,
|
||||
/**
|
||||
* @param mixed $cmp_name_1
|
||||
* @param mixed $cmp_name_2
|
||||
*/
|
||||
static function ($cmp_name_1, $cmp_name_2) {
|
||||
return strcasecmp(
|
||||
$cmp_name_1->getProperties()->getText(),
|
||||
$cmp_name_2->getProperties()->getText()
|
||||
);
|
||||
}
|
||||
);
|
||||
usort($plugins, static function (Plugin $plugin1, Plugin $plugin2): int {
|
||||
return strcasecmp($plugin1->getProperties()->getText(), $plugin2->getProperties()->getText());
|
||||
});
|
||||
|
||||
return $plugin_list;
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* Produce a PDF report (export) from a query
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -14,24 +11,13 @@ use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\RadioPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\TextPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
use TCPDF;
|
||||
|
||||
use function __;
|
||||
use function class_exists;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
/**
|
||||
* Skip the plugin if TCPDF is not available.
|
||||
*/
|
||||
if (! class_exists('TCPDF')) {
|
||||
$GLOBALS['skip_import'] = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// phpcs:enable
|
||||
|
||||
/**
|
||||
* Handles the export for the PDF class
|
||||
* Produce a PDF report (export) from a query
|
||||
*/
|
||||
class ExportPdf extends ExportPlugin
|
||||
{
|
||||
@ -378,4 +364,9 @@ class ExportPdf extends ExportPlugin
|
||||
{
|
||||
$this->pdf = $pdf;
|
||||
}
|
||||
|
||||
public function isAvailable(): bool
|
||||
{
|
||||
return class_exists(TCPDF::class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* Set of functions used to build XML dumps of tables
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -29,18 +26,8 @@ use function strlen;
|
||||
|
||||
use const PHP_VERSION;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
/* Can't do server export */
|
||||
if (! isset($GLOBALS['db']) || strlen($GLOBALS['db']) === 0) {
|
||||
$GLOBALS['skip_import'] = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// phpcs:enable
|
||||
|
||||
/**
|
||||
* Handles the export for the XML class
|
||||
* Used to build XML dumps of tables
|
||||
*/
|
||||
class ExportXml extends ExportPlugin
|
||||
{
|
||||
@ -616,4 +603,12 @@ class ExportXml extends ExportPlugin
|
||||
{
|
||||
$this->tables = $tables;
|
||||
}
|
||||
|
||||
public function isAvailable(): bool
|
||||
{
|
||||
global $db;
|
||||
|
||||
// Can't do server export.
|
||||
return isset($db) && strlen($db) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ namespace PhpMyAdmin\Plugins;
|
||||
|
||||
use PhpMyAdmin\Export;
|
||||
use PhpMyAdmin\Properties\Plugins\ExportPluginProperties;
|
||||
use PhpMyAdmin\Properties\Plugins\PluginPropertyItem;
|
||||
use PhpMyAdmin\Relation;
|
||||
use PhpMyAdmin\Transformations;
|
||||
|
||||
@ -20,7 +21,7 @@ use function stripos;
|
||||
* methods, but those are not declared here, because they are not implemented
|
||||
* by all export plugins.
|
||||
*/
|
||||
abstract class ExportPlugin
|
||||
abstract class ExportPlugin implements Plugin
|
||||
{
|
||||
/**
|
||||
* PhpMyAdmin\Properties\Plugins\ExportPluginProperties object containing
|
||||
@ -259,7 +260,7 @@ abstract class ExportPlugin
|
||||
*
|
||||
* @return ExportPluginProperties
|
||||
*/
|
||||
public function getProperties()
|
||||
public function getProperties(): PluginPropertyItem
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
@ -411,4 +412,9 @@ abstract class ExportPlugin
|
||||
|
||||
return $relation;
|
||||
}
|
||||
|
||||
public function isAvailable(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* CSV import plugin for phpMyAdmin using LOAD DATA
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
@ -23,24 +20,18 @@ use function trim;
|
||||
|
||||
use const PHP_EOL;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
// We need relations enabled and we work only on database
|
||||
if (! isset($GLOBALS['plugin_param']) || $GLOBALS['plugin_param'] !== 'table') {
|
||||
$GLOBALS['skip_import'] = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// phpcs:enable
|
||||
|
||||
/**
|
||||
* Handles the import for the CSV format using load data
|
||||
* CSV import plugin for phpMyAdmin using LOAD DATA
|
||||
*/
|
||||
class ImportLdi extends AbstractImportCsv
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
if (! $this->isAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setProperties();
|
||||
}
|
||||
|
||||
@ -198,4 +189,12 @@ class ImportLdi extends AbstractImportCsv
|
||||
$this->import->runQuery('', '', $sql_data);
|
||||
$finished = true;
|
||||
}
|
||||
|
||||
public function isAvailable(): bool
|
||||
{
|
||||
global $plugin_param;
|
||||
|
||||
// We need relations enabled and we work only on database.
|
||||
return isset($plugin_param) && $plugin_param === 'table';
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ namespace PhpMyAdmin\Plugins;
|
||||
use PhpMyAdmin\File;
|
||||
use PhpMyAdmin\Import;
|
||||
use PhpMyAdmin\Properties\Plugins\ImportPluginProperties;
|
||||
use PhpMyAdmin\Properties\Plugins\PluginPropertyItem;
|
||||
|
||||
use function strlen;
|
||||
|
||||
@ -17,7 +18,7 @@ use function strlen;
|
||||
* Provides a common interface that will have to be implemented by all of the
|
||||
* import plugins.
|
||||
*/
|
||||
abstract class ImportPlugin
|
||||
abstract class ImportPlugin implements Plugin
|
||||
{
|
||||
/**
|
||||
* ImportPluginProperties object containing the import plugin properties
|
||||
@ -50,7 +51,7 @@ abstract class ImportPlugin
|
||||
*
|
||||
* @return ImportPluginProperties
|
||||
*/
|
||||
public function getProperties()
|
||||
public function getProperties(): PluginPropertyItem
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
@ -86,4 +87,9 @@ abstract class ImportPlugin
|
||||
$options,
|
||||
];
|
||||
}
|
||||
|
||||
public function isAvailable(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
14
libraries/classes/Plugins/Plugin.php
Normal file
14
libraries/classes/Plugins/Plugin.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Plugins;
|
||||
|
||||
use PhpMyAdmin\Properties\Plugins\PluginPropertyItem;
|
||||
|
||||
interface Plugin
|
||||
{
|
||||
public function getProperties(): PluginPropertyItem;
|
||||
|
||||
public function isAvailable(): bool;
|
||||
}
|
||||
@ -12,7 +12,6 @@ use PhpMyAdmin\Relation;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function class_exists;
|
||||
use function count;
|
||||
use function getcwd;
|
||||
use function is_array;
|
||||
@ -23,15 +22,6 @@ use function strlen;
|
||||
use function ucfirst;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
/**
|
||||
* Skip the plugin if TCPDF is not available.
|
||||
*/
|
||||
if (! class_exists('TCPDF')) {
|
||||
$GLOBALS['skip_import'] = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* block attempts to directly run this script
|
||||
*/
|
||||
|
||||
@ -14,7 +14,6 @@ use PhpMyAdmin\Util;
|
||||
|
||||
use function __;
|
||||
use function ceil;
|
||||
use function class_exists;
|
||||
use function getcwd;
|
||||
use function in_array;
|
||||
use function intval;
|
||||
@ -27,15 +26,6 @@ use function str_replace;
|
||||
use function strtotime;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
/**
|
||||
* Skip the plugin if TCPDF is not available.
|
||||
*/
|
||||
if (! class_exists('TCPDF')) {
|
||||
$GLOBALS['skip_import'] = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* block attempts to directly run this script
|
||||
*/
|
||||
|
||||
@ -14,8 +14,10 @@ use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyRootGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
|
||||
use PhpMyAdmin\Properties\Options\Items\SelectPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\SchemaPluginProperties;
|
||||
use TCPDF;
|
||||
|
||||
use function __;
|
||||
use function class_exists;
|
||||
|
||||
/**
|
||||
* Handles the schema export for the PDF format
|
||||
@ -124,4 +126,9 @@ class SchemaPdf extends SchemaPlugin
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isAvailable(): bool
|
||||
{
|
||||
return class_exists(TCPDF::class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ namespace PhpMyAdmin\Plugins;
|
||||
|
||||
use PhpMyAdmin\Properties\Options\Groups\OptionsPropertyMainGroup;
|
||||
use PhpMyAdmin\Properties\Options\Items\BoolPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\PluginPropertyItem;
|
||||
use PhpMyAdmin\Properties\Plugins\SchemaPluginProperties;
|
||||
|
||||
use function __;
|
||||
@ -19,7 +20,7 @@ use function __;
|
||||
* methods, but those are not declared here, because they are not implemented
|
||||
* by all export plugins.
|
||||
*/
|
||||
abstract class SchemaPlugin
|
||||
abstract class SchemaPlugin implements Plugin
|
||||
{
|
||||
/**
|
||||
* PhpMyAdmin\Properties\Plugins\SchemaPluginProperties object containing
|
||||
@ -34,7 +35,7 @@ abstract class SchemaPlugin
|
||||
*
|
||||
* @return SchemaPluginProperties
|
||||
*/
|
||||
public function getProperties()
|
||||
public function getProperties(): PluginPropertyItem
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
@ -85,4 +86,9 @@ abstract class SchemaPlugin
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function isAvailable(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
49
test/classes/PluginsTest.php
Normal file
49
test/classes/PluginsTest.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Tests;
|
||||
|
||||
use PhpMyAdmin\Plugins;
|
||||
|
||||
/**
|
||||
* @covers \PhpMyAdmin\Plugins
|
||||
*/
|
||||
class PluginsTest extends AbstractTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
parent::loadDefaultConfig();
|
||||
}
|
||||
|
||||
public function testGetExport(): void
|
||||
{
|
||||
global $plugin_param;
|
||||
|
||||
$plugins = Plugins::getExport('database', false);
|
||||
$this->assertEquals(['export_type' => 'database', 'single_table' => false], $plugin_param);
|
||||
$this->assertIsArray($plugins);
|
||||
$this->assertCount(14, $plugins);
|
||||
$this->assertContainsOnlyInstancesOf(Plugins\ExportPlugin::class, $plugins);
|
||||
}
|
||||
|
||||
public function testGetImport(): void
|
||||
{
|
||||
global $plugin_param;
|
||||
|
||||
$plugins = Plugins::getImport('database');
|
||||
$this->assertEquals('database', $plugin_param);
|
||||
$this->assertIsArray($plugins);
|
||||
$this->assertCount(6, $plugins);
|
||||
$this->assertContainsOnlyInstancesOf(Plugins\ImportPlugin::class, $plugins);
|
||||
}
|
||||
|
||||
public function testGetSchema(): void
|
||||
{
|
||||
$plugins = Plugins::getSchema();
|
||||
$this->assertIsArray($plugins);
|
||||
$this->assertCount(4, $plugins);
|
||||
$this->assertContainsOnlyInstancesOf(Plugins\SchemaPlugin::class, $plugins);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user