Skip to content

Commit

Permalink
Fix "Unexpected output detected" displayed twice
Browse files Browse the repository at this point in the history
  • Loading branch information
mvorisek committed Apr 24, 2022
1 parent b612681 commit 624d976
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 35 deletions.
50 changes: 36 additions & 14 deletions demos/_unit-test/late-output-error.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,56 @@

namespace Atk4\Ui\Demos;

use Atk4\Ui\Button;
use Atk4\Ui\Callback;
use Atk4\Ui\CallbackLater;
use Atk4\Ui\Header;
use Atk4\Ui\Modal;

/** @var \Atk4\Ui\App $app */
require_once __DIR__ . '/../init-app.php';

$cb = CallbackLater::addTo($app);
$cb->setUrlTrigger('err_headers_already_sent');

$modal = \Atk4\Ui\Modal::addTo($app, ['cb' => $cb]);
$modal->set(function () {
$cbH1 = Callback::addTo($app);
$cbH1->setUrlTrigger('err_headers_already_sent_1');
$modalH1 = Modal::addTo($app, ['cb' => $cbH1]);
$modalH1->set(function () {
header('x-unmanaged-header: test');
flush();
});

$cb2 = CallbackLater::addTo($app);
$cb2->setUrlTrigger('err_unexpected_output_detected');

$modal2 = \Atk4\Ui\Modal::addTo($app, ['cb' => $cb2]);
$modal2->set(function () {
$cbO1 = Callback::addTo($app);
$cbO1->setUrlTrigger('err_unexpected_output_detected_1');
$modalO1 = Modal::addTo($app, ['cb' => $cbO1]);
$modalO1->set(function () {
// unexpected output can be detected only when output buffering is enabled and not flushed
if (ob_get_level() === 0) {
ob_start();
}
echo 'unmanaged output';
});

$button = \Atk4\Ui\Button::addTo($app, ['Test LateOutputError: Headers already sent']);
$button->on('click', $modal->show());
$cbH2 = CallbackLater::addTo($app);
$cbH2->setUrlTrigger('err_headers_already_sent_2');
$modalH2 = Modal::addTo($app, ['cb' => $cbH2]);
$modalH2->set($modalH1->fx);

$cbO2 = CallbackLater::addTo($app);
$cbO2->setUrlTrigger('err_unexpected_output_detected_2');
$modalO2 = Modal::addTo($app, ['cb' => $cbO2]);
$modalO2->set($modalO1->fx);

Header::addTo($app, ['content' => 'Before render (/w Callback)']);

$buttonH1 = Button::addTo($app, ['Test LateOutputError I: Headers already sent']);
$buttonH1->on('click', $modalH1->show());

$buttonO1 = Button::addTo($app, ['Test LateOutputError I: Unexpected output detected']);
$buttonO1->on('click', $modalO1->show());

Header::addTo($app, ['content' => 'After render (/w CallbackLater)']);

$buttonH2 = Button::addTo($app, ['Test LateOutputError II: Headers already sent']);
$buttonH2->on('click', $modalH2->show());

$button2 = \Atk4\Ui\Button::addTo($app, ['Test LateOutputError: Unexpected output detected']);
$button2->on('click', $modal2->show());
$buttonO2 = Button::addTo($app, ['Test LateOutputError II: Unexpected output detected']);
$buttonO2->on('click', $modalO2->show());
4 changes: 3 additions & 1 deletion src/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ public function terminate($output = '', array $headers = []): void
$this->outputResponse($output, $headers);
}

$this->runCalled = true; // prevent shutdown function from triggering.
$this->runCalled = true; // prevent shutdown function from triggering
$this->callExit();
}

Expand Down Expand Up @@ -1116,6 +1116,8 @@ protected function outputLateOutputError(LateOutputError $exception): void

$this->outputResponseUnsafe($plainTextMessage, $headersNew);

$this->runCalled = true; // prevent shutdown function from triggering

exit(1); // should be never reached from phpunit because we set catchExceptions = false
}

Expand Down
38 changes: 18 additions & 20 deletions tests/DemosHttpTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,32 +114,30 @@ protected function getPathWithAppVars(string $path): string
return parent::getPathWithAppVars($path);
}

private function getLateOutputErrorPath(string $trigger): string
/**
* @dataProvider demoLateOutputErrorProvider
*/
public function testDemoLateOutputError(string $urlTrigger, string $expectedOutput): void
{
return '_unit-test/late-output-error.php?' . Callback::URL_QUERY_TRIGGER_PREFIX . $trigger . '=ajax&'
. Callback::URL_QUERY_TARGET . '=' . $trigger . '&__atk_json=1';
}
$path = '_unit-test/late-output-error.php?' . Callback::URL_QUERY_TRIGGER_PREFIX . $urlTrigger . '=ajax&'
. Callback::URL_QUERY_TARGET . '=' . $urlTrigger . '&__atk_json=1';

public function testDemoLateOutputErrorHeadersAlreadySent(): void
{
$response = $this->getResponseFromRequest5xx($this->getLateOutputErrorPath('err_headers_already_sent'));
$response = $this->getResponseFromRequest5xx($path);

$this->assertSame(500, $response->getStatusCode());
$this->assertSame(
"\n" . '!! FATAL UI ERROR: Headers already sent, more headers cannot be set at this stage !!' . "\n",
$response->getBody()->getContents()
);
$this->assertSame($expectedOutput, $response->getBody()->getContents());
}

public function testDemoLateOutputErrorUnexpectedOutputDetected(): void
public function demoLateOutputErrorProvider(): array
{
$response = $this->getResponseFromRequest5xx($this->getLateOutputErrorPath('err_unexpected_output_detected'));

$this->assertSame(500, $response->getStatusCode());
$this->assertSame(
'unmanaged output'
. "\n" . '!! FATAL UI ERROR: Unexpected output detected !!' . "\n",
$response->getBody()->getContents()
);
$hOutput = "\n" . '!! FATAL UI ERROR: Headers already sent, more headers cannot be set at this stage !!' . "\n";
$oOutput = 'unmanaged output' . "\n" . '!! FATAL UI ERROR: Unexpected output detected !!' . "\n";

return [
['err_headers_already_sent_2', $hOutput],
['err_unexpected_output_detected_2', $oOutput],
['err_headers_already_sent_1', $hOutput],
['err_unexpected_output_detected_1', $oOutput],
];
}
}

0 comments on commit 624d976

Please sign in to comment.