Merge pull request #19710 from kamil-tekiela/Relation-getTables

Refactor Relation::getTables
This commit is contained in:
Maurício Meneghini Fauth 2025-05-22 19:25:07 -03:00 committed by GitHub
commit ebc7bd987f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 63 additions and 107 deletions

View File

@ -1722,12 +1722,6 @@ parameters:
count: 1
path: src/ConfigStorage/Relation.php
-
message: '#^Parameter \#2 \$callback of function usort expects callable\(string\|null, string\|null\)\: int, Closure\(string, string\)\: int\<\-1, 1\> given\.$#'
identifier: argument.type
count: 1
path: src/ConfigStorage/Relation.php
-
message: '#^Parameter \#2 \$table of method PhpMyAdmin\\ConfigStorage\\Relation\:\:getDisplayField\(\) expects string, mixed given\.$#'
identifier: argument.type
@ -3513,24 +3507,12 @@ parameters:
count: 1
path: src/Controllers/Table/RelationController.php
-
message: '#^Parameter \#1 \$identifier of static method PhpMyAdmin\\Util\:\:backquote\(\) expects string\|Stringable\|null, mixed given\.$#'
identifier: argument.type
count: 2
path: src/Controllers/Table/RelationController.php
-
message: '#^Parameter \#1 \$multiEditColumnsName of method PhpMyAdmin\\Table\\Table\:\:updateInternalRelations\(\) expects array\<string\>, mixed given\.$#'
identifier: argument.type
count: 1
path: src/Controllers/Table/RelationController.php
-
message: '#^Parameter \#2 \$callback of function usort expects callable\(string\|null, string\|null\)\: int, Closure\(string, string\)\: int\<\-1, 1\> given\.$#'
identifier: argument.type
count: 1
path: src/Controllers/Table/RelationController.php
-
message: '#^Parameter \#2 \$destinationDb of method PhpMyAdmin\\Table\\Table\:\:updateInternalRelations\(\) expects array\<string\>, mixed given\.$#'
identifier: argument.type

View File

@ -613,9 +613,6 @@
<DeprecatedMethod>
<code><![CDATA[Config::getInstance()]]></code>
</DeprecatedMethod>
<InvalidArgument>
<code><![CDATA[usort($tables, strnatcasecmp(...))]]></code>
</InvalidArgument>
<InvalidReturnStatement>
<code><![CDATA[$tableNameReplacements]]></code>
</InvalidReturnStatement>
@ -2505,14 +2502,11 @@
<code><![CDATA[$_POST['destination_table']]]></code>
<code><![CDATA[$multiEditColumnsName]]></code>
<code><![CDATA[$multiEditColumnsName]]></code>
<code><![CDATA[usort($tables, strnatcasecmp(...))]]></code>
</InvalidArgument>
<PossiblyInvalidArgument>
<code><![CDATA[$_POST['display_field']]]></code>
<code><![CDATA[$_POST['foreignDb']]]></code>
<code><![CDATA[$_POST['foreignDb']]]></code>
<code><![CDATA[$_POST['foreignDb']]]></code>
<code><![CDATA[$_POST['foreignDb']]]></code>
<code><![CDATA[$foreignTable]]></code>
<code><![CDATA[$foreignTable]]></code>
</PossiblyInvalidArgument>

View File

@ -39,7 +39,6 @@ use function is_string;
use function ksort;
use function mb_check_encoding;
use function mb_strlen;
use function mb_strtoupper;
use function mb_substr;
use function natcasesort;
use function preg_match;
@ -1615,22 +1614,20 @@ class Relation
/**
* Get tables for foreign key constraint
*
* @param string $foreignDb Database name
* @param string $tblStorageEngine Table storage engine
* @param string $foreignDb Database name
* @param string $storageEngine Table storage engine
*
* @return mixed[] Table names
* @return string[] Table names
*/
public function getTables(string $foreignDb, string $tblStorageEngine): array
public function getTables(string $foreignDb, string $storageEngine): array
{
$tables = [];
$tablesRows = $this->dbi->query('SHOW TABLE STATUS FROM ' . Util::backquote($foreignDb));
while ($row = $tablesRows->fetchRow()) {
if (! isset($row[1]) || mb_strtoupper($row[1]) !== $tblStorageEngine) {
continue;
}
$tables[] = $row[0];
}
$tablesRows = $this->dbi->query(
'SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '
. $this->dbi->quoteString($foreignDb)
. ' AND ENGINE = ' . $this->dbi->quoteString($storageEngine),
);
/** @var list<string> $tables */
$tables = $tablesRows->fetchAllColumn();
if ($this->config->settings['NaturalOrder']) {
usort($tables, strnatcasecmp(...));

View File

@ -121,7 +121,7 @@ final readonly class TableController implements InvocableController
$showComment = '';
} else {
$tableIsAView = false;
$tableStorageEngine = $pmaTable->getStorageEngine();
$tableStorageEngine = mb_strtoupper($pmaTable->getStorageEngine());
$showComment = $pmaTable->getComment();
}
@ -215,17 +215,12 @@ final readonly class TableController implements InvocableController
}
}
$newTableStorageEngine = $request->getParsedBodyParamAsStringOrNull('new_tbl_storage_engine');
$newTblStorageEngine = '';
if (
is_string($newTableStorageEngine) && $newTableStorageEngine !== ''
&& mb_strtoupper($newTableStorageEngine) !== $tableStorageEngine
) {
$newTblStorageEngine = mb_strtoupper($newTableStorageEngine);
$newTableStorageEngine = mb_strtoupper($request->getParsedBodyParamAsString('new_tbl_storage_engine', ''));
$newStorageEngine = '';
if ($newTableStorageEngine !== '' && $newTableStorageEngine !== $tableStorageEngine) {
$newStorageEngine = $newTableStorageEngine;
if ($pmaTable->isEngine('ARIA')) {
$createOptions['transactional'] = ($createOptions['transactional'] ?? '')
== '0' ? '0' : '1';
$createOptions['transactional'] = ($createOptions['transactional'] ?? '') == '0' ? '0' : '1';
$createOptions['page_checksum'] ??= '';
}
}
@ -237,7 +232,7 @@ final readonly class TableController implements InvocableController
$createOptions['page_checksum'] ?? '',
empty($createOptions['delay_key_write']) ? '0' : '1',
$createOptions['row_format'] ?? $pmaTable->getRowFormat(),
$newTblStorageEngine,
$newStorageEngine,
isset($createOptions['transactional']) && $createOptions['transactional'] == '0' ? '0' : '1',
$tableCollation,
$tableStorageEngine,
@ -322,7 +317,7 @@ final readonly class TableController implements InvocableController
$showComment = '';
} else {
$tableIsAView = false;
$tableStorageEngine = $pmaTable->getStorageEngine();
$tableStorageEngine = mb_strtoupper($pmaTable->getStorageEngine());
$showComment = $pmaTable->getComment();
}

View File

@ -21,15 +21,12 @@ use PhpMyAdmin\ResponseRenderer;
use PhpMyAdmin\Table\Table;
use PhpMyAdmin\Template;
use PhpMyAdmin\UrlParams;
use PhpMyAdmin\Util;
use PhpMyAdmin\Utils\ForeignKey;
use function __;
use function array_keys;
use function mb_strtoupper;
use function md5;
use function strnatcasecmp;
use function strtoupper;
use function uksort;
use function usort;
@ -83,7 +80,11 @@ final readonly class RelationController implements InvocableController
if (isset($_POST['foreignTable'])) {
$this->getDropdownValueForTable();
} else { // if only the db is selected
$this->getDropdownValueForDatabase($storageEngine);
$this->getDropdownValueForDatabase(
$storageEngine,
$request->getParsedBodyParamAsString('foreignDb'),
$request->getParsedBodyParamAsString('foreign', ''),
);
}
return $this->response->response();
@ -162,14 +163,12 @@ final readonly class RelationController implements InvocableController
* Dialog
*/
// Now find out the columns of our $table
// need to use DatabaseInterface::QUERY_BUFFERED with $this->dbi->numRows()
// in mysqli
$columns = $this->dbi->getColumns(Current::$database, Current::$table);
$columnArray = [];
$columnArray[''] = '';
foreach ($columns as $column) {
if (strtoupper($storageEngine) !== 'INNODB' && $column->key === '') {
if ($storageEngine !== 'InnoDB' && $column->key === '') {
continue;
}
@ -204,7 +203,6 @@ final readonly class RelationController implements InvocableController
'one_key' => $oneKey,
'column_array' => $columnArray,
'options_array' => $options,
'tbl_storage_engine' => $storageEngine,
'db' => Current::$database,
'table' => Current::$table,
'url_params' => UrlParams::$params,
@ -223,7 +221,6 @@ final readonly class RelationController implements InvocableController
'one_key' => [],
'column_array' => $columnArray,
'options_array' => $options,
'tbl_storage_engine' => $storageEngine,
'db' => Current::$database,
'table' => Current::$table,
'url_params' => UrlParams::$params,
@ -389,32 +386,14 @@ final readonly class RelationController implements InvocableController
*
* @param string $storageEngine Storage engine.
*/
public function getDropdownValueForDatabase(string $storageEngine): void
public function getDropdownValueForDatabase(string $storageEngine, string $foreignDb, string $foreign): void
{
$tables = [];
$foreign = isset($_POST['foreign']) && $_POST['foreign'] === 'true';
$foreign = $foreign === 'true';
if ($foreign) {
$query = 'SHOW TABLE STATUS FROM '
. Util::backquote($_POST['foreignDb']);
$tablesRs = $this->dbi->query($query);
foreach ($tablesRs as $row) {
if (! isset($row['Engine']) || mb_strtoupper($row['Engine']) !== $storageEngine) {
continue;
}
$tables[] = $row['Name'];
}
$tables = $this->relation->getTables($foreignDb, $storageEngine);
} else {
$query = 'SHOW TABLES FROM '
. Util::backquote($_POST['foreignDb']);
$tablesRs = $this->dbi->query($query);
$tables = $tablesRs->fetchAllColumn();
}
if ($this->config->settings['NaturalOrder']) {
usort($tables, strnatcasecmp(...));
$tables = $this->dbi->getTables($foreignDb);
}
$this->response->addJSON('tables', $tables);

View File

@ -39,6 +39,7 @@ use stdClass;
use function __;
use function in_array;
use function str_contains;
use function strtoupper;
/**
* Displays table structure infos like columns, indexes, size, rows
@ -150,7 +151,7 @@ readonly class StructureController implements InvocableController
$tableStorageEngine = __('View');
} else {
$tableIsAView = false;
$tableStorageEngine = $this->tableObj->getStorageEngine();
$tableStorageEngine = strtoupper($this->tableObj->getStorageEngine());
}
// prepare comments
@ -235,11 +236,9 @@ readonly class StructureController implements InvocableController
];
}
$engine = $this->tableObj->getStorageEngine();
return $this->template->render('table/structure/display_structure', [
'collations' => $collations,
'is_foreign_key_supported' => ForeignKey::isSupported($engine),
'is_foreign_key_supported' => ForeignKey::isSupported($tableStorageEngine),
'indexes' => Index::getFromTable($this->dbi, Current::$table, Current::$database),
'indexes_duplicates' => Index::findDuplicates(Current::$table, Current::$database),
'relation_parameters' => $relationParameters,

View File

@ -711,7 +711,7 @@ class Operations
*
* @return string[]
*/
public function getWarningMessagesArray(mixed $newTableStorageEngine): array
public function getWarningMessagesArray(string $newTableStorageEngine): array
{
$warningMessages = [];
foreach ($this->dbi->getWarnings() as $warning) {
@ -722,7 +722,7 @@ class Operations
// I just ignore it. But there are other 1478 messages
// that it's better to show.
if (
$newTableStorageEngine === 'MyISAM'
$newTableStorageEngine === 'MYISAM'
&& $warning->code === 1478
&& $warning->level === 'Error'
) {

View File

@ -188,7 +188,7 @@ class Table implements Stringable
public function isEngine(array|string $engine): bool
{
$engine = (array) $engine;
$tableStorageEngine = $this->getStorageEngine();
$tableStorageEngine = strtoupper($this->getStorageEngine());
return in_array($tableStorageEngine, $engine, true);
}
@ -300,7 +300,7 @@ class Table implements Stringable
{
$tableStorageEngine = $this->getStatusInfo('ENGINE');
return strtoupper((string) $tableStorageEngine);
return (string) $tableStorageEngine;
}
/**

View File

@ -2243,4 +2243,25 @@ class RelationTest extends AbstractTestCase
$dummyDbi->assertAllQueriesConsumed();
}
public function testGetTablesReturnsFilteredTables(): void
{
$dummyDbi = $this->createDbiDummy();
$dbi = $this->createDatabaseInterface($dummyDbi);
$dummyDbi->addResult(
"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'somedb' AND ENGINE = 'InnoDB'",
[
['table1'],
['table3'],
],
);
$relation = new Relation($dbi);
$tables = $relation->getTables('somedb', 'InnoDB');
self::assertEquals(['table1', 'table3'], $tables);
$dummyDbi->assertAllQueriesConsumed();
}
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace PhpMyAdmin\Tests\Controllers\Table;
use Generator;
use PhpMyAdmin\Config;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\Controllers\Table\RelationController;
@ -132,10 +131,8 @@ class RelationControllerTest extends AbstractTestCase
->willReturn($resultStub);
$resultStub->expects(self::any())
->method('getIterator')
->willReturnCallback(static function (): Generator {
yield from [['Engine' => 'InnoDB', 'Name' => 'table']];
});
->method('fetchAllColumn')
->willReturn(['table']);
$ctrl = new RelationController(
$this->response,
@ -145,8 +142,7 @@ class RelationControllerTest extends AbstractTestCase
Config::getInstance(),
);
$_POST['foreign'] = 'true';
$ctrl->getDropdownValueForDatabase('INNODB');
$ctrl->getDropdownValueForDatabase('INNODB', 'db', 'true');
$json = $this->response->getJSONResult();
self::assertSame(
['table'],
@ -161,14 +157,8 @@ class RelationControllerTest extends AbstractTestCase
*/
public function testGetDropdownValueForDbActionTwo(): void
{
$resultStub = $this->createMock(DummyResult::class);
$this->dbi->expects(self::exactly(1))
->method('query')
->willReturn($resultStub);
$resultStub->expects(self::any())
->method('fetchAllColumn')
->method('getTables')
->willReturn(['table']);
$ctrl = new RelationController(
@ -179,8 +169,7 @@ class RelationControllerTest extends AbstractTestCase
Config::getInstance(),
);
$_POST['foreign'] = 'false';
$ctrl->getDropdownValueForDatabase('INNODB');
$ctrl->getDropdownValueForDatabase('INNODB', 'db', 'false');
$json = $this->response->getJSONResult();
self::assertSame(
['table'],

View File

@ -1456,7 +1456,7 @@ class TableTest extends AbstractTestCase
$dbi = DatabaseInterface::getInstanceForTest($extension);
$tblObject = new Table($targetTable, $targetDb, $dbi);
$tblObject->getStatusInfo(null);
$expect = 'DBIDUMMY';
$expect = 'DBIdummy';
$tblStorageEngine = $dbi->getTable($targetDb, $targetTable)->getStorageEngine();
self::assertSame($expect, $tblStorageEngine);
}