Merge pull request #18845 from kamil-tekiela/Favorites

Refactor Favorites + DbTableExists
This commit is contained in:
Maurício Meneghini Fauth 2023-12-14 13:55:37 -03:00 committed by GitHub
commit 2a3550e185
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 448 additions and 629 deletions

View File

@ -2537,7 +2537,7 @@ parameters:
-
message: "#^Cannot access offset 'db' on mixed\\.$#"
count: 2
count: 1
path: src/Controllers/Database/Structure/FavoriteTableController.php
-
@ -2547,7 +2547,7 @@ parameters:
-
message: "#^Cannot access offset 'table' on mixed\\.$#"
count: 2
count: 1
path: src/Controllers/Database/Structure/FavoriteTableController.php
-
@ -2560,21 +2560,6 @@ parameters:
count: 1
path: src/Controllers/Database/Structure/FavoriteTableController.php
-
message: "#^Parameter \\#1 \\$currentTable of method PhpMyAdmin\\\\Controllers\\\\Database\\\\Structure\\\\FavoriteTableController\\:\\:checkFavoriteTable\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/Controllers/Database/Structure/FavoriteTableController.php
-
message: "#^Parameter \\#1 \\$db of method PhpMyAdmin\\\\RecentFavoriteTable\\:\\:add\\(\\) expects string, mixed given\\.$#"
count: 2
path: src/Controllers/Database/Structure/FavoriteTableController.php
-
message: "#^Parameter \\#1 \\$db of method PhpMyAdmin\\\\RecentFavoriteTable\\:\\:remove\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/Controllers/Database/Structure/FavoriteTableController.php
-
message: "#^Parameter \\#1 \\$json of function json_decode expects string, mixed given\\.$#"
count: 1
@ -2585,21 +2570,6 @@ parameters:
count: 1
path: src/Controllers/Database/Structure/FavoriteTableController.php
-
message: "#^Parameter \\#1 \\$string of function md5 expects string, mixed given\\.$#"
count: 1
path: src/Controllers/Database/Structure/FavoriteTableController.php
-
message: "#^Parameter \\#2 \\$table of method PhpMyAdmin\\\\RecentFavoriteTable\\:\\:add\\(\\) expects string, mixed given\\.$#"
count: 2
path: src/Controllers/Database/Structure/FavoriteTableController.php
-
message: "#^Parameter \\#2 \\$table of method PhpMyAdmin\\\\RecentFavoriteTable\\:\\:remove\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/Controllers/Database/Structure/FavoriteTableController.php
-
message: "#^Parameter \\#3 \\$favoriteTables of method PhpMyAdmin\\\\Controllers\\\\Database\\\\Structure\\\\FavoriteTableController\\:\\:synchronizeFavoriteTables\\(\\) expects array, mixed given\\.$#"
count: 1
@ -2735,16 +2705,6 @@ parameters:
count: 1
path: src/Controllers/Database/StructureController.php
-
message: "#^Cannot access offset 'db' on mixed\\.$#"
count: 1
path: src/Controllers/Database/StructureController.php
-
message: "#^Cannot access offset 'table' on mixed\\.$#"
count: 1
path: src/Controllers/Database/StructureController.php
-
message: "#^Only booleans are allowed in &&, int\\|false given on the right side\\.$#"
count: 1
@ -2795,11 +2755,6 @@ parameters:
count: 1
path: src/Controllers/Database/StructureController.php
-
message: "#^Parameter \\#1 \\$currentTable of method PhpMyAdmin\\\\Controllers\\\\Database\\\\StructureController\\:\\:checkFavoriteTable\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/Controllers/Database/StructureController.php
-
message: "#^Parameter \\#1 \\$currentTable of method PhpMyAdmin\\\\Controllers\\\\Database\\\\StructureController\\:\\:getStuffForEngineTypeTable\\(\\) expects array, mixed given\\.$#"
count: 1
@ -10280,6 +10235,61 @@ parameters:
count: 1
path: src/Export/Template.php
-
message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#"
count: 1
path: src/Favorites/RecentFavoriteTables.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be true\\.$#"
count: 1
path: src/Favorites/RecentFavoriteTables.php
-
message: "#^Cannot access an offset on mixed\\.$#"
count: 1
path: src/Favorites/RecentFavoriteTables.php
-
message: "#^Cannot access offset 'favoriteTables'\\|'recentTables' on mixed\\.$#"
count: 5
path: src/Favorites/RecentFavoriteTables.php
-
message: "#^Cannot access offset 'favorites_synced' on mixed\\.$#"
count: 1
path: src/Favorites/RecentFavoriteTables.php
-
message: "#^Cannot access offset mixed on mixed\\.$#"
count: 1
path: src/Favorites/RecentFavoriteTables.php
-
message: "#^Cannot access offset string on mixed\\.$#"
count: 5
path: src/Favorites/RecentFavoriteTables.php
-
message: "#^Cannot cast mixed to string\\.$#"
count: 1
path: src/Favorites/RecentFavoriteTables.php
-
message: "#^Method PhpMyAdmin\\\\Favorites\\\\RecentFavoriteTables\\:\\:getFromDb\\(\\) should return array\\<array\\{db\\: string, table\\: string\\}\\> but returns mixed\\.$#"
count: 1
path: src/Favorites/RecentFavoriteTables.php
-
message: "#^Parameter \\#1 \\$array of static method PhpMyAdmin\\\\Favorites\\\\RecentFavoriteTable\\:\\:fromArray\\(\\) expects array\\{db\\: string, table\\: string\\}, mixed given\\.$#"
count: 1
path: src/Favorites/RecentFavoriteTables.php
-
message: "#^Parameter \\#1 \\$str of method PhpMyAdmin\\\\DatabaseInterface\\:\\:quoteString\\(\\) expects string, string\\|false given\\.$#"
count: 1
path: src/Favorites/RecentFavoriteTables.php
-
message: "#^Cannot access offset 'multi_edit' on mixed\\.$#"
count: 7
@ -10895,11 +10905,6 @@ parameters:
count: 1
path: src/Header.php
-
message: "#^Parameter \\#1 \\$db of method PhpMyAdmin\\\\Header\\:\\:addRecentTable\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/Header.php
-
message: "#^Parameter \\#1 \\$message of static method PhpMyAdmin\\\\Html\\\\Generator\\:\\:getMessage\\(\\) expects PhpMyAdmin\\\\Message\\|string, mixed given\\.$#"
count: 1
@ -10910,11 +10915,6 @@ parameters:
count: 1
path: src/Header.php
-
message: "#^Parameter \\#2 \\$table of method PhpMyAdmin\\\\Header\\:\\:addRecentTable\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/Header.php
-
message: "#^Parameter \\#3 \\$db of class PhpMyAdmin\\\\Menu constructor expects string, mixed given\\.$#"
count: 1
@ -16035,86 +16035,6 @@ parameters:
count: 4
path: src/Query/Utilities.php
-
message: "#^Cannot access offset 'db' on mixed\\.$#"
count: 6
path: src/RecentFavoriteTable.php
-
message: "#^Cannot access offset 'favoriteTables'\\|'recentTables' on mixed\\.$#"
count: 3
path: src/RecentFavoriteTable.php
-
message: "#^Cannot access offset 'favorites_synced' on mixed\\.$#"
count: 1
path: src/RecentFavoriteTable.php
-
message: "#^Cannot access offset 'table' on mixed\\.$#"
count: 6
path: src/RecentFavoriteTable.php
-
message: "#^Cannot access offset mixed on mixed\\.$#"
count: 3
path: src/RecentFavoriteTable.php
-
message: "#^Method PhpMyAdmin\\\\RecentFavoriteTable\\:\\:getFromDb\\(\\) should return array but returns mixed\\.$#"
count: 1
path: src/RecentFavoriteTable.php
-
message: "#^Only booleans are allowed in a negated boolean, PhpMyAdmin\\\\Dbal\\\\ResultInterface\\|false given\\.$#"
count: 1
path: src/RecentFavoriteTable.php
-
message: "#^Only booleans are allowed in a ternary operator condition, string\\|null given\\.$#"
count: 1
path: src/RecentFavoriteTable.php
-
message: "#^Only booleans are allowed in an if condition, PhpMyAdmin\\\\Dbal\\\\ResultInterface\\|false given\\.$#"
count: 1
path: src/RecentFavoriteTable.php
-
message: "#^Only booleans are allowed in an if condition, string\\|null given\\.$#"
count: 2
path: src/RecentFavoriteTable.php
-
message: "#^Parameter \\#1 \\$database of method PhpMyAdmin\\\\DatabaseInterface\\:\\:getColumns\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/RecentFavoriteTable.php
-
message: "#^Parameter \\#1 \\$db of method PhpMyAdmin\\\\RecentFavoriteTable\\:\\:remove\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/RecentFavoriteTable.php
-
message: "#^Parameter \\#1 \\$str of method PhpMyAdmin\\\\DatabaseInterface\\:\\:quoteString\\(\\) expects string, string\\|false given\\.$#"
count: 1
path: src/RecentFavoriteTable.php
-
message: "#^Parameter \\#2 \\$table of method PhpMyAdmin\\\\DatabaseInterface\\:\\:getColumns\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/RecentFavoriteTable.php
-
message: "#^Parameter \\#2 \\$table of method PhpMyAdmin\\\\RecentFavoriteTable\\:\\:remove\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/RecentFavoriteTable.php
-
message: "#^Property PhpMyAdmin\\\\RecentFavoriteTable\\:\\:\\$tables \\(array\\) does not accept mixed\\.$#"
count: 1
path: src/RecentFavoriteTable.php
-
message: "#^Cannot access offset 'File' on mixed\\.$#"
count: 1
@ -19340,16 +19260,6 @@ parameters:
count: 1
path: tests/classes/Controllers/Database/PrivilegesControllerTest.php
-
message: "#^Cannot access offset 'favoriteTables' on mixed\\.$#"
count: 1
path: tests/classes/Controllers/Database/Structure/FavoriteTableControllerTest.php
-
message: "#^Parameter \\#2 \\$array of method PHPUnit\\\\Framework\\\\Assert\\:\\:assertArrayHasKey\\(\\) expects array\\|ArrayAccess, mixed given\\.$#"
count: 1
path: tests/classes/Controllers/Database/Structure/FavoriteTableControllerTest.php
-
message: "#^Cannot access offset 'COUNTED' on mixed\\.$#"
count: 4

View File

@ -1493,16 +1493,11 @@
<code><![CDATA[$GLOBALS['errorUrl']]]></code>
</InvalidArrayOffset>
<MixedArgument>
<code>$favoriteTable</code>
<code>$favoriteTables</code>
<code>$favoriteTables</code>
<code><![CDATA[$value['db']]]></code>
<code><![CDATA[$value['table']]]></code>
</MixedArgument>
<MixedArrayAccess>
<code><![CDATA[$value['db']]]></code>
<code><![CDATA[$value['db']]]></code>
<code><![CDATA[$value['table']]]></code>
<code><![CDATA[$value['table']]]></code>
</MixedArrayAccess>
<MixedArrayAssignment>
@ -1512,11 +1507,9 @@
</MixedArrayAssignment>
<MixedAssignment>
<code><![CDATA[$GLOBALS['errorUrl']]]></code>
<code>$favoriteTable</code>
<code>$favoriteTables</code>
<code>$favoriteTables</code>
<code>$value</code>
<code>$value</code>
</MixedAssignment>
</file>
<file src="src/Controllers/Database/Structure/RealRowCountController.php">
@ -1612,7 +1605,6 @@
<code><![CDATA[$currentTable['TABLE_NAME']]]></code>
<code><![CDATA[$currentTable['TABLE_NAME']]]></code>
<code><![CDATA[$currentTable['TABLE_NAME']]]></code>
<code><![CDATA[$currentTable['TABLE_NAME']]]></code>
<code>$dbTable</code>
<code>$overheadSize</code>
<code><![CDATA[$replicaInfo['Do_DB']]]></code>
@ -1647,8 +1639,6 @@
<code><![CDATA[$currentTable['TABLE_ROWS']]]></code>
<code><![CDATA[$currentTable['TABLE_TYPE']]]></code>
<code><![CDATA[$currentTable['Update_time']]]></code>
<code><![CDATA[$value['db']]]></code>
<code><![CDATA[$value['table']]]></code>
</MixedArrayAccess>
<MixedArrayAssignment>
<code><![CDATA[$currentTable['TABLE_ROWS']]]></code>
@ -1671,7 +1661,6 @@
<code>$truename</code>
<code>$updateTime</code>
<code>$updateTimeAll</code>
<code>$value</code>
</MixedAssignment>
<MixedMethodCall>
<code>getCharset</code>
@ -5925,6 +5914,45 @@
<code><![CDATA[$state['username']]]></code>
</MixedArgument>
</file>
<file src="src/Favorites/RecentFavoriteTables.php">
<DeprecatedMethod>
<code>Config::getInstance()</code>
<code>Config::getInstance()</code>
<code>Config::getInstance()</code>
<code>DatabaseInterface::getInstance()</code>
</DeprecatedMethod>
<MixedArgument>
<code>$table</code>
</MixedArgument>
<MixedArrayAccess>
<code><![CDATA[$_SESSION['tmpval'][$this->tableType->value . 'Tables']]]></code>
<code><![CDATA[$_SESSION['tmpval'][$this->tableType->value . 'Tables'][$this->serverId]]]></code>
</MixedArrayAccess>
<MixedArrayAssignment>
<code><![CDATA[$_SESSION['tmpval'][$this->tableType->value . 'Tables']]]></code>
<code><![CDATA[$_SESSION['tmpval'][$this->tableType->value . 'Tables']]]></code>
<code><![CDATA[$_SESSION['tmpval'][$this->tableType->value . 'Tables']]]></code>
<code><![CDATA[$_SESSION['tmpval'][$this->tableType->value . 'Tables'][$this->serverId]]]></code>
<code><![CDATA[$_SESSION['tmpval'][$this->tableType->value . 'Tables'][$this->serverId]]]></code>
<code><![CDATA[$_SESSION['tmpval'][$this->tableType->value . 'Tables'][$this->serverId]]]></code>
</MixedArrayAssignment>
<MixedAssignment>
<code>$table</code>
</MixedAssignment>
<MixedInferredReturnType>
<code>array{db:string, table:string}[]</code>
</MixedInferredReturnType>
<MixedReturnStatement>
<code>json_decode($value, true)</code>
</MixedReturnStatement>
<PossiblyNullOperand>
<code><![CDATA[$this->getPmaTable()]]></code>
<code><![CDATA[$this->getPmaTable()]]></code>
</PossiblyNullOperand>
<PossiblyUnusedReturnValue>
<code>bool|Message</code>
</PossiblyUnusedReturnValue>
</file>
<file src="src/File.php">
<DeprecatedMethod>
<code>Config::getInstance()</code>
@ -10548,76 +10576,6 @@
<code><![CDATA[$_SESSION['debug']['queries']]]></code>
</MixedArrayAssignment>
</file>
<file src="src/RecentFavoriteTable.php">
<DeprecatedMethod>
<code>Config::getInstance()</code>
<code>Config::getInstance()</code>
<code>Config::getInstance()</code>
<code>DatabaseInterface::getInstance()</code>
<code>DatabaseInterface::getInstance()</code>
<code>DatabaseInterface::getInstance()</code>
<code>DatabaseInterface::getInstance()</code>
<code>DatabaseInterface::getInstance()</code>
</DeprecatedMethod>
<MixedArgument>
<code><![CDATA[$tbl['db']]]></code>
<code><![CDATA[$tbl['db']]]></code>
<code><![CDATA[$tbl['table']]]></code>
<code><![CDATA[$tbl['table']]]></code>
</MixedArgument>
<MixedArrayAccess>
<code><![CDATA[$_SESSION['tmpval'][$this->tableType . 'Tables']]]></code>
<code><![CDATA[$_SESSION['tmpval'][$this->tableType . 'Tables'][$serverId]]]></code>
<code><![CDATA[$table['db']]]></code>
<code><![CDATA[$table['db']]]></code>
<code><![CDATA[$table['db']]]></code>
<code><![CDATA[$table['db']]]></code>
<code><![CDATA[$table['table']]]></code>
<code><![CDATA[$table['table']]]></code>
<code><![CDATA[$table['table']]]></code>
<code><![CDATA[$table['table']]]></code>
<code><![CDATA[$tbl['db']]]></code>
<code><![CDATA[$tbl['db']]]></code>
<code><![CDATA[$tbl['db']]]></code>
<code><![CDATA[$tbl['table']]]></code>
<code><![CDATA[$tbl['table']]]></code>
<code><![CDATA[$tbl['table']]]></code>
<code><![CDATA[$value['db']]]></code>
<code><![CDATA[$value['table']]]></code>
</MixedArrayAccess>
<MixedArrayAssignment>
<code><![CDATA[$_SESSION['tmpval'][$this->tableType . 'Tables']]]></code>
<code><![CDATA[$_SESSION['tmpval'][$this->tableType . 'Tables'][$serverId]]]></code>
</MixedArrayAssignment>
<MixedAssignment>
<code>$table</code>
<code>$table</code>
<code>$tbl</code>
<code><![CDATA[$this->tables]]></code>
<code>$value</code>
</MixedAssignment>
<MixedInferredReturnType>
<code>mixed[]</code>
</MixedInferredReturnType>
<MixedOperand>
<code><![CDATA[$table['db']]]></code>
<code><![CDATA[$table['table']]]></code>
</MixedOperand>
<MixedReturnStatement>
<code>json_decode($value, true)</code>
</MixedReturnStatement>
<PossiblyNullOperand>
<code><![CDATA[$this->getPmaTable()]]></code>
<code><![CDATA[$this->getPmaTable()]]></code>
</PossiblyNullOperand>
<PossiblyUnusedReturnValue>
<code>bool</code>
<code>bool|Message</code>
</PossiblyUnusedReturnValue>
<UnsupportedReferenceUsage>
<code><![CDATA[$this->tables =& $_SESSION['tmpval'][$this->tableType . 'Tables'][$serverId]]]></code>
</UnsupportedReferenceUsage>
</file>
<file src="src/Replication/Replication.php">
<MixedArgument>
<code><![CDATA[$pos['File']]]></code>
@ -13227,17 +13185,6 @@
<code>Config::getInstance()</code>
</DeprecatedMethod>
</file>
<file src="tests/classes/Controllers/Database/Structure/FavoriteTableControllerTest.php">
<MixedArgument>
<code>$json</code>
</MixedArgument>
<MixedArrayAccess>
<code><![CDATA[$json['favoriteTables']]]></code>
</MixedArrayAccess>
<MixedAssignment>
<code>$json</code>
</MixedAssignment>
</file>
<file src="tests/classes/Controllers/Database/Structure/RealRowCountControllerTest.php">
<DeprecatedMethod>
<code>Config::getInstance()</code>

View File

@ -159,7 +159,7 @@ class DesignerController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -57,7 +57,7 @@ final class EventsController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
$this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]);
return;

View File

@ -61,7 +61,7 @@ final class ExportController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -59,7 +59,7 @@ final class ImportController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -77,7 +77,7 @@ class RoutinesController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
$this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]);
return;
@ -103,7 +103,7 @@ class RoutinesController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
$this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]);
return;

View File

@ -47,7 +47,7 @@ class SearchController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -58,7 +58,7 @@ class SqlController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -8,16 +8,20 @@ use PhpMyAdmin\Config;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\Controllers\AbstractController;
use PhpMyAdmin\DbTableExists;
use PhpMyAdmin\Favorites\RecentFavoriteTable;
use PhpMyAdmin\Favorites\RecentFavoriteTables;
use PhpMyAdmin\Favorites\TableType;
use PhpMyAdmin\Http\ServerRequest;
use PhpMyAdmin\Identifiers\DatabaseName;
use PhpMyAdmin\Identifiers\TableName;
use PhpMyAdmin\Message;
use PhpMyAdmin\RecentFavoriteTable;
use PhpMyAdmin\ResponseRenderer;
use PhpMyAdmin\Template;
use PhpMyAdmin\Url;
use PhpMyAdmin\Util;
use function __;
use function array_map;
use function count;
use function json_decode;
use function json_encode;
@ -51,7 +55,7 @@ final class FavoriteTableController extends AbstractController
return;
}
$favoriteInstance = RecentFavoriteTable::getInstance('favorite');
$favoriteInstance = RecentFavoriteTables::getInstance(TableType::Favorite);
$favoriteTables = $request->getParam('favoriteTables');
$favoriteTables = $favoriteTables !== null ? json_decode($favoriteTables, true) : [];
@ -74,7 +78,7 @@ final class FavoriteTableController extends AbstractController
}
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));
@ -82,13 +86,19 @@ final class FavoriteTableController extends AbstractController
}
$changes = true;
$favoriteTable = $request->getParam('favorite_table', '');
$alreadyFavorite = $this->checkFavoriteTable($favoriteTable);
/** @var string $favoriteTableName */
$favoriteTableName = $request->getParam('favorite_table', '');
// TODO: Why is this $GLOBALS['db'] instead of $databaseName
$favoriteTable = new RecentFavoriteTable(
DatabaseName::from($GLOBALS['db']),
TableName::from($favoriteTableName),
);
$alreadyFavorite = $favoriteInstance->contains($favoriteTable);
if (isset($_REQUEST['remove_favorite'])) {
if ($alreadyFavorite) {
// If already in favorite list, remove it.
$favoriteInstance->remove($GLOBALS['db'], $favoriteTable);
$favoriteInstance->remove($favoriteTable);
$alreadyFavorite = false; // for favorite_anchor template
}
} elseif (isset($_REQUEST['add_favorite'])) {
@ -98,13 +108,16 @@ final class FavoriteTableController extends AbstractController
$changes = false;
} else {
// Otherwise add to favorite list.
$favoriteInstance->add($GLOBALS['db'], $favoriteTable);
$favoriteInstance->add($favoriteTable);
$alreadyFavorite = true; // for favorite_anchor template
}
}
}
$favoriteTables[$user] = $favoriteInstance->getTables();
$favoriteTables[$user] = array_map(
static fn (RecentFavoriteTable $table) => $table->toArray(),
$favoriteInstance->getTables(),
);
$json = [];
$json['changes'] = $changes;
@ -121,7 +134,7 @@ final class FavoriteTableController extends AbstractController
$favoriteParams = [
'db' => $GLOBALS['db'],
'ajax_request' => true,
'favorite_table' => $favoriteTable,
'favorite_table' => $favoriteTableName,
($alreadyFavorite ? 'remove' : 'add') . '_favorite' => true,
];
@ -129,8 +142,8 @@ final class FavoriteTableController extends AbstractController
$json['favoriteTables'] = json_encode($favoriteTables);
$json['list'] = $favoriteInstance->getHtmlList();
$json['anchor'] = $this->template->render('database/structure/favorite_anchor', [
'table_name_hash' => md5($favoriteTable),
'db_table_name_hash' => md5($GLOBALS['db'] . '.' . $favoriteTable),
'table_name_hash' => md5($favoriteTableName),
'db_table_name_hash' => md5($GLOBALS['db'] . '.' . $favoriteTableName),
'fav_params' => $favoriteParams,
'already_favorite' => $alreadyFavorite,
]);
@ -141,47 +154,34 @@ final class FavoriteTableController extends AbstractController
/**
* Synchronize favorite tables
*
* @param RecentFavoriteTable $favoriteInstance Instance of this class
* @param string $user The user hash
* @param mixed[] $favoriteTables Existing favorites
* @param RecentFavoriteTables $favoriteInstance Instance of this class
* @param string $user The user hash
* @param mixed[] $favoriteTables Existing favorites
*
* @return mixed[]
*/
private function synchronizeFavoriteTables(
RecentFavoriteTable $favoriteInstance,
RecentFavoriteTables $favoriteInstance,
string $user,
array $favoriteTables,
): array {
$favoriteInstanceTables = $favoriteInstance->getTables();
if ($favoriteInstanceTables === [] && isset($favoriteTables[$user])) {
if ($favoriteInstance->getTables() === [] && isset($favoriteTables[$user])) {
foreach ($favoriteTables[$user] as $value) {
$favoriteInstance->add($value['db'], $value['table']);
$favoriteInstance->add(new RecentFavoriteTable(
DatabaseName::from($value['db']),
TableName::from($value['table']),
));
}
}
$favoriteTables[$user] = $favoriteInstance->getTables();
$favoriteTables[$user] = array_map(
static fn (RecentFavoriteTable $table) => $table->toArray(),
$favoriteInstance->getTables(),
);
// Set flag when localStorage and pmadb(if present) are in sync.
$_SESSION['tmpval']['favorites_synced'][$GLOBALS['server']] = true;
return ['favoriteTables' => json_encode($favoriteTables), 'list' => $favoriteInstance->getHtmlList()];
}
/**
* Function to check if a table is already in favorite list.
*
* @param string $currentTable current table
*/
private function checkFavoriteTable(string $currentTable): bool
{
$recentFavoriteTables = RecentFavoriteTable::getInstance('favorite');
foreach ($recentFavoriteTables->getTables() as $value) {
if ($value['db'] == $GLOBALS['db'] && $value['table'] == $currentTable) {
return true;
}
}
return false;
}
}

View File

@ -56,7 +56,7 @@ final class RealRowCountController extends AbstractController
}
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -12,12 +12,15 @@ use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\Controllers\AbstractController;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\DbTableExists;
use PhpMyAdmin\Favorites\RecentFavoriteTable;
use PhpMyAdmin\Favorites\RecentFavoriteTables;
use PhpMyAdmin\Favorites\TableType;
use PhpMyAdmin\Html\Generator;
use PhpMyAdmin\Http\ServerRequest;
use PhpMyAdmin\Identifiers\DatabaseName;
use PhpMyAdmin\Identifiers\TableName;
use PhpMyAdmin\Message;
use PhpMyAdmin\Query\Utilities;
use PhpMyAdmin\RecentFavoriteTable;
use PhpMyAdmin\Replication\Replication;
use PhpMyAdmin\Replication\ReplicationInfo;
use PhpMyAdmin\ResponseRenderer;
@ -134,7 +137,7 @@ class StructureController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));
@ -235,6 +238,7 @@ class StructureController extends AbstractController
$overallApproxRows = false;
$structureTableRows = [];
$trackedTables = $this->trackingChecker->getTrackedTables($GLOBALS['db']);
$recentFavoriteTables = RecentFavoriteTables::getInstance(TableType::Favorite);
foreach ($this->tables as $currentTable) {
// Get valid statistics whatever is the table type
@ -429,7 +433,12 @@ class StructureController extends AbstractController
'do' => $do,
'approx_rows' => $approxRows,
'show_superscript' => $showSuperscript,
'already_favorite' => $this->checkFavoriteTable($currentTable['TABLE_NAME']),
'already_favorite' => $recentFavoriteTables->contains(
new RecentFavoriteTable(
DatabaseName::from($GLOBALS['db']),
TableName::from($currentTable['TABLE_NAME']),
),
),
'num_favorite_tables' => $config->settings['NumFavoriteTables'],
'properties_num_columns' => $config->settings['PropertiesNumColumns'],
'limit_chars' => $config->settings['LimitChars'],
@ -611,23 +620,6 @@ class StructureController extends AbstractController
return [$do, $ignored];
}
/**
* Function to check if a table is already in favorite list.
*
* @param string $currentTable current table
*/
protected function checkFavoriteTable(string $currentTable): bool
{
$recentFavoriteTables = RecentFavoriteTable::getInstance('favorite');
foreach ($recentFavoriteTables->getTables() as $value) {
if ($value['db'] == $GLOBALS['db'] && $value['table'] == $currentTable) {
return true;
}
}
return false;
}
/**
* Find table with truename
*

View File

@ -56,7 +56,7 @@ class TrackingController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -11,6 +11,8 @@ use PhpMyAdmin\CheckUserPrivileges;
use PhpMyAdmin\Config;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Favorites\RecentFavoriteTables;
use PhpMyAdmin\Favorites\TableType;
use PhpMyAdmin\Git;
use PhpMyAdmin\Html\Generator;
use PhpMyAdmin\Http\Factory\ResponseFactory;
@ -20,7 +22,6 @@ use PhpMyAdmin\Identifiers\DatabaseName;
use PhpMyAdmin\Identifiers\TableName;
use PhpMyAdmin\LanguageManager;
use PhpMyAdmin\Message;
use PhpMyAdmin\RecentFavoriteTable;
use PhpMyAdmin\ResponseRenderer;
use PhpMyAdmin\Server\Select;
use PhpMyAdmin\Template;
@ -104,7 +105,7 @@ class HomeController extends AbstractController
unset($_SESSION['partial_logout']);
}
$syncFavoriteTables = RecentFavoriteTable::getInstance('favorite')
$syncFavoriteTables = RecentFavoriteTables::getInstance(TableType::Favorite)
->getHtmlSyncFavoriteTables();
$config = Config::getInstance();

View File

@ -58,7 +58,7 @@ final class CollationController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -226,7 +226,7 @@ class DatabaseController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -81,7 +81,7 @@ class TableController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -57,7 +57,7 @@ class ViewController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -4,8 +4,9 @@ declare(strict_types=1);
namespace PhpMyAdmin\Controllers;
use PhpMyAdmin\Favorites\RecentFavoriteTables;
use PhpMyAdmin\Favorites\TableType;
use PhpMyAdmin\Http\ServerRequest;
use PhpMyAdmin\RecentFavoriteTable;
final class RecentTablesListController extends AbstractController
{
@ -15,6 +16,6 @@ final class RecentTablesListController extends AbstractController
return;
}
$this->response->addJSON(['list' => RecentFavoriteTable::getInstance('recent')->getHtmlList()]);
$this->response->addJSON(['list' => RecentFavoriteTables::getInstance(TableType::Recent)->getHtmlList()]);
}
}

View File

@ -152,7 +152,7 @@ class AddFieldController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($urlParams, '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -63,7 +63,7 @@ class ChangeController extends AbstractController
$this->response->addHTML($this->pageSettings->getHTML());
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -100,7 +100,7 @@ class ChartController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($urlParams, '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));
@ -142,7 +142,7 @@ class ChartController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));
@ -228,7 +228,7 @@ class ChartController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -56,7 +56,7 @@ final class DeleteConfirmController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -45,7 +45,7 @@ final class DropColumnConfirmationController extends AbstractController
return;
}
if (! $this->dbTableExists->hasDatabase($db)) {
if (! $this->dbTableExists->selectDatabase($db)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -71,7 +71,7 @@ class FindReplaceController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -52,7 +52,7 @@ final class GisVisualizationController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -62,7 +62,7 @@ final class ImportController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -52,7 +52,7 @@ final class IndexRenameController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -59,7 +59,7 @@ class IndexesController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -5,11 +5,13 @@ declare(strict_types=1);
namespace PhpMyAdmin\Controllers\Table;
use PhpMyAdmin\Controllers\AbstractController;
use PhpMyAdmin\Favorites\RecentFavoriteTable;
use PhpMyAdmin\Favorites\RecentFavoriteTables;
use PhpMyAdmin\Favorites\TableType;
use PhpMyAdmin\Http\ServerRequest;
use PhpMyAdmin\Identifiers\DatabaseName;
use PhpMyAdmin\Identifiers\InvalidIdentifier;
use PhpMyAdmin\Identifiers\TableName;
use PhpMyAdmin\RecentFavoriteTable;
use function __;
@ -29,8 +31,9 @@ final class RecentFavoriteController extends AbstractController
return;
}
RecentFavoriteTable::getInstance('recent')->removeIfInvalid($db->getName(), $table->getName());
RecentFavoriteTable::getInstance('favorite')->removeIfInvalid($db->getName(), $table->getName());
$favoriteTable = new RecentFavoriteTable($db, $table);
RecentFavoriteTables::getInstance(TableType::Recent)->removeIfInvalid($favoriteTable);
RecentFavoriteTables::getInstance(TableType::Favorite)->removeIfInvalid($favoriteTable);
$this->redirect('/sql', ['db' => $db->getName(), 'table' => $table->getName()]);
}

View File

@ -171,7 +171,7 @@ class SearchController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -60,7 +60,7 @@ class SqlController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($urlParams, '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -69,7 +69,7 @@ final class PrimaryController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -96,7 +96,7 @@ class StructureController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($urlParams, '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -65,7 +65,7 @@ final class TrackingController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -96,7 +96,7 @@ class ZoomSearchController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -70,7 +70,7 @@ final class IndexController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon($GLOBALS['urlParams'], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
$this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]);
return;
@ -96,7 +96,7 @@ final class IndexController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
$this->redirect('/', ['reload' => true, 'message' => __('No databases selected.')]);
return;

View File

@ -69,7 +69,7 @@ class CreateController extends AbstractController
$GLOBALS['errorUrl'] .= Url::getCommon(['db' => $GLOBALS['db']], '&');
$databaseName = DatabaseName::tryFrom($request->getParam('db'));
if ($databaseName === null || ! $this->dbTableExists->hasDatabase($databaseName)) {
if ($databaseName === null || ! $this->dbTableExists->selectDatabase($databaseName)) {
if ($request->isAjax()) {
$this->response->setRequestStatus(false);
$this->response->addJSON('message', Message::error(__('No databases selected.')));

View File

@ -12,9 +12,6 @@ use function sprintf;
final class DbTableExists
{
/** @psalm-var list<non-empty-string> */
private array $databases = [];
/** @psalm-var list<non-empty-string> */
private array $tables = [];
@ -22,32 +19,22 @@ final class DbTableExists
{
}
public function hasDatabase(DatabaseName $databaseName): bool
public function selectDatabase(DatabaseName $databaseName): bool
{
if (in_array($databaseName->getName(), $this->databases, true)) {
return true;
}
if ($this->dbi->selectDb($databaseName)) {
$this->databases[] = $databaseName->getName();
return true;
}
return false;
return $this->dbi->selectDb($databaseName);
}
/**
* Check if a table exists in the given database.
* It will return true if the table exists, regardless if it's temporary or permanent.
*/
public function hasTable(DatabaseName $database, TableName $table): bool
{
if (in_array($database->getName() . '.' . $table->getName(), $this->tables, true)) {
return true;
}
if (
$this->hasCachedTableContent($database, $table)
|| $this->isPermanentTable($table)
|| $this->isTemporaryTable($table)
) {
if ($this->tableExists($database, $table)) {
$this->tables[] = $database->getName() . '.' . $table->getName();
return true;
@ -56,24 +43,13 @@ final class DbTableExists
return false;
}
private function hasCachedTableContent(DatabaseName $database, TableName $table): bool
private function tableExists(DatabaseName $database, TableName $table): bool
{
return (bool) $this->dbi->getCache()->getCachedTableContent([$database->getName(), $table->getName()]);
}
private function isPermanentTable(TableName $table): bool
{
$result = $this->dbi->tryQuery(sprintf('SHOW TABLES LIKE %s;', $this->dbi->quoteString($table->getName())));
return $result !== false && $result->numRows() > 0;
}
/**
* SHOW TABLES doesn't show temporary tables, so try select
* as it can happen just in case temporary table. It should be fast.
*/
private function isTemporaryTable(TableName $table): bool
{
return $this->dbi->tryQuery(sprintf('SELECT 1 FROM %s LIMIT 1;', Util::backquote($table))) !== false;
// SHOW TABLES doesn't show temporary tables, so try select.
return $this->dbi->tryQuery(sprintf(
'SELECT 1 FROM %s.%s LIMIT 1;',
Util::backquote($database),
Util::backquote($table),
)) !== false;
}
}

View File

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Favorites;
use PhpMyAdmin\Identifiers\DatabaseName;
use PhpMyAdmin\Identifiers\TableName;
final class RecentFavoriteTable
{
public function __construct(public readonly DatabaseName $db, public readonly TableName $table)
{
}
/** @param array{db:string, table:string} $array */
public static function fromArray(array $array): self
{
return new self(DatabaseName::from($array['db']), TableName::from($array['table']));
}
/** @return array{db:string, table:string} $array */
public function toArray(): array
{
return ['db' => $this->db->getName(), 'table' => $this->table->getName()];
}
}

View File

@ -5,18 +5,26 @@
declare(strict_types=1);
namespace PhpMyAdmin;
namespace PhpMyAdmin\Favorites;
use PhpMyAdmin\Config;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Dbal\Connection;
use PhpMyAdmin\DbTableExists;
use PhpMyAdmin\Message;
use PhpMyAdmin\Template;
use PhpMyAdmin\Url;
use PhpMyAdmin\Util;
use function __;
use function array_key_exists;
use function array_merge;
use function array_pop;
use function array_unique;
use function array_unshift;
use function array_values;
use function count;
use function in_array;
use function is_string;
use function json_decode;
use function json_encode;
@ -32,65 +40,75 @@ use const SORT_REGULAR;
* @TODO Change the release version in table pma_recent
* (#recent in documentation)
*/
class RecentFavoriteTable
class RecentFavoriteTables
{
/**
* Reference to session variable containing recently used or favorite tables.
*
* @var mixed[]
*/
/** @var RecentFavoriteTable[] */
private array $tables = [];
/**
* RecentFavoriteTable instances.
*
* @var array<string,RecentFavoriteTable>
* @var array<string,RecentFavoriteTables>
*/
private static array $instances = [];
private Relation $relation;
/**
* Creates a new instance of RecentFavoriteTable
*
* @param string $tableType Defines type of action, Favorite or Recent table.
* @phpstan-param 'favorite'|'recent' $tableType
*/
private function __construct(public Template $template, private string $tableType)
{
$this->relation = new Relation(DatabaseInterface::getInstance());
$serverId = $GLOBALS['server'];
private function __construct(
public Template $template,
private readonly TableType $tableType,
private readonly string $serverId,
private readonly DatabaseInterface $dbi,
private readonly Relation $relation,
private readonly DbTableExists $dbTableExists,
) {
// Code search hint: recentTables
// Code search hint: favoriteTables
if (! isset($_SESSION['tmpval'][$this->tableType . 'Tables'][$serverId])) {
$_SESSION['tmpval'][$this->tableType . 'Tables'][$serverId] = $this->getPmaTable()
if (! isset($_SESSION['tmpval'][$this->tableType->value . 'Tables'][$this->serverId])) {
$_SESSION['tmpval'][$this->tableType->value . 'Tables'][$this->serverId] = $this->getPmaTable() !== null
? $this->getFromDb()
: [];
}
$this->tables =& $_SESSION['tmpval'][$this->tableType . 'Tables'][$serverId];
foreach ($_SESSION['tmpval'][$this->tableType->value . 'Tables'][$this->serverId] as $table) {
$this->tables[] = RecentFavoriteTable::fromArray($table);
}
}
public function __destruct()
{
$_SESSION['tmpval'][$this->tableType->value . 'Tables'][$this->serverId] = [];
foreach ($this->tables as $table) {
$_SESSION['tmpval'][$this->tableType->value . 'Tables'][$this->serverId][] = $table->toArray();
}
}
/**
* Returns class instance.
*
* @param string $type the table type
* @psalm-param 'favorite'|'recent' $type
*/
public static function getInstance(string $type): RecentFavoriteTable
public static function getInstance(TableType $type): RecentFavoriteTables
{
if (! array_key_exists($type, self::$instances)) {
if (! array_key_exists($type->value, self::$instances)) {
$template = new Template();
self::$instances[$type] = new RecentFavoriteTable($template, $type);
$dbi = DatabaseInterface::getInstance();
self::$instances[$type->value] = new RecentFavoriteTables(
$template,
$type,
(string) $GLOBALS['server'],
$dbi,
new Relation($dbi),
new DbTableExists($dbi),
);
}
return self::$instances[$type];
return self::$instances[$type->value];
}
/**
* Returns the recent/favorite tables array
*
* @return mixed[]
* @return RecentFavoriteTable[]
*/
public function getTables(): array
{
@ -100,18 +118,17 @@ class RecentFavoriteTable
/**
* Returns recently used tables or favorite from phpMyAdmin database.
*
* @return mixed[]
* @return array{db:string, table:string}[]
*/
public function getFromDb(): array
private function getFromDb(): array
{
// Read from phpMyAdmin database, if recent tables is not in session
$dbi = DatabaseInterface::getInstance();
$sqlQuery = ' SELECT `tables` FROM ' . $this->getPmaTable()
. ' WHERE `username` = '
. $dbi->quoteString(Config::getInstance()->selectedServer['user'], Connection::TYPE_CONTROL);
. $this->dbi->quoteString(Config::getInstance()->selectedServer['user'], Connection::TYPE_CONTROL);
$result = $dbi->tryQueryAsControlUser($sqlQuery);
if ($result) {
$result = $this->dbi->tryQueryAsControlUser($sqlQuery);
if ($result !== false) {
$value = $result->fetchValue();
if (is_string($value)) {
return json_decode($value, true);
@ -126,25 +143,23 @@ class RecentFavoriteTable
*
* @return true|Message
*/
public function saveToDb(): bool|Message
private function saveToDb(): bool|Message
{
$username = Config::getInstance()->selectedServer['user'];
$dbi = DatabaseInterface::getInstance();
$sqlQuery = ' REPLACE INTO ' . $this->getPmaTable() . ' (`username`, `tables`)'
. ' VALUES (' . $dbi->quoteString($username) . ', '
. $dbi->quoteString(json_encode($this->tables)) . ')';
. ' VALUES (' . $this->dbi->quoteString($username) . ', '
. $this->dbi->quoteString(json_encode($this->tables)) . ')';
$success = $dbi->tryQuery($sqlQuery, Connection::TYPE_CONTROL);
$success = $this->dbi->tryQuery($sqlQuery, Connection::TYPE_CONTROL);
if (! $success) {
$errorMsg = match ($this->tableType) {
'recent' => __('Could not save recent table!'),
'favorite' => __('Could not save favorite table!'),
};
if ($success === false) {
$message = Message::error(match ($this->tableType) {
TableType::Recent => __('Could not save recent table!'),
TableType::Favorite => __('Could not save favorite table!'),
});
$message = Message::error($errorMsg);
$message->addMessage(
Message::rawError($dbi->getError(Connection::TYPE_CONTROL)),
Message::rawError($this->dbi->getError(Connection::TYPE_CONTROL)),
'<br><br>',
);
@ -155,21 +170,19 @@ class RecentFavoriteTable
}
/**
* Trim recent.favorite table according to the
* Trim recent/favorite table according to the
* NumRecentTables/NumFavoriteTables configuration.
*/
public function trim(): bool
private function trim(): void
{
$max = max(
Config::getInstance()->settings['Num' . ucfirst($this->tableType) . 'Tables'],
Config::getInstance()->settings['Num' . ucfirst($this->tableType->value) . 'Tables'],
0,
);
$trimmingOccurred = count($this->tables) > $max;
while (count($this->tables) > $max) {
array_pop($this->tables);
}
return $trimmingOccurred;
}
/**
@ -178,10 +191,10 @@ class RecentFavoriteTable
public function getHtmlList(): string
{
if ($this->tables !== []) {
if ($this->tableType === 'recent') {
if ($this->tableType === TableType::Recent) {
$tables = [];
foreach ($this->tables as $table) {
$tables[] = ['db' => $table['db'], 'table' => $table['table']];
$tables[] = $table->toArray();
}
return $this->template->render('recent_favorite_table_recent', ['tables' => $tables]);
@ -190,15 +203,15 @@ class RecentFavoriteTable
$tables = [];
foreach ($this->tables as $table) {
$removeParameters = [
'db' => $table['db'],
'db' => $table->db,
'ajax_request' => true,
'favorite_table' => $table['table'],
'favorite_table' => $table->table,
'remove_favorite' => true,
];
$tableParameters = [
'db' => $table['db'],
'table' => $table['table'],
'md5' => md5($table['db'] . '.' . $table['table']),
'db' => $table->db,
'table' => $table->table,
'md5' => md5($table->db . '.' . $table->table),
];
$tables[] = ['remove_parameters' => $removeParameters, 'table_parameters' => $tableParameters];
@ -208,14 +221,14 @@ class RecentFavoriteTable
}
return $this->template->render('recent_favorite_table_no_tables', [
'is_recent' => $this->tableType === 'recent',
'is_recent' => $this->tableType === TableType::Recent,
]);
}
public function getHtml(): string
{
$html = '<div class="drop_list">';
if ($this->tableType === 'recent') {
if ($this->tableType === TableType::Recent) {
$html .= '<button title="' . __('Recent tables')
. '" class="drop_button btn btn-sm btn-outline-secondary">'
. __('Recent') . '</button><ul id="pma_recent_list">';
@ -234,28 +247,20 @@ class RecentFavoriteTable
/**
* Add recently used or favorite tables.
*
* @param string $db database name where the table is located
* @param string $table table name
*
* @return true|Message True if success, Message if not
*/
public function add(string $db, string $table): bool|Message
public function add(RecentFavoriteTable $newTable): bool|Message
{
// If table does not exist, do not add._getPmaTable()
if (DatabaseInterface::getInstance()->getColumns($db, $table) === []) {
if (! $this->dbTableExists->hasTable($newTable->db, $newTable->table)) {
return true;
}
$tableArr = [];
$tableArr['db'] = $db;
$tableArr['table'] = $table;
// add only if this is new table
if (! isset($this->tables[0]) || $this->tables[0] != $tableArr) {
array_unshift($this->tables, $tableArr);
$this->tables = array_merge(array_unique($this->tables, SORT_REGULAR));
if (! isset($this->tables[0]) || $this->tables[0] != $newTable) {
array_unshift($this->tables, $newTable);
$this->tables = array_values(array_unique($this->tables, SORT_REGULAR));
$this->trim();
if ($this->getPmaTable()) {
if ($this->getPmaTable() !== null) {
return $this->saveToDb();
}
}
@ -266,22 +271,21 @@ class RecentFavoriteTable
/**
* Removes recent/favorite tables that don't exist.
*
* @param string $db database
* @param string $table table
*
* @return bool|Message True if invalid and removed, False if not invalid,
* Message if error while removing
*/
public function removeIfInvalid(string $db, string $table): bool|Message
public function removeIfInvalid(RecentFavoriteTable $tableToRemove): bool|Message
{
foreach ($this->tables as $tbl) {
if ($tbl['db'] != $db || $tbl['table'] != $table) {
foreach ($this->tables as $table) {
if (
$table->db->getName() !== $tableToRemove->db->getName()
|| $table->table->getName() !== $tableToRemove->table->getName()
) {
continue;
}
// TODO Figure out a better way to find the existence of a table
if (DatabaseInterface::getInstance()->getColumns($tbl['db'], $tbl['table']) === []) {
return $this->remove($tbl['db'], $tbl['table']);
if (! $this->dbTableExists->hasTable($table->db, $table->table)) {
return $this->remove($tableToRemove);
}
}
@ -291,28 +295,38 @@ class RecentFavoriteTable
/**
* Remove favorite tables.
*
* @param string $db database name where the table is located
* @param string $table table name
*
* @return true|Message True if success, Message if not
*/
public function remove(string $db, string $table): bool|Message
public function remove(RecentFavoriteTable $tableToRemove): bool|Message
{
foreach ($this->tables as $key => $value) {
if ($value['db'] != $db || $value['table'] != $table) {
foreach ($this->tables as $key => $table) {
if (
$table->db->getName() !== $tableToRemove->db->getName()
|| $table->table->getName() !== $tableToRemove->table->getName()
) {
continue;
}
unset($this->tables[$key]);
}
if ($this->getPmaTable()) {
if ($this->getPmaTable() !== null) {
return $this->saveToDb();
}
return true;
}
/**
* Function to check if a table is already in favorite list.
*/
public function contains(RecentFavoriteTable $currentTable): bool
{
// When looking for the value we are looking for a similar object with
// the same public properties, not the same instance. The in_array must be loose comparison.
return in_array($currentTable, $this->tables, false);
}
/**
* Generate Html for sync Favorite tables anchor. (from localStorage to pmadb)
*/
@ -360,12 +374,12 @@ class RecentFavoriteTable
private function getPmaTable(): string|null
{
$relationParameters = $this->relation->getRelationParameters();
if ($this->tableType === 'recent' && $relationParameters->recentlyUsedTablesFeature !== null) {
if ($this->tableType === TableType::Recent && $relationParameters->recentlyUsedTablesFeature !== null) {
return Util::backquote($relationParameters->recentlyUsedTablesFeature->database)
. '.' . Util::backquote($relationParameters->recentlyUsedTablesFeature->recent);
}
if ($this->tableType === 'favorite' && $relationParameters->favoriteTablesFeature !== null) {
if ($this->tableType === TableType::Favorite && $relationParameters->favoriteTablesFeature !== null) {
return Util::backquote($relationParameters->favoriteTablesFeature->database)
. '.' . Util::backquote($relationParameters->favoriteTablesFeature->favorite);
}

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Favorites;
enum TableType: string
{
case Recent = 'recent';
case Favorite = 'favorite';
}

View File

@ -8,7 +8,12 @@ declare(strict_types=1);
namespace PhpMyAdmin;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\Favorites\RecentFavoriteTable;
use PhpMyAdmin\Favorites\RecentFavoriteTables;
use PhpMyAdmin\Favorites\TableType;
use PhpMyAdmin\Html\Generator;
use PhpMyAdmin\Identifiers\DatabaseName;
use PhpMyAdmin\Identifiers\TableName;
use PhpMyAdmin\Navigation\Navigation;
use PhpMyAdmin\Theme\ThemeManager;
@ -257,8 +262,11 @@ class Header
}
$recentTable = '';
if (empty($_REQUEST['recent_table'])) {
$recentTable = $this->addRecentTable($GLOBALS['db'], $GLOBALS['table']);
if (empty($_REQUEST['recent_table']) && $GLOBALS['table'] !== '') {
$recentTable = $this->addRecentTable(
DatabaseName::from($GLOBALS['db']),
TableName::from($GLOBALS['table']),
);
}
if ($this->isAjax) {
@ -588,16 +596,14 @@ class Header
/**
* Add recently used table and reload the navigation.
*
* @param string $db Database name where the table is located.
* @param string $table The table name
*/
private function addRecentTable(string $db, string $table): string
private function addRecentTable(DatabaseName $db, TableName $table): string
{
if ($this->menuEnabled && $table !== '' && Config::getInstance()->settings['NumRecentTables'] > 0) {
$error = RecentFavoriteTable::getInstance('recent')->add($db, $table);
if ($this->menuEnabled && Config::getInstance()->settings['NumRecentTables'] > 0) {
$favoriteTable = new RecentFavoriteTable($db, $table);
$error = RecentFavoriteTables::getInstance(TableType::Recent)->add($favoriteTable);
if ($error === true) {
return RecentFavoriteTable::getHtmlUpdateRecentTables();
return RecentFavoriteTables::getHtmlUpdateRecentTables();
}
return $error->getDisplay();

View File

@ -12,6 +12,8 @@ use PhpMyAdmin\Config;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\ConfigStorage\RelationParameters;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Favorites\RecentFavoriteTables;
use PhpMyAdmin\Favorites\TableType;
use PhpMyAdmin\Html\Generator;
use PhpMyAdmin\Navigation\Nodes\Node;
use PhpMyAdmin\Navigation\Nodes\NodeColumn;
@ -32,7 +34,6 @@ use PhpMyAdmin\Navigation\Nodes\NodeTrigger;
use PhpMyAdmin\Navigation\Nodes\NodeTriggerContainer;
use PhpMyAdmin\Navigation\Nodes\NodeView;
use PhpMyAdmin\Navigation\Nodes\NodeViewContainer;
use PhpMyAdmin\RecentFavoriteTable;
use PhpMyAdmin\ResponseRenderer;
use PhpMyAdmin\Template;
use PhpMyAdmin\Url;
@ -1383,11 +1384,11 @@ class NavigationTree
$renderDetails = [];
$config = Config::getInstance();
if ($config->settings['NumRecentTables'] > 0) {
$renderDetails['recent'] = RecentFavoriteTable::getInstance('recent')->getHtml();
$renderDetails['recent'] = RecentFavoriteTables::getInstance(TableType::Recent)->getHtml();
}
if ($config->settings['NumFavoriteTables'] > 0) {
$renderDetails['favorite'] = RecentFavoriteTable::getInstance('favorite')->getHtml();
$renderDetails['favorite'] = RecentFavoriteTables::getInstance(TableType::Favorite)->getHtml();
}
return $this->template->render('navigation/tree/quick_warp', $renderDetails);

View File

@ -9,7 +9,7 @@ use PhpMyAdmin\Config;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\ConfigStorage\RelationParameters;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\RecentFavoriteTable;
use PhpMyAdmin\Favorites\RecentFavoriteTables;
use PhpMyAdmin\Tests\AbstractTestCase;
use PhpMyAdmin\Tests\Stubs\DummyResult;
use PHPUnit\Framework\Attributes\CoversClass;
@ -1908,7 +1908,7 @@ class RelationTest extends AbstractTestCase
$_SESSION['tmpval'] = [];
(new ReflectionProperty(Relation::class, 'cache'))->setValue(null, null);
(new ReflectionProperty(RecentFavoriteTable::class, 'instances'))->setValue(null, []);
(new ReflectionProperty(RecentFavoriteTables::class, 'instances'))->setValue(null, []);
$relation = new Relation($dbi);
$relation->initRelationParamsCache();

View File

@ -8,62 +8,58 @@ use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\Controllers\Database\Structure\FavoriteTableController;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\DbTableExists;
use PhpMyAdmin\RecentFavoriteTable;
use PhpMyAdmin\Favorites\RecentFavoriteTables;
use PhpMyAdmin\Favorites\TableType;
use PhpMyAdmin\Template;
use PhpMyAdmin\Tests\AbstractTestCase;
use PhpMyAdmin\Tests\Stubs\DbiDummy;
use PhpMyAdmin\Tests\Stubs\ResponseRenderer as ResponseStub;
use PHPUnit\Framework\Attributes\CoversClass;
use ReflectionClass;
use ReflectionMethod;
use ReflectionProperty;
use function json_encode;
#[CoversClass(FavoriteTableController::class)]
class FavoriteTableControllerTest extends AbstractTestCase
final class FavoriteTableControllerTest extends AbstractTestCase
{
protected DatabaseInterface $dbi;
protected DbiDummy $dummyDbi;
protected function setUp(): void
{
parent::setUp();
$this->dummyDbi = $this->createDbiDummy();
$this->dbi = $this->createDatabaseInterface($this->dummyDbi);
DatabaseInterface::$instance = $this->dbi;
}
public function testSynchronizeFavoriteTables(): void
{
$GLOBALS['server'] = 1;
$GLOBALS['text_dir'] = 'ltr';
$GLOBALS['db'] = 'db';
$favoriteInstance = $this->getMockBuilder(RecentFavoriteTable::class)
->disableOriginalConstructor()
->getMock();
$favoriteInstance->expects($this->exactly(2))
->method('getTables')
->willReturn([[]], [['db' => 'db', 'table' => 'table']]);
$dbiDummy = $this->createDbiDummy();
$dbi = $this->createDatabaseInterface($dbiDummy);
DatabaseInterface::$instance = $dbi;
$class = new ReflectionClass(FavoriteTableController::class);
$method = $class->getMethod('synchronizeFavoriteTables');
$dbiDummy->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']], ['1']);
(new ReflectionProperty(RecentFavoriteTables::class, 'instances'))->setValue(null, []);
$favoriteInstance = RecentFavoriteTables::getInstance(TableType::Favorite);
$controller = new FavoriteTableController(
new ResponseStub(),
new Template(),
new Relation($this->dbi),
new DbTableExists($this->dbi),
new Relation($dbi),
new DbTableExists($dbi),
);
// The user hash for test
$user = 'abcdefg';
$favoriteTable = [$user => [['db' => 'db', 'table' => 'table']]];
$favoriteTable = [$user => [['db' => 'test_db', 'table' => 'test_table']]];
$_SESSION['tmpval'] = ['favorites_synced' => [$GLOBALS['server'] => null]];
$method = new ReflectionMethod(FavoriteTableController::class, 'synchronizeFavoriteTables');
$json = $method->invokeArgs($controller, [$favoriteInstance, $user, $favoriteTable]);
$this->assertEquals(json_encode($favoriteTable), $json['favoriteTables'] ?? '');
$this->assertArrayHasKey('list', $json);
self::assertIsArray($json);
self::assertEquals(json_encode($favoriteTable), $json['favoriteTables'] ?? '');
self::assertArrayHasKey('list', $json);
/**
* @psalm-suppress TypeDoesNotContainType
* @phpstan-ignore-next-line
*/
self::assertTrue($_SESSION['tmpval']['favorites_synced'][$GLOBALS['server']]);
$dbiDummy->assertAllQueriesConsumed();
}
}

View File

@ -12,7 +12,6 @@ use PhpMyAdmin\Core;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\DbTableExists;
use PhpMyAdmin\Http\ServerRequest;
use PhpMyAdmin\RecentFavoriteTable;
use PhpMyAdmin\Replication\Replication;
use PhpMyAdmin\Table\Table;
use PhpMyAdmin\Template;
@ -252,65 +251,6 @@ class StructureControllerTest extends AbstractTestCase
);
}
/**
* Tests for checkFavoriteTable()
*/
public function testCheckFavoriteTable(): void
{
$class = new ReflectionClass(StructureController::class);
$method = $class->getMethod('checkFavoriteTable');
$dbiDummy = $this->createDbiDummy();
$dbi = $this->createDatabaseInterface($dbiDummy);
$GLOBALS['db'] = 'sakila';
DatabaseInterface::$instance = $dbi;
$dbiDummy->removeDefaultResults();
$dbiDummy->addResult(
'SHOW COLUMNS FROM `sakila`.`country`',
[
['country_id', 'smallint(5) unsigned', 'NO', 'PRI', null, 'auto_increment'],
],
['Field', 'Type', 'Null', 'Key', 'Default', 'Extra'],
);
$dbiDummy->addResult(
'SHOW INDEXES FROM `sakila`.`country`',
[],
['Table', 'Non_unique', 'Key_name', 'Column_name'],
);
$controller = new StructureController(
$this->response,
$this->template,
$this->relation,
$this->replication,
$dbi,
$this->createStub(TrackingChecker::class),
$this->createStub(PageSettings::class),
new DbTableExists($dbi),
);
$recentFavoriteTables = RecentFavoriteTable::getInstance('favorite');
$this->assertSame([], $recentFavoriteTables->getTables());
$recentFavoriteTables->remove('sakila', 'country');
$recentFavoriteTables->add('sakila', 'country');
$this->assertSame([
[
'db' => 'sakila',
'table' => 'country',
],
], $recentFavoriteTables->getTables());
$this->assertFalse(
$method->invokeArgs($controller, ['']),
);
$this->assertTrue(
$method->invokeArgs($controller, ['country']),
);
}
/** @throws ReflectionException */
public function testDisplayTableList(): void
{

View File

@ -55,7 +55,7 @@ class TableControllerTest extends AbstractTestCase
$this->dummyDbi->addSelectDb('test_db');
$this->dummyDbi->addSelectDb('test_db');
// phpcs:disable Generic.Files.LineLength.TooLong
$this->dummyDbi->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']], ['Tables_in_test_db (test_table)']);
$this->dummyDbi->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']]);
$this->dummyDbi->addResult(
'SELECT *, `TABLE_SCHEMA` AS `Db`, `TABLE_NAME` AS `Name`, `TABLE_TYPE` AS `TABLE_TYPE`, `ENGINE` AS `Engine`, `ENGINE` AS `Type`, `VERSION` AS `Version`, `ROW_FORMAT` AS `Row_format`, `TABLE_ROWS` AS `Rows`, `AVG_ROW_LENGTH` AS `Avg_row_length`, `DATA_LENGTH` AS `Data_length`, `MAX_DATA_LENGTH` AS `Max_data_length`, `INDEX_LENGTH` AS `Index_length`, `DATA_FREE` AS `Data_free`, `AUTO_INCREMENT` AS `Auto_increment`, `CREATE_TIME` AS `Create_time`, `UPDATE_TIME` AS `Update_time`, `CHECK_TIME` AS `Check_time`, `TABLE_COLLATION` AS `Collation`, `CHECKSUM` AS `Checksum`, `CREATE_OPTIONS` AS `Create_options`, `TABLE_COMMENT` AS `Comment` FROM `information_schema`.`TABLES` t WHERE `TABLE_SCHEMA` COLLATE utf8_bin IN (\'test_db\') AND t.`TABLE_NAME` COLLATE utf8_bin = \'test_table\' ORDER BY Name ASC',
[['ref', 'test_db', 'test_table', 'BASE TABLE', 'InnoDB', '10', 'Dynamic', '3', '5461', '16384', '0', '49152', '0', '4', '2021-11-07 15:21:00', null, null, 'utf8mb4_general_ci', null, '', '', '0', 'N', 'test_db', 'test_table', 'BASE TABLE', 'InnoDB', 'InnoDB', '10', 'Dynamic', '3', '5461', '16384', '0', '49152', '0', '4', '2021-11-07 15:21:00', null, null, 'utf8mb4_general_ci', null, '', '']],

View File

@ -35,7 +35,7 @@ class AddFieldControllerTest extends AbstractTestCase
$dummyDbi = $this->createDbiDummy();
$dummyDbi->addSelectDb('test_db');
$dummyDbi->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']]);
$dummyDbi->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']]);
$dbi = $this->createDatabaseInterface($dummyDbi);
DatabaseInterface::$instance = $dbi;

View File

@ -30,7 +30,7 @@ final class ChangeControllerTest extends AbstractTestCase
$dummyDbi = $this->createDbiDummy();
$dummyDbi->addSelectDb('test_db');
$dummyDbi->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']]);
$dummyDbi->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']]);
$dummyDbi->addResult(
'SELECT * FROM `test_db`.`test_table` LIMIT 1;',
[['1', 'abcd', '2011-01-20 02:00:02']],
@ -125,7 +125,7 @@ final class ChangeControllerTest extends AbstractTestCase
$dummyDbi = $this->createDbiDummy();
$dummyDbi->addSelectDb('test_db');
$dummyDbi->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']]);
$dummyDbi->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']]);
$dummyDbi->addResult(
'SELECT * FROM `test_db`.`test_table` LIMIT 1;',
[['1', 'abcd', '2011-01-20 02:00:02']],

View File

@ -62,7 +62,7 @@ class ChartControllerTest extends AbstractTestCase
$dummyDbi = $this->createDbiDummy();
$dummyDbi->addSelectDb('test_db');
$dummyDbi->addResult('SHOW TABLES LIKE \'table_for_chart\';', [['table_for_chart']]);
$dummyDbi->addResult('SELECT 1 FROM `test_db`.`table_for_chart` LIMIT 1;', [['1']]);
$dummyDbi->addSelectDb('test_db');
$dummyDbi->addResult(
'SELECT * FROM `test_db`.`table_for_chart`;',

View File

@ -30,7 +30,7 @@ class DeleteConfirmControllerTest extends AbstractTestCase
$dummyDbi = $this->createDbiDummy();
$dummyDbi->addSelectDb('test_db');
$dummyDbi->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']]);
$dummyDbi->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']]);
$dbi = $this->createDatabaseInterface($dummyDbi);
DatabaseInterface::$instance = $dbi;

View File

@ -34,7 +34,7 @@ class DropColumnConfirmationControllerTest extends AbstractTestCase
$dummyDbi = $this->createDbiDummy();
$dummyDbi->addSelectDb('test_db');
$dummyDbi->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']]);
$dummyDbi->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']]);
$dbi = $this->createDatabaseInterface($dummyDbi);
DatabaseInterface::$instance = $dbi;

View File

@ -40,7 +40,7 @@ class ImportControllerTest extends AbstractTestCase
$dummyDbi = $this->createDbiDummy();
$dummyDbi->addSelectDb('test_db');
$dummyDbi->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']]);
$dummyDbi->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']]);
$dummyDbi->addResult('SELECT @@local_infile;', [['1']]);
$dbi = $this->createDatabaseInterface($dummyDbi);
DatabaseInterface::$instance = $dbi;

View File

@ -29,7 +29,7 @@ class IndexRenameControllerTest extends AbstractTestCase
$dummyDbi = $this->createDbiDummy();
$dummyDbi->addSelectDb('test_db');
$dummyDbi->addSelectDb('test_db');
$dummyDbi->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']]);
$dummyDbi->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']]);
$dbi = $this->createDatabaseInterface($dummyDbi);
DatabaseInterface::$instance = $dbi;

View File

@ -7,8 +7,12 @@ namespace PhpMyAdmin\Tests\Controllers\Table;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\Controllers\Table\RecentFavoriteController;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Favorites\RecentFavoriteTable;
use PhpMyAdmin\Favorites\RecentFavoriteTables;
use PhpMyAdmin\Favorites\TableType;
use PhpMyAdmin\Http\Factory\ServerRequestFactory;
use PhpMyAdmin\RecentFavoriteTable;
use PhpMyAdmin\Identifiers\DatabaseName;
use PhpMyAdmin\Identifiers\TableName;
use PhpMyAdmin\Template;
use PhpMyAdmin\Tests\AbstractTestCase;
use PhpMyAdmin\Tests\Stubs\ResponseRenderer;
@ -33,13 +37,17 @@ class RecentFavoriteControllerTest extends AbstractTestCase
'favoriteTables' => [2 => [['db' => 'test_db', 'table' => 'test_table']]],
];
DatabaseInterface::$instance = $this->createDatabaseInterface();
$dbiDummy = $this->createDbiDummy();
$dbiDummy->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']], ['1']);
$dbiDummy->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']], ['1']);
DatabaseInterface::$instance = $this->createDatabaseInterface($dbiDummy);
$recent = RecentFavoriteTable::getInstance('recent');
$favorite = RecentFavoriteTable::getInstance('favorite');
$recent = RecentFavoriteTables::getInstance(TableType::Recent);
$favorite = RecentFavoriteTables::getInstance(TableType::Favorite);
self::assertSame([['db' => 'test_db', 'table' => 'test_table']], $recent->getTables());
self::assertSame([['db' => 'test_db', 'table' => 'test_table']], $favorite->getTables());
$table = new RecentFavoriteTable(DatabaseName::from('test_db'), TableName::from('test_table'));
self::assertEquals([$table], $recent->getTables());
self::assertEquals([$table], $favorite->getTables());
$request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/')
->withQueryParams(['db' => 'test_db', 'table' => 'test_table']);
@ -54,8 +62,8 @@ class RecentFavoriteControllerTest extends AbstractTestCase
$response->getHeaderLine('Location'),
);
self::assertSame([['db' => 'test_db', 'table' => 'test_table']], $recent->getTables());
self::assertSame([['db' => 'test_db', 'table' => 'test_table']], $favorite->getTables());
self::assertEquals([$table], $recent->getTables());
self::assertEquals([$table], $favorite->getTables());
}
public function testRecentFavoriteControllerWithInvalidDbAndTable(): void
@ -70,15 +78,16 @@ class RecentFavoriteControllerTest extends AbstractTestCase
];
$dbiDummy = $this->createDbiDummy();
$dbiDummy->addResult('SELECT 1 FROM `invalid_db`.`invalid_table` LIMIT 1;', false);
$dbiDummy->addResult('SELECT 1 FROM `invalid_db`.`invalid_table` LIMIT 1;', false);
DatabaseInterface::$instance = $this->createDatabaseInterface($dbiDummy);
$dbiDummy->addResult('SHOW COLUMNS FROM `invalid_db`.`invalid_table`', false);
$dbiDummy->addResult('SHOW COLUMNS FROM `invalid_db`.`invalid_table`', false);
$recent = RecentFavoriteTable::getInstance('recent');
$favorite = RecentFavoriteTable::getInstance('favorite');
$recent = RecentFavoriteTables::getInstance(TableType::Recent);
$favorite = RecentFavoriteTables::getInstance(TableType::Favorite);
self::assertSame([['db' => 'invalid_db', 'table' => 'invalid_table']], $recent->getTables());
self::assertSame([['db' => 'invalid_db', 'table' => 'invalid_table']], $favorite->getTables());
$table = new RecentFavoriteTable(DatabaseName::from('invalid_db'), TableName::from('invalid_table'));
self::assertEquals([$table], $recent->getTables());
self::assertEquals([$table], $favorite->getTables());
$request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/')
->withQueryParams(['db' => 'invalid_db', 'table' => 'invalid_table']);
@ -95,6 +104,7 @@ class RecentFavoriteControllerTest extends AbstractTestCase
self::assertSame([], $recent->getTables());
self::assertSame([], $favorite->getTables());
$dbiDummy->assertAllQueriesConsumed();
}
public function testRecentFavoriteControllerWithInvalidDbAndTableName(): void

View File

@ -49,7 +49,7 @@ class SqlControllerTest extends AbstractTestCase
$config->selectedServer = $config->getSettings()->Servers[1]->asArray();
$this->dummyDbi->addSelectDb('test_db');
$this->dummyDbi->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']]);
$this->dummyDbi->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']]);
$pageSettings = new PageSettings(
new UserPreferences($this->dbi, new Relation($this->dbi), new Template()),

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace PhpMyAdmin\Tests\Controllers\Table;
use PhpMyAdmin\Charsets;
use PhpMyAdmin\Config;
use PhpMyAdmin\Config\PageSettings;
use PhpMyAdmin\ConfigStorage\Relation;
@ -52,9 +53,11 @@ class StructureControllerTest extends AbstractTestCase
$config->settings['ShowPropertyComments'] = false;
(new ReflectionProperty(Relation::class, 'cache'))->setValue(null, null);
(new ReflectionProperty(Template::class, 'twig'))->setValue(null, null);
(new ReflectionProperty(Charsets::class, 'collations'))->setValue(null, []);
$this->dummyDbi->addSelectDb('test_db');
$this->dummyDbi->addSelectDb('test_db');
$this->dummyDbi->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [[1]]);
$this->dummyDbi->addResult(
'SHOW COLLATION',
[
@ -160,5 +163,8 @@ class StructureControllerTest extends AbstractTestCase
]);
$this->assertSame($expected, $response->getHTMLResult());
$this->dummyDbi->assertAllSelectsConsumed();
$this->dummyDbi->assertAllQueriesConsumed();
}
}

View File

@ -30,7 +30,7 @@ final class ZoomSearchControllerTest extends AbstractTestCase
$dbi = $this->createDatabaseInterface($dbiDummy);
$dbiDummy->addSelectDb('test_db');
$dbiDummy->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']]);
$dbiDummy->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']]);
$request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/')
->withQueryParams(['db' => 'test_db', 'table' => 'test_table']);
@ -76,7 +76,7 @@ final class ZoomSearchControllerTest extends AbstractTestCase
$dbi = $this->createDatabaseInterface($dbiDummy);
$dbiDummy->addSelectDb('test_db');
$dbiDummy->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']]);
$dbiDummy->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']]);
$request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/')
->withQueryParams(['db' => 'test_db', 'table' => 'test_table'])

View File

@ -20,9 +20,7 @@ final class DbTableExistsTest extends AbstractTestCase
$dbiDummy->addSelectDb('test_db');
$dbi = $this->createDatabaseInterface($dbiDummy);
$dbTableExists = new DbTableExists($dbi);
$this->assertTrue($dbTableExists->hasDatabase(DatabaseName::from('test_db')));
// cached result
$this->assertTrue($dbTableExists->hasDatabase(DatabaseName::from('test_db')));
$this->assertTrue($dbTableExists->selectDatabase(DatabaseName::from('test_db')));
$dbiDummy->assertAllSelectsConsumed();
}
@ -32,19 +30,17 @@ final class DbTableExistsTest extends AbstractTestCase
$dbi = $this->createMock(DatabaseInterface::class);
$dbi->expects($this->once())->method('selectDb')->with($db)->willReturn(false);
$dbTableExists = new DbTableExists($dbi);
$this->assertFalse($dbTableExists->hasDatabase($db));
$this->assertFalse($dbTableExists->selectDatabase($db));
}
public function testHasTable(): void
{
$dbiDummy = $this->createDbiDummy();
$dbiDummy->removeDefaultResults();
$dbiDummy->addResult('SHOW TABLES LIKE \'test_table\';', [['test_table']], ['Tables_in_test_db (test_table)']);
$dbiDummy->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']], ['1']);
$dbi = $this->createDatabaseInterface($dbiDummy);
$dbi->getCache()->clearTableCache();
$dbTableExists = new DbTableExists($dbi);
$this->assertTrue($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table')));
$dbi->getCache()->clearTableCache();
// cached result
$this->assertTrue($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table')));
$dbiDummy->assertAllQueriesConsumed();
@ -54,39 +50,21 @@ final class DbTableExistsTest extends AbstractTestCase
{
$dbiDummy = $this->createDbiDummy();
$dbiDummy->removeDefaultResults();
$dbiDummy->addResult('SHOW TABLES LIKE \'test_table\';', [], ['Tables_in_test_db (test_table)']);
$dbiDummy->addResult('SELECT 1 FROM `test_table` LIMIT 1;', [['1']], ['1']);
$dbiDummy->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', [['1']], ['1']);
$dbi = $this->createDatabaseInterface($dbiDummy);
$dbi->getCache()->clearTableCache();
$dbTableExists = new DbTableExists($dbi);
$this->assertTrue($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table')));
$dbi->getCache()->clearTableCache();
// cached result
$this->assertTrue($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table')));
$dbiDummy->assertAllQueriesConsumed();
}
public function testHasTableWithDbiCache(): void
{
$dbiDummy = $this->createDbiDummy();
$dbiDummy->removeDefaultResults();
$dbi = $this->createDatabaseInterface($dbiDummy);
$dbi->getCache()->cacheTableContent(['test_db', 'test_table'], ['test_table']);
$dbTableExists = new DbTableExists($dbi);
$this->assertTrue($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table')));
$dbi->getCache()->clearTableCache();
// cached result
$this->assertTrue($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table')));
}
public function testHasTableWithNoTable(): void
{
$dbiDummy = $this->createDbiDummy();
$dbiDummy->removeDefaultResults();
$dbiDummy->addResult('SHOW TABLES LIKE \'test_table\';', false);
$dbiDummy->addResult('SELECT 1 FROM `test_table` LIMIT 1;', false);
$dbiDummy->addResult('SELECT 1 FROM `test_db`.`test_table` LIMIT 1;', false);
$dbi = $this->createDatabaseInterface($dbiDummy);
$dbi->getCache()->clearTableCache();
$dbTableExists = new DbTableExists($dbi);
$this->assertFalse($dbTableExists->hasTable(DatabaseName::from('test_db'), TableName::from('test_table')));
$dbiDummy->assertAllQueriesConsumed();