Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Allow non cachable plugins to return null on empty #594

Merged
merged 3 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Classes/ContentObject/JsonContentObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public function cObjGet(array $setup, string $addKey = ''): array
$content[$theKey] = (bool)(int)$content[$theKey];
}
if ($theValue === 'USER_INT' || strpos((string)$content[$theKey], '<!--INT_SCRIPT.') === 0) {
$content[$theKey] = $this->headlessUserInt->wrap($content[$theKey]);
$content[$theKey] = $this->headlessUserInt->wrap($content[$theKey], (int)($conf['ifEmptyReturnNull'] ?? 0) === 1 ? HeadlessUserInt::STANDARD_NULLABLE : HeadlessUserInt::STANDARD);
}
if ((int)($conf['ifEmptyReturnNull'] ?? 0) === 1 && $content[$theKey] === '') {
$content[$theKey] = null;
Expand Down
82 changes: 53 additions & 29 deletions Classes/Utility/HeadlessUserInt.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,43 +17,16 @@
use function preg_replace;
use function preg_replace_callback;
use function sprintf;
use function strpos;
use function substr;

class HeadlessUserInt
{
public const STANDARD = 'HEADLESS_INT';
public const NESTED = 'NESTED_HEADLESS_INT';
public const STANDARD_NULLABLE = 'HEADLESS_INT_NULL';
public const NESTED_NULLABLE = 'NESTED_HEADLESS_INT_NULL';
private const REGEX = '/("|)%s_START<<(.*?)>>%s_END("|)/s';

/**
* for use in preg_replace_callback
* to unwrap all HEADLESS_INT<<>>HEADLESS_INT blocks
*
* @param array<int, string> $input
* @return string
*/
private function replace(array $input): string
{
$content = $input[2];
if ($input[1] === $input[3] && $input[1] === '"') {
// have a look inside if it might be json already
$decoded = json_decode($content);

if ($decoded !== null) {
return $content;
}
return json_encode($content);
}

// trim one occurrence of double quotes at both ends
$jsonEncoded = json_encode($content);
if ($jsonEncoded[0] === '"' && $jsonEncoded[-1] === '"') {
$jsonEncoded = substr($jsonEncoded, 1, -1);
}
return $jsonEncoded;
}

public function wrap(string $content, string $type = self::STANDARD): string
{
return preg_replace(
Expand All @@ -73,10 +46,61 @@ public function unwrap(string $content): string
);
}

if (strpos($content, self::NESTED_NULLABLE) !== false) {
$content = preg_replace_callback(
sprintf(self::REGEX, self::NESTED_NULLABLE, self::NESTED_NULLABLE),
function (array $content) {
return $this->replace($content, true);
},
$content
);
}

if (strpos($content, self::STANDARD_NULLABLE) !== false) {
$content = preg_replace_callback(
sprintf(self::REGEX, self::STANDARD_NULLABLE, self::STANDARD_NULLABLE),
function (array $content) {
return $this->replace($content, true);
},
$content
);
}

return preg_replace_callback(
sprintf(self::REGEX, self::STANDARD, self::STANDARD),
[$this, 'replace'],
$content
);
}

/**
* for use in preg_replace_callback
* to unwrap all HEADLESS_INT<<>>HEADLESS_INT blocks
*
* @param array<int, string> $input
*/
private function replace(array $input, bool $returnNull = false): ?string
{
$content = $input[2];
if ($input[1] === $input[3] && $input[1] === '"') {
// have a look inside if it might be json already
$decoded = json_decode($content);

if (empty($decoded) && $returnNull) {
return json_encode(null);
}

if ($decoded !== null) {
return $content;
}
return json_encode($content);
}

// trim one occurrence of double quotes at both ends
$jsonEncoded = json_encode($content);
if ($jsonEncoded[0] === '"' && $jsonEncoded[-1] === '"') {
$jsonEncoded = substr($jsonEncoded, 1, -1);
}
return $jsonEncoded;
}
}
52 changes: 52 additions & 0 deletions Tests/Unit/Hooks/HeadlessUserIntTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
use TYPO3\TestingFramework\Core\Unit\UnitTestCase;

use function json_encode;

class HeadlessUserIntTest extends UnitTestCase
{
use ProphecyTrait;
Expand Down Expand Up @@ -129,6 +131,56 @@ public function processingOnQuotedJsonContent()
self::assertEquals($testProcessed, $tsfe->content);
}

/**
* @test
*/
public function processingEmptyPluginResponse()
{
$testProcessed = json_encode(
''
);
$testContent = '"HEADLESS_INT_NULL_START<<' . $testProcessed . '>>HEADLESS_INT_NULL_END"';

$setup = [];
$setup['plugin.']['tx_headless.']['staticTemplate'] = '1';

$tmpl = $this->prophesize(TemplateService::class);
$tmpl->setup = $setup;

$tsfe = $this->prophesize(TypoScriptFrontendController::class);
$tsfe->tmpl = $tmpl->reveal();

$tsfe->content = $testContent;

$classUnderTest = new HeadlessUserInt();

$tsfe->content = $classUnderTest->unwrap($tsfe->content);

self::assertEquals(json_encode(null), $tsfe->content);

$testProcessed = json_encode(
''
);
$testContent = '"NESTED_HEADLESS_INT_NULL_START<<' . $testProcessed . '>>NESTED_HEADLESS_INT_NULL_END"';

$setup = [];
$setup['plugin.']['tx_headless.']['staticTemplate'] = '1';

$tmpl = $this->prophesize(TemplateService::class);
$tmpl->setup = $setup;

$tsfe = $this->prophesize(TypoScriptFrontendController::class);
$tsfe->tmpl = $tmpl->reveal();

$tsfe->content = $testContent;

$classUnderTest = new HeadlessUserInt();

$tsfe->content = $classUnderTest->unwrap($tsfe->content);

self::assertEquals(json_encode(null), $tsfe->content);
}

/**
* @test
*/
Expand Down