Merge pull request #19151 from MauricioFauth/stmt-history-middleware

Extract Footer::setHistory() into a middleware
This commit is contained in:
Maurício Meneghini Fauth 2024-05-09 19:40:47 -03:00 committed by GitHub
commit 898fb91773
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 179 additions and 75 deletions

View File

@ -7602,7 +7602,7 @@ parameters:
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 4
count: 2
path: src/Footer.php
-
@ -7620,11 +7620,6 @@ parameters:
count: 1
path: src/Footer.php
-
message: "#^Parameter \\#4 \\$sqlquery of method PhpMyAdmin\\\\ConfigStorage\\\\Relation\\:\\:setHistory\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/Footer.php
-
message: "#^Only booleans are allowed in an elseif condition, int\\|false given\\.$#"
count: 1
@ -8230,6 +8225,16 @@ parameters:
count: 1
path: src/Http/Middleware/SetupPageRedirection.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Http/Middleware/StatementHistory.php
-
message: "#^Parameter \\#4 \\$sqlquery of method PhpMyAdmin\\\\ConfigStorage\\\\Relation\\:\\:setHistory\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/Http/Middleware/StatementHistory.php
-
message: "#^Parameter \\#1 \\$known_string of function hash_equals expects string, mixed given\\.$#"
count: 1

View File

@ -5996,10 +5996,6 @@
</MixedOperand>
</file>
<file src="src/Footer.php">
<DeprecatedMethod>
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
</DeprecatedMethod>
<DeprecatedProperty>
<code><![CDATA[Routing::$route]]></code>
</DeprecatedProperty>
@ -6014,13 +6010,8 @@
<code><![CDATA[array{revision: string, revisionUrl: string, branch: string, branchUrl: string}|[]]]></code>
<code><![CDATA[is_array($info) ? $info : []]]></code>
</MixedReturnTypeCoercion>
<RedundantCast>
<code><![CDATA[(string) $_REQUEST['no_history']]]></code>
</RedundantCast>
<RiskyTruthyFalsyComparison>
<code><![CDATA[$object]]></code>
<code><![CDATA[empty($GLOBALS['error_message'])]]></code>
<code><![CDATA[empty($GLOBALS['sql_query'])]]></code>
<code><![CDATA[empty($_REQUEST['no_debug'])]]></code>
</RiskyTruthyFalsyComparison>
<UnusedReturnValue>
@ -6522,6 +6513,17 @@
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
</DeprecatedMethod>
</file>
<file src="src/Http/Middleware/StatementHistory.php">
<DeprecatedMethod>
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
</DeprecatedMethod>
<MixedArgument>
<code><![CDATA[$GLOBALS['sql_query']]]></code>
</MixedArgument>
<RiskyTruthyFalsyComparison>
<code><![CDATA[empty($GLOBALS['error_message'])]]></code>
</RiskyTruthyFalsyComparison>
</file>
<file src="src/Http/Middleware/TokenRequestParamChecking.php">
<MixedArgument>
<code><![CDATA[$_SESSION[' PMA_token ']]]></code>

View File

@ -38,6 +38,7 @@ use PhpMyAdmin\Http\Middleware\SessionHandling;
use PhpMyAdmin\Http\Middleware\SetupPageRedirection;
use PhpMyAdmin\Http\Middleware\SqlDelimiterSetting;
use PhpMyAdmin\Http\Middleware\SqlQueryGlobalSetting;
use PhpMyAdmin\Http\Middleware\StatementHistory;
use PhpMyAdmin\Http\Middleware\ThemeInitialization;
use PhpMyAdmin\Http\Middleware\TokenMismatchChecking;
use PhpMyAdmin\Http\Middleware\TokenRequestParamChecking;
@ -116,6 +117,7 @@ class Application
$requestHandler->add(new ProfilingChecking());
$requestHandler->add(new UserPreferencesLoading($this->config));
$requestHandler->add(new RecentTableHandling($this->config));
$requestHandler->add(new StatementHistory($this->config));
$runner = new RequestHandlerRunner(
$requestHandler,

View File

@ -7,7 +7,6 @@ declare(strict_types=1);
namespace PhpMyAdmin;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\Error\ErrorHandler;
use PhpMyAdmin\Routing\Routing;
use Traversable;
@ -17,7 +16,6 @@ use function file_exists;
use function in_array;
use function is_array;
use function is_object;
use function is_scalar;
use function json_encode;
use function json_last_error;
@ -44,12 +42,9 @@ class Footer
*/
private bool $isEnabled = true;
private Relation $relation;
public function __construct(private readonly Template $template, private readonly Config $config)
{
$this->scripts = new Scripts($this->template);
$this->relation = new Relation(DatabaseInterface::getInstance());
}
/**
@ -160,32 +155,6 @@ class Footer
return $retval;
}
/**
* Saves query in history
*/
private function setHistory(): void
{
if (
(
isset($_REQUEST['no_history'])
&& is_scalar($_REQUEST['no_history'])
&& (string) $_REQUEST['no_history'] !== ''
)
|| ! empty($GLOBALS['error_message'])
|| empty($GLOBALS['sql_query'])
|| ! DatabaseInterface::getInstance()->isConnected()
) {
return;
}
$this->relation->setHistory(
Current::$database,
Current::$table,
$this->config->selectedServer['user'],
$GLOBALS['sql_query'],
);
}
/**
* Disables the rendering of the footer
*/
@ -228,36 +197,35 @@ class Footer
*/
public function getDisplay(): string
{
$this->setHistory();
if ($this->isEnabled) {
if (! $this->isAjax && ! $this->isMinimal) {
if (Core::getEnv('SCRIPT_NAME') !== '') {
$url = $this->getSelfUrl();
}
$this->scripts->addCode('window.Console.debugSqlInfo = ' . $this->getDebugMessage() . ';');
$errorMessages = $this->getErrorMessages();
$scripts = $this->scripts->getDisplay();
if ($this->config->config->debug->demo) {
$gitRevisionInfo = $this->getGitRevisionInfo();
}
$footer = Config::renderFooter();
}
return $this->template->render('footer', [
'is_ajax' => $this->isAjax,
'is_minimal' => $this->isMinimal,
'self_url' => $url ?? null,
'error_messages' => $errorMessages ?? '',
'scripts' => $scripts ?? '',
'is_demo' => $this->config->config->debug->demo,
'git_revision_info' => $gitRevisionInfo ?? [],
'footer' => $footer ?? '',
]);
if (! $this->isEnabled) {
return '';
}
return '';
if (! $this->isAjax && ! $this->isMinimal) {
if (Core::getEnv('SCRIPT_NAME') !== '') {
$url = $this->getSelfUrl();
}
$this->scripts->addCode('window.Console.debugSqlInfo = ' . $this->getDebugMessage() . ';');
$errorMessages = $this->getErrorMessages();
$scripts = $this->scripts->getDisplay();
if ($this->config->config->debug->demo) {
$gitRevisionInfo = $this->getGitRevisionInfo();
}
$footer = Config::renderFooter();
}
return $this->template->render('footer', [
'is_ajax' => $this->isAjax,
'is_minimal' => $this->isMinimal,
'self_url' => $url ?? null,
'error_messages' => $errorMessages ?? '',
'scripts' => $scripts ?? '',
'is_demo' => $this->config->config->debug->demo,
'git_revision_info' => $gitRevisionInfo ?? [],
'footer' => $footer ?? '',
]);
}
}

View File

@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Http\Middleware;
use PhpMyAdmin\Config;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\Current;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use function assert;
final class StatementHistory implements MiddlewareInterface
{
private readonly Relation $relation;
private readonly DatabaseInterface $dbi;
public function __construct(
private readonly Config $config,
DatabaseInterface|null $dbi = null,
Relation|null $relation = null,
) {
$this->dbi = $dbi ?? DatabaseInterface::getInstance();
$this->relation = $relation ?? new Relation($this->dbi, $this->config);
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
assert($request instanceof ServerRequest);
$response = $handler->handle($request);
if (
! $request->has('no_history')
&& empty($GLOBALS['error_message'])
&& $GLOBALS['sql_query'] !== ''
&& $this->dbi->isConnected()
) {
$this->relation->setHistory(
Current::$database,
Current::$table,
$this->config->selectedServer['user'],
$GLOBALS['sql_query'],
);
}
return $response;
}
}

View File

@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Tests\Http\Middleware;
use PhpMyAdmin\Config;
use PhpMyAdmin\ConfigStorage\Relation;
use PhpMyAdmin\Current;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Http\Factory\ServerRequestFactory;
use PhpMyAdmin\Http\Middleware\StatementHistory;
use PhpMyAdmin\Tests\AbstractTestCase;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\TestWith;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\RequestHandlerInterface;
#[CoversClass(StatementHistory::class)]
final class StatementHistoryTest extends AbstractTestCase
{
public function testStatementHistory(): void
{
Current::$database = 'test_db';
Current::$table = 'test_table';
$GLOBALS['sql_query'] = 'SELECT 1;';
$config = new Config();
$config->selectedServer['user'] = 'test_user';
$dbi = self::createStub(DatabaseInterface::class);
$dbi->method('isConnected')->willReturn(true);
$relation = self::createMock(Relation::class);
$relation->expects(self::once())->method('setHistory')->with(
self::identicalTo('test_db'),
self::identicalTo('test_table'),
self::identicalTo('test_user'),
self::identicalTo('SELECT 1;'),
);
$statementHistory = new StatementHistory($config, $dbi, $relation);
$response = self::createStub(ResponseInterface::class);
$handler = self::createStub(RequestHandlerInterface::class);
$handler->method('handle')->willReturn($response);
$request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/');
self::assertSame($response, $statementHistory->process($request, $handler));
}
#[TestWith(['true', 'SELECT 1;', true])]
#[TestWith([null, '', true])]
#[TestWith([null, 'SELECT 1;', false])]
public function testSkipHistory(string|null $noHistoryParam, string $sqlQuery, bool $isConnected): void
{
$GLOBALS['sql_query'] = $sqlQuery;
$dbi = self::createStub(DatabaseInterface::class);
$dbi->method('isConnected')->willReturn($isConnected);
$relation = self::createMock(Relation::class);
$relation->expects(self::never())->method('setHistory');
$statementHistory = new StatementHistory(new Config(), $dbi, $relation);
$response = self::createStub(ResponseInterface::class);
$handler = self::createStub(RequestHandlerInterface::class);
$handler->method('handle')->willReturn($response);
$parsedBody = $noHistoryParam !== null ? ['no_history' => $noHistoryParam] : [];
$request = ServerRequestFactory::create()->createServerRequest('POST', 'https://example.com/')
->withParsedBody($parsedBody);
self::assertSame($response, $statementHistory->process($request, $handler));
}
}