Merge pull request #19710 from kamil-tekiela/Relation-getTables
Refactor Relation::getTables
This commit is contained in:
commit
ebc7bd987f
@ -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
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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(...));
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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'
|
||||
) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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'],
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user