Skip to content

Commit 560cafb

Browse files
Merge pull request #19180 from MauricioFauth/responserenderer
Refactor ResponseRenderer contructor and response method
2 parents 3ef015e + ebf0f11 commit 560cafb

6 files changed

Lines changed: 180 additions & 79 deletions

File tree

phpstan-baseline.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12282,7 +12282,7 @@ parameters:
1228212282

1228312283
-
1228412284
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
12285-
count: 5
12285+
count: 4
1228612286
path: src/ResponseRenderer.php
1228712287

1228812288
-

psalm-baseline.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10159,7 +10159,6 @@
1015910159
<DeprecatedMethod>
1016010160
<code><![CDATA[Config::getInstance()]]></code>
1016110161
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
10162-
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
1016310162
</DeprecatedMethod>
1016410163
<InvalidArrayOffset>
1016510164
<code><![CDATA[$GLOBALS['focus_querywindow']]]></code>
@@ -10173,7 +10172,6 @@
1017310172
</MixedAssignment>
1017410173
<RiskyTruthyFalsyComparison>
1017510174
<code><![CDATA[empty($GLOBALS['error_message'])]]></code>
10176-
<code><![CDATA[empty($_REQUEST['ajax_request'])]]></code>
1017710175
<code><![CDATA[empty($_REQUEST['no_debug'])]]></code>
1017810176
</RiskyTruthyFalsyComparison>
1017910177
</file>

src/Header.php

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515

1616
use function array_merge;
1717
use function defined;
18-
use function gmdate;
19-
use function header;
2018
use function htmlspecialchars;
2119
use function ini_get;
2220
use function json_encode;
@@ -210,8 +208,6 @@ public function disableWarnings(): void
210208
/** @return mixed[] */
211209
public function getDisplay(): array
212210
{
213-
$this->sendHttpHeaders();
214-
215211
$baseDir = defined('PMA_PATH_TO_BASEDIR') ? PMA_PATH_TO_BASEDIR : '';
216212

217213
/** @var ThemeManager $themeManager */
@@ -338,27 +334,6 @@ public function getMessage(): string
338334
return $retval;
339335
}
340336

341-
/**
342-
* Sends out the HTTP headers
343-
*/
344-
public function sendHttpHeaders(): void
345-
{
346-
if (defined('TESTSUITE')) {
347-
return;
348-
}
349-
350-
/**
351-
* Sends http headers
352-
*/
353-
$GLOBALS['now'] = gmdate('D, d M Y H:i:s') . ' GMT';
354-
355-
$headers = $this->getHttpHeaders();
356-
357-
foreach ($headers as $name => $value) {
358-
header(sprintf('%s: %s', $name, $value));
359-
}
360-
}
361-
362337
/** @return array<string, string> */
363338
public function getHttpHeaders(): array
364339
{
@@ -545,4 +520,9 @@ public function setIsTransformationWrapper(bool $isTransformationWrapper): void
545520
{
546521
$this->isTransformationWrapper = $isTransformationWrapper;
547522
}
523+
524+
public function getConsole(): Console
525+
{
526+
return $this->console;
527+
}
548528
}

src/ResponseRenderer.php

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@ class ResponseRenderer
2828
{
2929
private static ResponseRenderer|null $instance = null;
3030

31-
/**
32-
* Header instance
33-
*/
34-
protected Header $header;
3531
/**
3632
* HTML data to be used in the response
3733
*/
@@ -43,10 +39,7 @@ class ResponseRenderer
4339
* @var mixed[]
4440
*/
4541
private array $JSON = [];
46-
/**
47-
* PhpMyAdmin\Footer instance
48-
*/
49-
protected Footer $footer;
42+
5043
/**
5144
* Whether we are servicing an ajax request.
5245
*/
@@ -136,24 +129,16 @@ class ResponseRenderer
136129

137130
protected Response $response;
138131

139-
protected Template $template;
140-
protected Config $config;
141-
142-
private function __construct()
143-
{
144-
$this->config = Config::getInstance();
145-
$this->template = new Template();
146-
$dbi = DatabaseInterface::getInstance();
147-
$relation = new Relation($dbi);
148-
$this->header = new Header(
149-
$this->template,
150-
new Console($relation, $this->template, new BookmarkRepository($dbi, $relation)),
151-
$this->config,
152-
);
153-
$this->footer = new Footer($this->template, $this->config);
154-
$this->response = ResponseFactory::create()->createResponse();
155-
156-
$this->setAjax(! empty($_REQUEST['ajax_request']));
132+
protected function __construct(
133+
protected Config $config,
134+
protected Template $template,
135+
protected Header $header,
136+
protected Footer $footer,
137+
protected ErrorHandler $errorHandler,
138+
protected DatabaseInterface $dbi,
139+
ResponseFactory $responseFactory,
140+
) {
141+
$this->response = $responseFactory->createResponse(StatusCodeInterface::STATUS_OK, 'OK');
157142
}
158143

159144
/**
@@ -172,10 +157,26 @@ public function setAjax(bool $isAjax): void
172157
*/
173158
public static function getInstance(): ResponseRenderer
174159
{
175-
if (self::$instance === null) {
176-
self::$instance = new ResponseRenderer();
160+
if (self::$instance !== null) {
161+
return self::$instance;
177162
}
178163

164+
$config = Config::getInstance();
165+
$template = new Template($config);
166+
$dbi = DatabaseInterface::getInstance();
167+
$relation = new Relation($dbi);
168+
$console = new Console($relation, $template, new BookmarkRepository($dbi, $relation));
169+
170+
self::$instance = new ResponseRenderer(
171+
$config,
172+
$template,
173+
new Header($template, $console, $config),
174+
new Footer($template, $config),
175+
ErrorHandler::getInstance(),
176+
$dbi,
177+
ResponseFactory::create(),
178+
);
179+
179180
return self::$instance;
180181
}
181182

@@ -271,7 +272,7 @@ private function ajaxResponse(): string
271272
$this->addJSON('title', '<title>' . $this->getHeader()->getPageTitle() . '</title>');
272273
}
273274

274-
if (DatabaseInterface::getInstance()->isConnected()) {
275+
if ($this->dbi->isConnected()) {
275276
$this->addJSON('menu', $this->getHeader()->getMenu()->getDisplay());
276277
}
277278

@@ -289,7 +290,7 @@ private function ajaxResponse(): string
289290
$this->addJSON('errors', $errors);
290291
}
291292

292-
$promptPhpErrors = ErrorHandler::getInstance()->hasErrorsForPrompt();
293+
$promptPhpErrors = $this->errorHandler->hasErrorsForPrompt();
293294
$this->addJSON('promptPhpErrors', $promptPhpErrors);
294295

295296
if (empty($GLOBALS['error_message'])) {
@@ -317,12 +318,6 @@ private function ajaxResponse(): string
317318
}
318319
}
319320

320-
// Set the Content-Type header to JSON so that jQuery parses the
321-
// response correctly.
322-
foreach (Core::headerJSON() as $name => $value) {
323-
$this->addHeader($name, $value);
324-
}
325-
326321
$result = json_encode($this->JSON);
327322
if ($result === false) {
328323
return (string) json_encode([
@@ -336,9 +331,19 @@ private function ajaxResponse(): string
336331

337332
public function response(): Response
338333
{
339-
$this->response->getBody()->write($this->isAjax() ? $this->ajaxResponse() : $this->getDisplay());
334+
if ($this->isAjax()) {
335+
$headers = Core::headerJSON();
336+
$body = $this->ajaxResponse();
337+
} else {
338+
$headers = $this->header->getHttpHeaders();
339+
$body = $this->getDisplay();
340+
}
341+
342+
foreach ($headers as $name => $value) {
343+
$this->response = $this->response->withHeader($name, $value);
344+
}
340345

341-
return $this->response;
346+
return $this->response->write($body);
342347
}
343348

344349
public function addHeader(string $name, string $value): void

tests/unit/ResponseRendererTest.php

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,24 @@
55
namespace PhpMyAdmin\Tests;
66

77
use Fig\Http\Message\StatusCodeInterface;
8+
use PhpMyAdmin\Config;
9+
use PhpMyAdmin\Current;
810
use PhpMyAdmin\DatabaseInterface;
911
use PhpMyAdmin\Header;
1012
use PhpMyAdmin\Html\MySQLDocumentation;
1113
use PhpMyAdmin\Message;
1214
use PhpMyAdmin\ResponseRenderer;
1315
use PhpMyAdmin\Scripts;
16+
use PhpMyAdmin\Template;
17+
use PhpMyAdmin\Version;
1418
use PHPUnit\Framework\Attributes\CoversClass;
1519
use ReflectionProperty;
1620

1721
use function array_column;
22+
use function json_decode;
1823

1924
#[CoversClass(ResponseRenderer::class)]
20-
class ResponseRendererTest extends AbstractTestCase
25+
final class ResponseRendererTest extends AbstractTestCase
2126
{
2227
protected function setUp(): void
2328
{
@@ -107,4 +112,115 @@ public function testCheckParametersWithAllParameters(): void
107112

108113
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
109114
}
115+
116+
public function testHtmlResponse(): void
117+
{
118+
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
119+
120+
$_SERVER['SCRIPT_NAME'] = 'index.php';
121+
Current::$server = 0;
122+
123+
$responseRenderer = ResponseRenderer::getInstance();
124+
$responseRenderer->setAjax(false);
125+
$responseRenderer->addHTML('<div>TEST</div>');
126+
127+
$response = $responseRenderer->response();
128+
129+
self::assertSame(StatusCodeInterface::STATUS_OK, $response->getStatusCode());
130+
self::assertSame('text/html; charset=utf-8', $response->getHeaderLine('Content-Type'));
131+
$header = $responseRenderer->getHeader();
132+
self::assertSame(
133+
(new Template(new Config()))->render('base', [
134+
'header' => [
135+
'lang' => 'en',
136+
'allow_third_party_framing' => false,
137+
'base_dir' => '',
138+
'theme_path' => '',
139+
'version' => 'v=' . Version::VERSION,
140+
'text_dir' => 'ltr',
141+
'server' => 0,
142+
'title' => 'phpMyAdmin',
143+
'scripts' => $header->getScripts()->getDisplay(),
144+
'body_id' => '',
145+
'navigation' => '',
146+
'custom_header' => '',
147+
'load_user_preferences' => '',
148+
'show_hint' => true,
149+
'is_warnings_enabled' => true,
150+
'is_menu_enabled' => true,
151+
'is_logged_in' => true,
152+
'menu' => '',
153+
'console' => $header->getConsole()->getDisplay(),
154+
'messages' => '',
155+
'theme_color_mode' => 'light',
156+
'theme_color_modes' => ['light'],
157+
'theme_id' => '',
158+
'current_user' => ['pma_test', 'localhost'],
159+
'is_mariadb' => false,
160+
],
161+
'content' => '<div>TEST</div>',
162+
'footer' => [
163+
'is_minimal' => false,
164+
'self_url' => 'index.php?route=%2F&server=0&lang=en',
165+
'error_messages' => '',
166+
'scripts' => <<<'HTML'
167+
168+
<script data-cfasync="false">
169+
// <![CDATA[
170+
window.Console.debugSqlInfo = 'false';
171+
172+
// ]]>
173+
</script>
174+
175+
HTML,
176+
'is_demo' => false,
177+
'git_revision_info' => [],
178+
'footer' => '',
179+
],
180+
]),
181+
(string) $response->getBody(),
182+
);
183+
184+
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
185+
}
186+
187+
public function testJsonResponse(): void
188+
{
189+
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
190+
191+
$_SERVER['SCRIPT_NAME'] = 'index.php';
192+
Current::$server = 0;
193+
194+
$responseRenderer = ResponseRenderer::getInstance();
195+
$responseRenderer->setAjax(true);
196+
$responseRenderer->addJSON('message', 'test message');
197+
$responseRenderer->addJSON('test', 'test');
198+
199+
$response = $responseRenderer->response();
200+
201+
self::assertSame(StatusCodeInterface::STATUS_OK, $response->getStatusCode());
202+
self::assertSame('application/json; charset=UTF-8', $response->getHeaderLine('Content-Type'));
203+
$body = (string) $response->getBody();
204+
self::assertJson($body);
205+
$header = $responseRenderer->getHeader();
206+
self::assertEquals(
207+
[
208+
'message' => 'test message',
209+
'test' => 'test',
210+
'success' => true,
211+
'title' => '<title>phpMyAdmin</title>',
212+
'menu' => $header->getMenu()->getDisplay(),
213+
'scripts' => $header->getScripts()->getFiles(),
214+
'selflink' => 'index.php?route=%2F&server=0&lang=en',
215+
'displayMessage' => '',
216+
'debug' => "'false'",
217+
'promptPhpErrors' => false,
218+
'reloadQuerywindow' => ['db' => '', 'table' => '', 'sql_query' => ''],
219+
'params' => $header->getJsParams(),
220+
],
221+
json_decode($body, true),
222+
);
223+
224+
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
225+
}
110226
}

0 commit comments

Comments
 (0)