From 7fc625738bb151ee0384850ca6d6abbf53c74dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Wed, 28 Jan 2026 09:44:11 -0300 Subject: [PATCH] Extract dependencies from Import\Import class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Uses DI instead. Signed-off-by: MaurĂ­cio Meneghini Fauth --- app/services.php | 5 +- phpstan-baseline.neon | 45 ++++--- psalm-baseline.xml | 17 +-- src/Controllers/Database/ImportController.php | 4 +- src/Controllers/Server/ImportController.php | 4 +- src/Controllers/Table/ImportController.php | 4 +- src/Import/Import.php | 64 +++++----- src/Plugins/Import/ImportShp.php | 8 +- src/Plugins/ImportPlugin.php | 9 +- .../Import/ImportControllerTest.php | 2 +- tests/unit/Import/ImportTest.php | 8 +- tests/unit/Plugins/Import/ImportCsvTest.php | 120 +++++++++--------- .../Plugins/Import/ImportMediawikiTest.php | 28 ++-- tests/unit/Plugins/Import/ImportOdsTest.php | 49 +++---- tests/unit/Plugins/Import/ImportXmlTest.php | 23 +--- 15 files changed, 186 insertions(+), 204 deletions(-) diff --git a/app/services.php b/app/services.php index 54aa3ac7e6..426ddcfb60 100644 --- a/app/services.php +++ b/app/services.php @@ -124,7 +124,10 @@ return [ ], HttpRequest::class => ['class' => HttpRequest::class], ResponseFactory::class => ['class' => ResponseFactory::class, 'factory' => [ResponseFactory::class, 'create']], - Import::class => ['class' => Import::class], + Import::class => [ + 'class' => Import::class, + 'arguments' => [DatabaseInterface::class, ResponseRenderer::class, Config::class], + ], SimulateDml::class => ['class' => SimulateDml::class, 'arguments' => [DatabaseInterface::class]], InsertEdit::class => [ 'class' => InsertEdit::class, diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 51410e79ff..721df6dfe6 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -7059,24 +7059,6 @@ parameters: count: 1 path: src/Import/Ajax.php - - - message: ''' - #^Call to deprecated method getInstance\(\) of class PhpMyAdmin\\Config\: - Use dependency injection instead\.$# - ''' - identifier: staticMethod.deprecated - count: 4 - path: src/Import/Import.php - - - - message: ''' - #^Call to deprecated method getInstance\(\) of class PhpMyAdmin\\Dbal\\DatabaseInterface\: - Use dependency injection instead\.$# - ''' - identifier: staticMethod.deprecated - count: 5 - path: src/Import/Import.php - - message: '#^Cannot access property \$precision on int\|PhpMyAdmin\\Import\\DecimalSize\.$#' identifier: property.nonObject @@ -9645,6 +9627,15 @@ parameters: Use dependency injection instead\.$# ''' identifier: staticMethod.deprecated + count: 2 + path: src/Plugins/Import/ImportShp.php + + - + message: ''' + #^Call to deprecated method getInstance\(\) of class PhpMyAdmin\\Dbal\\DatabaseInterface\: + Use dependency injection instead\.$# + ''' + identifier: staticMethod.deprecated count: 1 path: src/Plugins/Import/ImportShp.php @@ -9921,6 +9912,24 @@ parameters: count: 1 path: src/Plugins/Import/Upload/UploadSession.php + - + message: ''' + #^Call to deprecated method getInstance\(\) of class PhpMyAdmin\\Config\: + Use dependency injection instead\.$# + ''' + identifier: staticMethod.deprecated + count: 1 + path: src/Plugins/ImportPlugin.php + + - + message: ''' + #^Call to deprecated method getInstance\(\) of class PhpMyAdmin\\Dbal\\DatabaseInterface\: + Use dependency injection instead\.$# + ''' + identifier: staticMethod.deprecated + count: 1 + path: src/Plugins/ImportPlugin.php + - message: '#^Cannot cast mixed to string\.$#' identifier: cast.string diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 59dc080997..8d0ef1f973 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -4931,17 +4931,6 @@ - - - - - - - - - - - @@ -6509,6 +6498,8 @@ + + @@ -6681,6 +6672,10 @@ + + + + diff --git a/src/Controllers/Database/ImportController.php b/src/Controllers/Database/ImportController.php index 2db488a76a..3ec690e5f4 100644 --- a/src/Controllers/Database/ImportController.php +++ b/src/Controllers/Database/ImportController.php @@ -85,7 +85,7 @@ final readonly class ImportController implements InvocableController $timeoutPassed = $_REQUEST['timeout_passed'] ?? null; $localImportFile = $_REQUEST['local_import_file'] ?? null; - $compressions = Import::getCompressions(); + $compressions = Import::getCompressions($this->config); $charsets = Charsets::getCharsets($this->dbi, $this->config->selectedServer['DisableIS']); @@ -126,7 +126,7 @@ final readonly class ImportController implements InvocableController 'charsets' => $charsets, 'is_foreign_key_check' => ForeignKey::isCheckEnabled(), 'user_upload_dir' => Util::userDir($this->config->config->UploadDir), - 'local_files' => Import::getLocalFiles($importList), + 'local_files' => Import::getLocalFiles($this->config, $importList), ]); return $this->response->response(); diff --git a/src/Controllers/Server/ImportController.php b/src/Controllers/Server/ImportController.php index 214bc8f527..e97a8a2f91 100644 --- a/src/Controllers/Server/ImportController.php +++ b/src/Controllers/Server/ImportController.php @@ -70,7 +70,7 @@ final readonly class ImportController implements InvocableController $timeoutPassed = $_REQUEST['timeout_passed'] ?? null; $localImportFile = $_REQUEST['local_import_file'] ?? null; - $compressions = Import::getCompressions(); + $compressions = Import::getCompressions($this->config); $charsets = Charsets::getCharsets($this->dbi, $this->config->selectedServer['DisableIS']); @@ -111,7 +111,7 @@ final readonly class ImportController implements InvocableController 'charsets' => $charsets, 'is_foreign_key_check' => ForeignKey::isCheckEnabled(), 'user_upload_dir' => Util::userDir($this->config->config->UploadDir), - 'local_files' => Import::getLocalFiles($importList), + 'local_files' => Import::getLocalFiles($this->config, $importList), ]); return $this->response->response(); diff --git a/src/Controllers/Table/ImportController.php b/src/Controllers/Table/ImportController.php index 6a3ab79f87..c08fb39faf 100644 --- a/src/Controllers/Table/ImportController.php +++ b/src/Controllers/Table/ImportController.php @@ -109,7 +109,7 @@ final readonly class ImportController implements InvocableController $timeoutPassed = $request->getParam('timeout_passed'); $localImportFile = $request->getParam('local_import_file'); - $compressions = Import::getCompressions(); + $compressions = Import::getCompressions($this->config); $charsets = Charsets::getCharsets($this->dbi, $this->config->selectedServer['DisableIS']); @@ -155,7 +155,7 @@ final readonly class ImportController implements InvocableController 'charsets' => $charsets, 'is_foreign_key_check' => ForeignKey::isCheckEnabled(), 'user_upload_dir' => Util::userDir($this->config->config->UploadDir), - 'local_files' => Import::getLocalFiles($importList), + 'local_files' => Import::getLocalFiles($this->config, $importList), ]); return $this->response->response(); diff --git a/src/Import/Import.php b/src/Import/Import.php index fc3c48d08e..27ba319e58 100644 --- a/src/Import/Import.php +++ b/src/Import/Import.php @@ -59,7 +59,7 @@ use function trim; /** * Library that provides common import functions that are used by import plugins */ -class Import +final class Import { private string|null $importRunBuffer = null; public static bool $hasError = false; @@ -68,9 +68,12 @@ class Import public static string $errorUrl = ''; private bool $forceExecute = false; - public function __construct() - { - Config::getInstance()->selectedServer['DisableIS'] = false; + public function __construct( + private readonly DatabaseInterface $dbi, + private readonly ResponseRenderer $responseRenderer, + private readonly Config $config, + ) { + $this->config->selectedServer['DisableIS'] = false; } /** @@ -106,8 +109,7 @@ class Import */ public function executeQuery(string $sql, array &$sqlData): void { - $dbi = DatabaseInterface::getInstance(); - self::$result = $dbi->tryQuery($sql); + self::$result = $this->dbi->tryQuery($sql); // USE query changes the database, son need to track // while running multiple queries @@ -115,18 +117,18 @@ class Import ImportSettings::$message = '# '; if (self::$result === false) { - ImportSettings::$failedQueries[] = ['sql' => $sql, 'error' => $dbi->getError()]; + ImportSettings::$failedQueries[] = ['sql' => $sql, 'error' => $this->dbi->getError()]; ImportSettings::$message .= __('Error'); - if (! Config::getInstance()->settings['IgnoreMultiSubmitErrors']) { + if (! $this->config->settings['IgnoreMultiSubmitErrors']) { self::$hasError = true; return; } } else { $aNumRows = (int) self::$result->numRows(); - $aAffectedRows = (int) @$dbi->affectedRows(); + $aAffectedRows = (int) @$this->dbi->affectedRows(); if ($aNumRows > 0) { ImportSettings::$message .= __('Rows') . ': ' . $aNumRows; } elseif ($aAffectedRows > 0) { @@ -759,7 +761,7 @@ class Import if ($analyses !== null) { /* TODO: Do more checking here to make sure they really are matched */ if (count($tables) !== count($analyses)) { - ResponseRenderer::getInstance()->callExit(); + $this->responseRenderer->callExit(); } /* Create SQL code to create the tables */ @@ -809,7 +811,6 @@ class Import * * Only one insert query is formed for each table */ - $dbi = DatabaseInterface::getInstance(); foreach ($tables as $tableIndex => $table) { $numCols = count($table->columns); $lastColumnKey = array_key_last($table->columns); @@ -856,7 +857,7 @@ class Import } $tempSQLStr .= $isVarchar - ? $dbi->quoteString((string) $row[$columnIndex]) + ? $this->dbi->quoteString((string) $row[$columnIndex]) : (string) $row[$columnIndex]; } @@ -919,7 +920,7 @@ class Import $tables[] = new ImportTable($regs[1]); } - $message = $this->getSuccessMessage($dbName, $tables, $dbi); + $message = $this->getSuccessMessage($dbName, $tables); ImportSettings::$importNotice = $message; } @@ -928,7 +929,6 @@ class Import { $sqlDelimiter = $_POST['sql_delimiter']; $queries = explode($sqlDelimiter, $sqlQuery); - $dbi = DatabaseInterface::getInstance(); foreach ($queries as $sqlQuery) { if ($sqlQuery === '') { continue; @@ -939,19 +939,18 @@ class Import continue; } - $sqlError = $dbi->getError(); + $sqlError = $this->dbi->getError(); $error = $sqlError !== '' ? $sqlError : __( 'Only INSERT, UPDATE, DELETE, REPLACE and SET (without options like GLOBAL) ' . 'SQL queries containing transactional engine tables can be rolled back.', ); - $response = ResponseRenderer::getInstance(); - $response->addJSON('message', Message::rawError($error)); - $response->callExit(); + $this->responseRenderer->addJSON('message', Message::rawError($error)); + $this->responseRenderer->callExit(); } // If everything fine, START a transaction. - $dbi->query('START TRANSACTION'); + $this->dbi->query('START TRANSACTION'); } /** @@ -1019,8 +1018,7 @@ class Import . '.' . Util::backquote($table) . ' ' . 'LIMIT 1'; - $dbi = DatabaseInterface::getInstance(); - $result = $dbi->tryQuery($checkTableQuery); + $result = $this->dbi->tryQuery($checkTableQuery); if (! $result) { return false; @@ -1040,23 +1038,21 @@ class Import // Query to check if table is 'Transactional'. $checkQuery = 'SELECT `ENGINE` FROM `information_schema`.`tables` ' - . 'WHERE `table_name` = ' . $dbi->quoteString($table) . ' ' - . 'AND `table_schema` = ' . $dbi->quoteString($db) . ' ' + . 'WHERE `table_name` = ' . $this->dbi->quoteString($table) . ' ' + . 'AND `table_schema` = ' . $this->dbi->quoteString($db) . ' ' . 'AND UPPER(`engine`) IN ("' . implode('", "', $transactionalEngines) . '")'; - $result = $dbi->tryQuery($checkQuery); + $result = $this->dbi->tryQuery($checkQuery); return $result && $result->numRows() === 1; } /** @return string[] */ - public static function getCompressions(): array + public static function getCompressions(Config $config): array { $compressions = []; - - $config = Config::getInstance(); if ($config->config->GZipDump && function_exists('gzopen')) { $compressions[] = 'gzip'; } @@ -1073,7 +1069,7 @@ class Import } /** @param ImportPlugin[] $importList List of plugin instances. */ - public static function getLocalFiles(array $importList): false|string + public static function getLocalFiles(Config $config, array $importList): false|string { $fileListing = new FileListing(); @@ -1093,7 +1089,7 @@ class Import : ''; return $fileListing->getFileSelectOptions( - Util::userDir(Config::getInstance()->config->UploadDir), + Util::userDir($config->config->UploadDir), $matcher, $active, ); @@ -1109,7 +1105,7 @@ class Import $importFileName = (string) preg_replace('/[^\x{0001}-\x{FFFF}]/u', '_', $importFileName); if ($databaseName !== '') { - $existingTables = DatabaseInterface::getInstance()->getTables($databaseName); + $existingTables = $this->dbi->getTables($databaseName); // check to see if {filename} as table exist // if no use filename as table name @@ -1144,7 +1140,7 @@ class Import } /** @param ImportTable[] $tables */ - private function getHtmlListForAllTables(array $tables, string $dbName, DatabaseInterface $dbi): string + private function getHtmlListForAllTables(array $tables, string $dbName): string { $message = '