diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4ddb11f9..06285280 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -28,7 +28,7 @@ jobs: fail-fast: false matrix: php-version: - - 8.1 + - 8.2 code-quality: name: "Code quality checks" runs-on: ubuntu-20.04 @@ -44,7 +44,7 @@ jobs: - name: "Show Composer version" run: composer --version - name: "Cache dependencies installed with composer" - uses: actions/cache@v3 + uses: actions/cache@v4 with: key: "php${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.json') }}" path: ~/.cache/composer @@ -62,7 +62,7 @@ jobs: - "ts:lint" - "php:cs-fixer" php-version: - - 8.1 + - 8.2 tests: runs-on: ubuntu-latest strategy: @@ -84,7 +84,7 @@ jobs: extensions: intl, mbstring, pdo_sqlite - name: "Cache composer dependencies" - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.composer/cache key: php-${{ matrix.php-versions }} diff --git a/.github/workflows/codecoverage.yml b/.github/workflows/codecoverage.yml index 34ec5b40..54e19749 100644 --- a/.github/workflows/codecoverage.yml +++ b/.github/workflows/codecoverage.yml @@ -23,7 +23,7 @@ jobs: - name: "Show Composer version" run: composer --version - name: "Cache dependencies installed with composer" - uses: actions/cache@v3 + uses: actions/cache@v4 with: key: "php${{ matrix.php-version }}-typo3${{ matrix.typo3-version }}-${{ matrix.composer-dependencies }}-composer-${{ hashFiles('**/composer.json') }}" path: ~/.cache/composer diff --git a/Classes/ContentObject/JsonContentContentObject.php b/Classes/ContentObject/JsonContentContentObject.php index 1a91ead6..4b1a71cb 100755 --- a/Classes/ContentObject/JsonContentContentObject.php +++ b/Classes/ContentObject/JsonContentContentObject.php @@ -136,10 +136,14 @@ protected function groupContentElementsByColPos(array $contentElements, array $c $element = $this->headlessUserInt->wrap($element); } - $element = json_decode($element); + $element = json_decode($element, true); - if ($this->isColPolsGroupingEnabled($conf) && $element->colPos >= 0) { - $data['colPos' . $element->colPos][] = $element; + if ($element === []) { + continue; + } + + if ($this->isColPolsGroupingEnabled($conf) && ($element['colPos'] ?? 0) >= 0) { + $data['colPos' . $element['colPos']][] = $element; } else { $data[] = $element; } @@ -209,7 +213,8 @@ private function prepareValue(array $conf): array $cObj->parentRecordNumber = $this->cObj->currentRecordNumber; $frontendController->currentRecord = $registerField; $this->cObj->lastChanged($row['tstamp'] ?? 0); - $cObj->start($row, $conf['table'], $this->request); + $cObj->setRequest($this->request); + $cObj->start($row, $conf['table']); $tmpValue = $cObj->cObjGetSingle($renderObjName, $renderObjConf, $renderObjKey); $cobjValue[] = $tmpValue; } diff --git a/Classes/DataProcessing/DatabaseQueryProcessor.php b/Classes/DataProcessing/DatabaseQueryProcessor.php index fead8a87..aac95c33 100644 --- a/Classes/DataProcessing/DatabaseQueryProcessor.php +++ b/Classes/DataProcessing/DatabaseQueryProcessor.php @@ -58,15 +58,8 @@ */ class DatabaseQueryProcessor implements DataProcessorInterface { - /** - * @var ContentDataProcessor - */ - protected $contentDataProcessor; - - /** - * @var TypoScriptService - */ - private $typoScriptService; + private ContentDataProcessor $contentDataProcessor; + private TypoScriptService $typoScriptService; public function __construct(ContentDataProcessor $contentDataProcessor = null, TypoScriptService $typoScriptService = null) { @@ -100,7 +93,7 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu $targetVariableName = $cObj->stdWrapValue('as', $processorConfiguration, 'records'); $records = $cObj->getRecords($tableName, $processorConfiguration); - $processedRecordVariables = $this->processRecordVariables($records, $tableName, $processorConfiguration); + $processedRecordVariables = $this->processRecordVariables($cObj, $records, $tableName, $processorConfiguration); $processedData[$targetVariableName] = $processedRecordVariables; @@ -114,20 +107,24 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu * * @return array */ - private function processRecordVariables(array $records, string $tableName, array $processorConfiguration): array + private function processRecordVariables(ContentObjectRenderer $cObj, array $records, string $tableName, array $processorConfiguration): array { $processedRecordVariables = []; foreach ($records as $key => $record) { $recordContentObjectRenderer = $this->createContentObjectRenderer(); $recordContentObjectRenderer->start($record, $tableName); + $recordContentObjectRenderer->setRequest($cObj->getRequest()); + + $objConf = []; + $objName = '< ' . $tableName; if (isset($processorConfiguration['fields.'])) { + $objName = 'JSON'; $fields = $this->typoScriptService->convertTypoScriptArrayToPlainArray($processorConfiguration['fields.']); - $jsonCE = $this->typoScriptService->convertPlainArrayToTypoScriptArray(['fields' => $fields, '_typoScriptNodeValue' => 'JSON']); - $record = \json_decode($recordContentObjectRenderer->cObjGetSingle('JSON', $jsonCE), true); + $objConf = $this->typoScriptService->convertPlainArrayToTypoScriptArray(['fields' => $fields, '_typoScriptNodeValue' => 'JSON']); } - $processedRecordVariables[$key] = $record; + $processedRecordVariables[$key] = \json_decode($recordContentObjectRenderer->cObjGetSingle($objName, $objConf), true); $processedRecordVariables[$key] = $this->contentDataProcessor->process($recordContentObjectRenderer, $processorConfiguration, $processedRecordVariables[$key]); if (isset($processorConfiguration['overrideFields.'])) { @@ -148,9 +145,6 @@ private function processRecordVariables(array $records, string $tableName, array return $processedRecordVariables; } - /** - * @return ContentObjectRenderer - */ protected function createContentObjectRenderer(): ContentObjectRenderer { return GeneralUtility::makeInstance(ContentObjectRenderer::class); diff --git a/Classes/Event/Listener/AfterLinkIsGeneratedListener.php b/Classes/Event/Listener/AfterLinkIsGeneratedListener.php index be460c24..7d587865 100644 --- a/Classes/Event/Listener/AfterLinkIsGeneratedListener.php +++ b/Classes/Event/Listener/AfterLinkIsGeneratedListener.php @@ -14,8 +14,13 @@ use FriendsOfTYPO3\Headless\Utility\HeadlessFrontendUrlInterface; use TYPO3\CMS\Core\LinkHandling\LinkService; use TYPO3\CMS\Core\Site\Entity\NullSite; +use TYPO3\CMS\Core\Site\Entity\Site; use TYPO3\CMS\Frontend\Event\AfterLinkIsGeneratedEvent; +use function is_numeric; +use function is_string; +use function str_starts_with; + final class AfterLinkIsGeneratedListener { public function __construct( @@ -39,16 +44,24 @@ public function __invoke(AfterLinkIsGeneratedEvent $event): void $urlUtility = $this->urlUtility->withRequest($event->getContentObjectRenderer()->getRequest()); - if ($pageId) { + if (is_numeric($pageId) && ((int)$pageId) > 0) { $href = $urlUtility->getFrontendUrlForPage( $event->getLinkResult()->getUrl(), (int)$pageId ); } else { + /** + * @var Site $site + */ $site = $event->getContentObjectRenderer()->getRequest()->getAttribute('site'); + $key = 'frontendBase'; if (!$site instanceof NullSite) { - $href = $urlUtility->getFrontendUrlWithSite($event->getLinkResult()->getUrl(), $site); + if (is_string($pageId) && str_starts_with($pageId, 't3://page?uid=current&type=' . $site->getSettings()->get('headless.sitemap.type', '1533906435'))) { + $key = $site->getSettings()->get('headless.sitemap.key', 'frontendApiProxy'); + } + + $href = $urlUtility->getFrontendUrlWithSite($event->getLinkResult()->getUrl(), $site, $key); } } diff --git a/Classes/Event/Listener/AfterPagePreviewUriGeneratedListener.php b/Classes/Event/Listener/AfterPagePreviewUriGeneratedListener.php index 67f85a44..6b4efa89 100644 --- a/Classes/Event/Listener/AfterPagePreviewUriGeneratedListener.php +++ b/Classes/Event/Listener/AfterPagePreviewUriGeneratedListener.php @@ -11,13 +11,13 @@ namespace FriendsOfTYPO3\Headless\Event\Listener; -use FriendsOfTYPO3\Headless\Utility\Headless; use FriendsOfTYPO3\Headless\Utility\HeadlessFrontendUrlInterface; use FriendsOfTYPO3\Headless\Utility\HeadlessMode; use TYPO3\CMS\Backend\Routing\Event\AfterPagePreviewUriGeneratedEvent; use TYPO3\CMS\Core\Exception\SiteNotFoundException; use TYPO3\CMS\Core\Http\Uri; use TYPO3\CMS\Core\Site\SiteFinder; +use TYPO3\CMS\Core\Utility\GeneralUtility; final class AfterPagePreviewUriGeneratedListener { @@ -31,16 +31,10 @@ public function __invoke(AfterPagePreviewUriGeneratedEvent $event): void try { $site = $this->siteFinder->getSiteByPageId($event->getPageId()); - $mode = (int)($site->getConfiguration()['headless'] ?? HeadlessMode::NONE); - if ($mode === HeadlessMode::MIXED) { - // in BE context we override it to force generate url - $mode = HeadlessMode::FULL; - } - - $request = $GLOBALS['TYPO3_REQUEST']; - $request = $request->withAttribute('language', $site->getLanguageById($event->getLanguageId())); - $request = $request->withAttribute('headless', new Headless($mode)); + $headlessMode = GeneralUtility::makeInstance(HeadlessMode::class); + $headlessMode = $headlessMode->withRequest($GLOBALS['TYPO3_REQUEST']); + $request = $headlessMode->overrideBackendRequestBySite($site, $site->getLanguageById($event->getLanguageId())); $urlUtility = $this->urlUtility->withRequest($request); $event->setPreviewUri(new Uri($urlUtility->getFrontendUrlWithSite($event->getPreviewUri()->__toString(), $site))); diff --git a/Classes/Middleware/RedirectHandler.php b/Classes/Middleware/RedirectHandler.php index 859c227b..d2b9cb86 100644 --- a/Classes/Middleware/RedirectHandler.php +++ b/Classes/Middleware/RedirectHandler.php @@ -40,9 +40,11 @@ public function __construct( ResponseFactoryInterface $responseFactory, LoggerInterface $logger, HeadlessFrontendUrlInterface $urlUtility, + HeadlessMode $headlessMode ) { parent::__construct($redirectService, $eventDispatcher, $responseFactory, $logger); $this->urlUtility = $urlUtility; + $this->headlessMode = $headlessMode; } /** diff --git a/Classes/Middleware/SiteBaseRedirectResolver.php b/Classes/Middleware/SiteBaseRedirectResolver.php index d152d5c1..d87ff3a5 100644 --- a/Classes/Middleware/SiteBaseRedirectResolver.php +++ b/Classes/Middleware/SiteBaseRedirectResolver.php @@ -11,6 +11,7 @@ namespace FriendsOfTYPO3\Headless\Middleware; +use FriendsOfTYPO3\Headless\Utility\HeadlessMode; use FriendsOfTYPO3\Headless\Utility\UrlUtility; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -22,6 +23,8 @@ class SiteBaseRedirectResolver extends \TYPO3\CMS\Frontend\Middleware\SiteBaseRedirectResolver { + public function __construct(private readonly HeadlessMode $headlessMode) {} + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $response = parent::process($request, $handler); @@ -32,9 +35,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface return $response; } - $siteConf = $site->getConfiguration(); - - if (!($siteConf['headless'] ?? false)) { + if (!$this->headlessMode->withRequest($request)->isEnabled()) { return $response; } diff --git a/Classes/Utility/HeadlessMode.php b/Classes/Utility/HeadlessMode.php index c4a52f87..cabbbe5a 100644 --- a/Classes/Utility/HeadlessMode.php +++ b/Classes/Utility/HeadlessMode.php @@ -12,6 +12,8 @@ namespace FriendsOfTYPO3\Headless\Utility; use Psr\Http\Message\ServerRequestInterface; +use TYPO3\CMS\Core\Site\Entity\SiteInterface; +use TYPO3\CMS\Core\Site\Entity\SiteLanguage; final class HeadlessMode { @@ -41,4 +43,22 @@ public function isEnabled(): bool return $headless->getMode() === self::FULL || ($headless->getMode() === self::MIXED && ($this->request->getHeader('Accept')[0] ?? '') === 'application/json'); } + + public function overrideBackendRequestBySite(SiteInterface $site, ?SiteLanguage $language = null): ServerRequestInterface + { + $mode = (int)($site->getConfiguration()['headless'] ?? self::NONE); + + if ($mode === self::MIXED) { + // in BE context we override + $mode = self::NONE; + } + + $request = clone $this->request; + + if ($language) { + $request = $request->withAttribute('language', $language); + } + + return $request->withAttribute('headless', new Headless($mode)); + } } diff --git a/Classes/Utility/UrlUtility.php b/Classes/Utility/UrlUtility.php index 866847e0..ccaf2d32 100644 --- a/Classes/Utility/UrlUtility.php +++ b/Classes/Utility/UrlUtility.php @@ -26,6 +26,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use function array_merge; +use function ltrim; use function rtrim; use function str_contains; @@ -96,11 +97,15 @@ public function getFrontendUrlWithSite($url, SiteInterface $site, string $return $frontendBase = GeneralUtility::makeInstance(Uri::class, $this->sanitizeBaseUrl($frontendBaseUrl)); $frontBase = $frontendBase->getHost(); + $frontExtraPath = $frontendBase->getPath(); $frontPort = $frontendBase->getPort(); $targetUri = new Uri($this->sanitizeBaseUrl($url)); if (str_contains($url, $base)) { $targetUri = $targetUri->withHost($frontBase); + if ($frontExtraPath) { + $targetUri = $targetUri->withPath($frontExtraPath . ($targetUri->getPath() !== '' ? '/' . ltrim($targetUri->getPath(), '/') : '')); + } } if ($port === $frontPort) { @@ -182,6 +187,10 @@ protected function logError(string $message): void */ private function sanitizeBaseUrl(string $base): string { + if (str_starts_with($base, '#')) { + return $base; + } + // no protocol ("//") and the first part is no "/" (path), means that this is a domain like // "www.domain.com/blabla", and we want to ensure that this one then gets a "no-scheme agnostic" part if (!empty($base) && !str_contains($base, '//') && $base[0] !== '/') { diff --git a/Classes/ViewHelpers/LoginFormViewHelper.php b/Classes/ViewHelpers/LoginFormViewHelper.php index 48e7281e..e8d7b95a 100644 --- a/Classes/ViewHelpers/LoginFormViewHelper.php +++ b/Classes/ViewHelpers/LoginFormViewHelper.php @@ -263,7 +263,7 @@ protected function renderRequestTokenHiddenField(): string // basically "request token, yes" - uses form-action URI as scope if ($isTrulyRequestToken || $requestToken === '@nonce') { $requestToken = RequestToken::create($formAction); - // basically "request token with 'my-scope'" - uses 'my-scope' + // basically "request token with 'my-scope'" - uses 'my-scope' } elseif (is_string($requestToken) && $requestToken !== '') { $requestToken = RequestToken::create($requestToken); } diff --git a/Classes/XClass/Controller/PreviewController.php b/Classes/XClass/Controller/PreviewController.php index 5c4d1765..2258563d 100644 --- a/Classes/XClass/Controller/PreviewController.php +++ b/Classes/XClass/Controller/PreviewController.php @@ -11,6 +11,7 @@ namespace FriendsOfTYPO3\Headless\XClass\Controller; +use FriendsOfTYPO3\Headless\Utility\HeadlessMode; use FriendsOfTYPO3\Headless\Utility\UrlUtility; use TYPO3\CMS\Core\Site\Entity\Site; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -25,6 +26,15 @@ class PreviewController extends \TYPO3\CMS\Workspaces\Controller\PreviewControll protected function generateUrl(Site $site, int $pageUid, array $parameters): string { $url = (string)$site->getRouter()->generateUri($pageUid, $parameters); - return GeneralUtility::makeInstance(UrlUtility::class)->getFrontendUrlForPage($url, $pageUid); + + if (!isset($GLOBALS['TYPO3_REQUEST'])) { + return $url; + } + + $headlessMode = GeneralUtility::makeInstance(HeadlessMode::class); + $headlessMode = $headlessMode->withRequest($GLOBALS['TYPO3_REQUEST']); + $request = $headlessMode->overrideBackendRequestBySite($site, $parameters['_language'] ?? null); + + return GeneralUtility::makeInstance(UrlUtility::class)->withRequest($request)->getFrontendUrlForPage($url, $pageUid); } } diff --git a/Classes/XClass/Preview/PreviewUriBuilder.php b/Classes/XClass/Preview/PreviewUriBuilder.php index e3bfbefe..d1eec263 100644 --- a/Classes/XClass/Preview/PreviewUriBuilder.php +++ b/Classes/XClass/Preview/PreviewUriBuilder.php @@ -11,6 +11,7 @@ namespace FriendsOfTYPO3\Headless\XClass\Preview; +use FriendsOfTYPO3\Headless\Utility\HeadlessMode; use FriendsOfTYPO3\Headless\Utility\UrlUtility; use TYPO3\CMS\Core\Exception\SiteNotFoundException; use TYPO3\CMS\Core\Routing\InvalidRouteArgumentsException; @@ -46,7 +47,13 @@ public function buildUriForPage(int $uid, int $languageId = 0): string $language = $site->getDefaultLanguage(); } - return GeneralUtility::makeInstance(UrlUtility::class)->getFrontendUrlForPage((string)$site->getRouter()->generateUri($uid, ['ADMCMD_prev' => $previewKeyword, '_language' => $language], ''), $uid); + $headlessMode = GeneralUtility::makeInstance(HeadlessMode::class); + $headlessMode = $headlessMode->withRequest($GLOBALS['TYPO3_REQUEST']); + $request = $headlessMode->overrideBackendRequestBySite($site, $language); + + return GeneralUtility::makeInstance(UrlUtility::class) + ->withRequest($request) + ->getFrontendUrlForPage((string)$site->getRouter()->generateUri($uid, ['ADMCMD_prev' => $previewKeyword, '_language' => $language], ''), $uid); } catch (SiteNotFoundException | InvalidRouteArgumentsException $e) { throw new UnableToLinkToPageException('The page ' . $uid . ' had no proper connection to a site, no link could be built.', 1559794916); } diff --git a/Classes/XClass/ResourceLocalDriver.php b/Classes/XClass/ResourceLocalDriver.php index 4fc5f8ab..404722c2 100644 --- a/Classes/XClass/ResourceLocalDriver.php +++ b/Classes/XClass/ResourceLocalDriver.php @@ -26,19 +26,22 @@ class ResourceLocalDriver extends LocalDriver { protected function determineBaseUrl(): void { - $headlessMode = GeneralUtility::makeInstance(HeadlessMode::class)->withRequest($GLOBALS['TYPO3_REQUEST']); + $request = $GLOBALS['TYPO3_REQUEST'] ?? null; - if ((($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface - && ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isBackend()) || - !$headlessMode->isEnabled()) { + if (!$request instanceof ServerRequestInterface) { + return; + } + + $headlessMode = GeneralUtility::makeInstance(HeadlessMode::class)->withRequest($request); + + if (!$headlessMode->isEnabled() || ApplicationType::fromRequest($request)->isBackend()) { parent::determineBaseUrl(); return; } - if (($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface && - $this->hasCapability(ResourceStorage::CAPABILITY_PUBLIC)) { - $urlUtility = GeneralUtility::makeInstance(UrlUtility::class); + if ($this->hasCapability(ResourceStorage::CAPABILITY_PUBLIC)) { + $urlUtility = GeneralUtility::makeInstance(UrlUtility::class)->withRequest($request); $this->configuration['baseUri'] = $urlUtility->getStorageProxyUrl(); } diff --git a/Configuration/RequestMiddlewares.php b/Configuration/RequestMiddlewares.php index a0f054f1..dc26ccd1 100644 --- a/Configuration/RequestMiddlewares.php +++ b/Configuration/RequestMiddlewares.php @@ -30,6 +30,7 @@ 'headless/mode-setter' => [ 'before' => [ 'typo3/cms-frontend/base-redirect-resolver', + 'headless/cms-redirects/redirecthandler', ], 'target' => HeadlessModeSetter::class, ], diff --git a/Configuration/TypoScript/ContentElement/Bullets.typoscript b/Configuration/TypoScript/ContentElement/Bullets.typoscript index 5ec175c5..6578fcc5 100755 --- a/Configuration/TypoScript/ContentElement/Bullets.typoscript +++ b/Configuration/TypoScript/ContentElement/Bullets.typoscript @@ -1,5 +1,6 @@ tt_content.bullets =< lib.contentElementWithHeader tt_content.bullets { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/Div.typoscript b/Configuration/TypoScript/ContentElement/Div.typoscript index 674d68d3..79c10750 100755 --- a/Configuration/TypoScript/ContentElement/Div.typoscript +++ b/Configuration/TypoScript/ContentElement/Div.typoscript @@ -1,5 +1,6 @@ tt_content.div =< lib.contentElement tt_content.div { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/FeLogin.typoscript b/Configuration/TypoScript/ContentElement/FeLogin.typoscript index 10b77fd9..f1b75fdf 100644 --- a/Configuration/TypoScript/ContentElement/FeLogin.typoscript +++ b/Configuration/TypoScript/ContentElement/FeLogin.typoscript @@ -1,5 +1,6 @@ tt_content.felogin_login =< lib.contentElementWithHeader tt_content.felogin_login { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/Form.typoscript b/Configuration/TypoScript/ContentElement/Form.typoscript index c4d41648..f9c618c9 100644 --- a/Configuration/TypoScript/ContentElement/Form.typoscript +++ b/Configuration/TypoScript/ContentElement/Form.typoscript @@ -1,5 +1,6 @@ tt_content.form_formframework =< lib.contentElement tt_content.form_formframework { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/Header.typoscript b/Configuration/TypoScript/ContentElement/Header.typoscript index 4c88501d..ccbd6941 100755 --- a/Configuration/TypoScript/ContentElement/Header.typoscript +++ b/Configuration/TypoScript/ContentElement/Header.typoscript @@ -1 +1,4 @@ -tt_content.header =< lib.contentElementWithHeader +tt_content { + header =< lib.contentElementWithHeader + header.dataProcessing > +} diff --git a/Configuration/TypoScript/ContentElement/Html.typoscript b/Configuration/TypoScript/ContentElement/Html.typoscript index 7d2ac69d..6e40437c 100755 --- a/Configuration/TypoScript/ContentElement/Html.typoscript +++ b/Configuration/TypoScript/ContentElement/Html.typoscript @@ -1,5 +1,6 @@ tt_content.html =< lib.contentElement tt_content.html { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/Image.typoscript b/Configuration/TypoScript/ContentElement/Image.typoscript index 0abbc1d3..11448ed4 100755 --- a/Configuration/TypoScript/ContentElement/Image.typoscript +++ b/Configuration/TypoScript/ContentElement/Image.typoscript @@ -1,5 +1,6 @@ tt_content.image =< lib.contentElementWithHeader tt_content.image { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/List.typoscript b/Configuration/TypoScript/ContentElement/List.typoscript index d4ad4255..f3a30bbe 100755 --- a/Configuration/TypoScript/ContentElement/List.typoscript +++ b/Configuration/TypoScript/ContentElement/List.typoscript @@ -1,5 +1,6 @@ tt_content.list =< lib.contentElementWithHeader tt_content.list { + dataProcessing > fields { type = TEXT type { diff --git a/Configuration/TypoScript/ContentElement/MenuAbstract.typoscript b/Configuration/TypoScript/ContentElement/MenuAbstract.typoscript index 3afd7008..670be334 100755 --- a/Configuration/TypoScript/ContentElement/MenuAbstract.typoscript +++ b/Configuration/TypoScript/ContentElement/MenuAbstract.typoscript @@ -1,5 +1,6 @@ tt_content.menu_abstract =< lib.contentElementWithHeader tt_content.menu_abstract { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/MenuCategorizedContent.typoscript b/Configuration/TypoScript/ContentElement/MenuCategorizedContent.typoscript index 0b0ba510..d2fb607c 100755 --- a/Configuration/TypoScript/ContentElement/MenuCategorizedContent.typoscript +++ b/Configuration/TypoScript/ContentElement/MenuCategorizedContent.typoscript @@ -1,5 +1,6 @@ tt_content.menu_categorized_content =< lib.contentElementWithHeader tt_content.menu_categorized_content { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/MenuCategorizedPages.typoscript b/Configuration/TypoScript/ContentElement/MenuCategorizedPages.typoscript index c83696ea..2e33626c 100755 --- a/Configuration/TypoScript/ContentElement/MenuCategorizedPages.typoscript +++ b/Configuration/TypoScript/ContentElement/MenuCategorizedPages.typoscript @@ -1,5 +1,6 @@ tt_content.menu_categorized_pages =< lib.contentElementWithHeader tt_content.menu_categorized_pages { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/MenuPages.typoscript b/Configuration/TypoScript/ContentElement/MenuPages.typoscript index e0301fc8..d402c9ee 100755 --- a/Configuration/TypoScript/ContentElement/MenuPages.typoscript +++ b/Configuration/TypoScript/ContentElement/MenuPages.typoscript @@ -1,5 +1,6 @@ tt_content.menu_pages =< lib.contentElementWithHeader tt_content.menu_pages { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/MenuRecentlyUpdated.typoscript b/Configuration/TypoScript/ContentElement/MenuRecentlyUpdated.typoscript index 87849d7c..bc826ee4 100755 --- a/Configuration/TypoScript/ContentElement/MenuRecentlyUpdated.typoscript +++ b/Configuration/TypoScript/ContentElement/MenuRecentlyUpdated.typoscript @@ -1,5 +1,6 @@ tt_content.menu_recently_updated =< lib.contentElementWithHeader tt_content.menu_recently_updated { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/MenuRelatedPages.typoscript b/Configuration/TypoScript/ContentElement/MenuRelatedPages.typoscript index 20e5ad43..acefb4b5 100755 --- a/Configuration/TypoScript/ContentElement/MenuRelatedPages.typoscript +++ b/Configuration/TypoScript/ContentElement/MenuRelatedPages.typoscript @@ -1,5 +1,6 @@ tt_content.menu_related_pages =< lib.contentElementWithHeader tt_content.menu_related_pages { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/MenuSection.typoscript b/Configuration/TypoScript/ContentElement/MenuSection.typoscript index 5f50f964..43463dae 100755 --- a/Configuration/TypoScript/ContentElement/MenuSection.typoscript +++ b/Configuration/TypoScript/ContentElement/MenuSection.typoscript @@ -1,5 +1,6 @@ tt_content.menu_section =< lib.contentElementWithHeader tt_content.menu_section { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/MenuSectionPages.typoscript b/Configuration/TypoScript/ContentElement/MenuSectionPages.typoscript index bf92d3f4..b0195309 100755 --- a/Configuration/TypoScript/ContentElement/MenuSectionPages.typoscript +++ b/Configuration/TypoScript/ContentElement/MenuSectionPages.typoscript @@ -1,5 +1,6 @@ tt_content.menu_section_pages =< lib.contentElementWithHeader tt_content.menu_section_pages { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/MenuSitemap.typoscript b/Configuration/TypoScript/ContentElement/MenuSitemap.typoscript index 47c81921..810492d4 100755 --- a/Configuration/TypoScript/ContentElement/MenuSitemap.typoscript +++ b/Configuration/TypoScript/ContentElement/MenuSitemap.typoscript @@ -1,5 +1,6 @@ tt_content.menu_sitemap =< lib.contentElementWithHeader tt_content.menu_sitemap { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/MenuSitemapPages.typoscript b/Configuration/TypoScript/ContentElement/MenuSitemapPages.typoscript index eae6dde9..1988b4d7 100755 --- a/Configuration/TypoScript/ContentElement/MenuSitemapPages.typoscript +++ b/Configuration/TypoScript/ContentElement/MenuSitemapPages.typoscript @@ -1,5 +1,6 @@ tt_content.menu_sitemap_pages =< lib.contentElementWithHeader tt_content.menu_sitemap_pages { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/MenuSubpages.typoscript b/Configuration/TypoScript/ContentElement/MenuSubpages.typoscript index e2f87908..d89fa7a3 100755 --- a/Configuration/TypoScript/ContentElement/MenuSubpages.typoscript +++ b/Configuration/TypoScript/ContentElement/MenuSubpages.typoscript @@ -1,5 +1,6 @@ tt_content.menu_subpages =< lib.contentElementWithHeader tt_content.menu_subpages { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/Shortcut.typoscript b/Configuration/TypoScript/ContentElement/Shortcut.typoscript index eef56788..5f7a9473 100755 --- a/Configuration/TypoScript/ContentElement/Shortcut.typoscript +++ b/Configuration/TypoScript/ContentElement/Shortcut.typoscript @@ -1,5 +1,6 @@ tt_content.shortcut =< lib.contentElement tt_content.shortcut { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/Table.typoscript b/Configuration/TypoScript/ContentElement/Table.typoscript index 0e6b99e8..eb506522 100755 --- a/Configuration/TypoScript/ContentElement/Table.typoscript +++ b/Configuration/TypoScript/ContentElement/Table.typoscript @@ -1,5 +1,6 @@ tt_content.table =< lib.contentElementWithHeader tt_content.table { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/Text.typoscript b/Configuration/TypoScript/ContentElement/Text.typoscript index 2e2dd796..0034ab04 100755 --- a/Configuration/TypoScript/ContentElement/Text.typoscript +++ b/Configuration/TypoScript/ContentElement/Text.typoscript @@ -1,5 +1,6 @@ tt_content.text =< lib.contentElementWithHeader tt_content.text { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/Textmedia.typoscript b/Configuration/TypoScript/ContentElement/Textmedia.typoscript index 679cfd29..2c24464d 100755 --- a/Configuration/TypoScript/ContentElement/Textmedia.typoscript +++ b/Configuration/TypoScript/ContentElement/Textmedia.typoscript @@ -1,5 +1,6 @@ tt_content.textmedia =< lib.contentElementWithHeader tt_content.textmedia { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/Textpic.typoscript b/Configuration/TypoScript/ContentElement/Textpic.typoscript index 416fd1db..d57873c4 100755 --- a/Configuration/TypoScript/ContentElement/Textpic.typoscript +++ b/Configuration/TypoScript/ContentElement/Textpic.typoscript @@ -1,5 +1,6 @@ tt_content.textpic =< lib.contentElementWithHeader tt_content.textpic { + dataProcessing > fields { content { fields { diff --git a/Configuration/TypoScript/ContentElement/Uploads.typoscript b/Configuration/TypoScript/ContentElement/Uploads.typoscript index 487a8adc..181d5bf7 100755 --- a/Configuration/TypoScript/ContentElement/Uploads.typoscript +++ b/Configuration/TypoScript/ContentElement/Uploads.typoscript @@ -1,5 +1,6 @@ tt_content.uploads =< lib.contentElementWithHeader tt_content.uploads { + dataProcessing > fields { content { fields { diff --git a/Tests/Functional/ContentTypes/MenuCategorizedContentElementTest.php b/Tests/Functional/ContentTypes/MenuCategorizedContentElementTest.php index de27593e..ba3a9096 100644 --- a/Tests/Functional/ContentTypes/MenuCategorizedContentElementTest.php +++ b/Tests/Functional/ContentTypes/MenuCategorizedContentElementTest.php @@ -38,21 +38,17 @@ public function testMenuContentElement() self::assertIsArray($contentElement['content']['menu'][1]); $firstCategorizedContentElement = $contentElement['content']['menu'][0]; - self::assertEquals('17', $firstCategorizedContentElement['uid']); - self::assertEquals('1', $firstCategorizedContentElement['pid']); - self::assertEquals('1', $firstCategorizedContentElement['sorting']); - self::assertEquals('header', $firstCategorizedContentElement['CType']); - self::assertEquals('default', $firstCategorizedContentElement['frame_class']); + self::assertEquals('17', $firstCategorizedContentElement['id']); + self::assertEquals('header', $firstCategorizedContentElement['type']); + self::assertEquals('default', $firstCategorizedContentElement['appearance']['frameClass']); self::assertEquals('1', $firstCategorizedContentElement['colPos']); - self::assertEquals('3', $firstCategorizedContentElement['categories']); + self::assertEquals('SysCategory3Title', $firstCategorizedContentElement['categories']); $secondCategorizedContentElement = $contentElement['content']['menu'][1]; - self::assertEquals('18', $secondCategorizedContentElement['uid']); - self::assertEquals('1', $secondCategorizedContentElement['pid']); - self::assertEquals('1', $secondCategorizedContentElement['sorting']); - self::assertEquals('textpic', $secondCategorizedContentElement['CType']); - self::assertEquals('default', $secondCategorizedContentElement['frame_class']); + self::assertEquals('18', $secondCategorizedContentElement['id']); + self::assertEquals('textpic', $secondCategorizedContentElement['type']); + self::assertEquals('default', $secondCategorizedContentElement['appearance']['frameClass']); self::assertEquals('1', $secondCategorizedContentElement['colPos']); - self::assertEquals('3', $secondCategorizedContentElement['categories']); + self::assertEquals('SysCategory3Title', $secondCategorizedContentElement['categories']); } } diff --git a/Tests/Unit/DataProcessing/DatabaseQueryProcessorTest.php b/Tests/Unit/DataProcessing/DatabaseQueryProcessorTest.php index 053b8dfe..ef93d28e 100644 --- a/Tests/Unit/DataProcessing/DatabaseQueryProcessorTest.php +++ b/Tests/Unit/DataProcessing/DatabaseQueryProcessorTest.php @@ -15,12 +15,15 @@ use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; +use TYPO3\CMS\Core\Http\ServerRequest; use TYPO3\CMS\Core\TypoScript\TypoScriptService; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Frontend\ContentObject\ContentDataProcessor; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; +use function json_encode; + class DatabaseQueryProcessorTest extends UnitTestCase { use ProphecyTrait; @@ -50,6 +53,7 @@ protected function setUp(): void $this->typoScriptService = $this->prophesize(TypoScriptService::class); $this->contentDataProcessor = $this->prophesize(ContentDataProcessor::class); $this->contentObjectRenderer = $this->prophesize(ContentObjectRenderer::class); + $this->contentObjectRenderer->getRequest()->willReturn(new ServerRequest()); $this->subject = $this->getAccessibleMock(DatabaseQueryProcessor::class, ['createContentObjectRenderer'], [ $this->contentDataProcessor->reveal(), $this->typoScriptService->reveal(), @@ -114,6 +118,10 @@ public function processWithoutAdditionalFields(): void $this->contentObjectRenderer->stdWrapValue('as', $processorConfigurationWithoutTable, 'records')->shouldBeCalledOnce()->willReturn('records'); $contentObjectRenderer = $this->prophesize(ContentObjectRenderer::class); + $contentObjectRenderer->getRequest()->willReturn(new ServerRequest()); + $contentObjectRenderer->setRequest(Argument::type(ServerRequest::class))->shouldBeCalledOnce(); + $contentObjectRenderer->cObjGetSingle(Argument::any(), [])->willReturn(json_encode([ 'uid' => 1])); + $contentObjectRenderer->start($records[0], 'tt_content')->shouldBeCalledOnce(); $this->subject->expects(self::any())->method('createContentObjectRenderer')->willReturn($contentObjectRenderer->reveal()); $this->contentDataProcessor->process($contentObjectRenderer, $processorConfigurationWithoutTable, $records[0])->shouldBeCalledOnce()->willReturn($records[0]); @@ -158,6 +166,8 @@ public function processWithAdditionalFields(): void $this->contentObjectRenderer->stdWrapValue('as', $processorConfigurationWithoutTable, 'records')->shouldBeCalledOnce()->willReturn('records'); $contentObjectRenderer = $this->prophesize(ContentObjectRenderer::class); + $contentObjectRenderer->getRequest()->willReturn(new ServerRequest()); + $contentObjectRenderer->setRequest(Argument::type(ServerRequest::class))->shouldBeCalledOnce(); $this->subject->expects(self::any())->method('createContentObjectRenderer')->willReturn($contentObjectRenderer->reveal()); $expectedRecords = [ @@ -173,6 +183,7 @@ public function processWithAdditionalFields(): void $this->typoScriptService->convertPlainArrayToTypoScriptArray(['fields' => $fields, '_typoScriptNodeValue' => 'JSON'])->shouldBeCalledOnce()->willReturn($jsonCE); $contentObjectRenderer->start($records[0], $processorConfiguration['table'])->shouldBeCalledOnce(); + $contentObjectRenderer->setRequest(Argument::type(ServerRequest::class))->shouldBeCalledOnce(); $contentObjectRenderer->cObjGetSingle('JSON', $jsonCE)->willReturn('{"title":"title"}'); $processedData['records'] = $expectedRecords; diff --git a/Tests/Unit/Event/Listener/AfterLinkIsGeneratedListenerTest.php b/Tests/Unit/Event/Listener/AfterLinkIsGeneratedListenerTest.php index 2f7c25b4..c3fc744d 100644 --- a/Tests/Unit/Event/Listener/AfterLinkIsGeneratedListenerTest.php +++ b/Tests/Unit/Event/Listener/AfterLinkIsGeneratedListenerTest.php @@ -33,7 +33,10 @@ public function test__construct() $resolver->evaluate(Argument::any())->willReturn(true); $siteFinder = $this->prophesize(SiteFinder::class); - $listener = new AfterLinkIsGeneratedListener(new UrlUtility(null, $resolver->reveal(), $siteFinder->reveal()), $this->prophesize(LinkService::class)->reveal()); + $listener = new AfterLinkIsGeneratedListener( + new UrlUtility(null, $resolver->reveal(), $siteFinder->reveal()), + $this->prophesize(LinkService::class)->reveal() + ); self::assertInstanceOf(AfterLinkIsGeneratedListener::class, $listener); } @@ -44,7 +47,10 @@ public function test__invokeNotModifingAnything() $resolver->evaluate(Argument::any())->willReturn(true); $siteFinder = $this->prophesize(SiteFinder::class); - $listener = new AfterLinkIsGeneratedListener(new UrlUtility(null, $resolver->reveal(), $siteFinder->reveal()), $this->prophesize(LinkService::class)->reveal()); + $listener = new AfterLinkIsGeneratedListener( + new UrlUtility(null, $resolver->reveal(), $siteFinder->reveal()), + $this->prophesize(LinkService::class)->reveal() + ); $site = new Site('test', 1, []); $cObj = $this->prophesize(ContentObjectRenderer::class); @@ -73,8 +79,15 @@ public function test__invokeModifingFromPageUid() $resolver->evaluate(Argument::any())->willReturn(true); $urlUtility = $this->prophesize(UrlUtility::class); - $urlUtility->getFrontendUrlForPage(Argument::is('/'), Argument::is(2))->willReturn('https://frontend-domain.tld/page'); - $urlUtility->getFrontendUrlWithSite(Argument::is('/'), Argument::any())->willReturn('https://frontend-domain.tld/page'); + $urlUtility->getFrontendUrlForPage( + Argument::is('/'), + Argument::is(2) + )->willReturn('https://frontend-domain.tld/page'); + $urlUtility->getFrontendUrlWithSite( + Argument::is('/'), + Argument::any(), + Argument::is('frontendBase') + )->willReturn('https://frontend-domain.tld/page'); $site = new Site('test', 1, []); $cObj = $this->prophesize(ContentObjectRenderer::class); @@ -83,7 +96,10 @@ public function test__invokeModifingFromPageUid() $urlUtility->withRequest($request)->willReturn($urlUtility->reveal()); - $listener = new AfterLinkIsGeneratedListener($urlUtility->reveal(), $this->prophesize(LinkService::class)->reveal()); + $listener = new AfterLinkIsGeneratedListener( + $urlUtility->reveal(), + $this->prophesize(LinkService::class)->reveal() + ); $linkResult = new LinkResult('page', '/'); $linkResult = $linkResult->withLinkText('t3://page?uid=2'); @@ -102,7 +118,11 @@ public function test__invokeModifingWithoutPageId() $site = new Site('test', 1, []); $urlUtility = $this->prophesize(UrlUtility::class); - $urlUtility->getFrontendUrlWithSite(Argument::is('/'), Argument::is($site))->willReturn('https://front.typo3.tld'); + $urlUtility->getFrontendUrlWithSite( + Argument::is('/'), + Argument::is($site), + Argument::is('frontendBase') + )->willReturn('https://front.typo3.tld'); $cObj = $this->prophesize(ContentObjectRenderer::class); $request = (new ServerRequest())->withAttribute('site', $site); @@ -110,7 +130,10 @@ public function test__invokeModifingWithoutPageId() $urlUtility->withRequest($request)->willReturn($urlUtility->reveal()); - $listener = new AfterLinkIsGeneratedListener($urlUtility->reveal(), $this->prophesize(LinkService::class)->reveal()); + $listener = new AfterLinkIsGeneratedListener( + $urlUtility->reveal(), + $this->prophesize(LinkService::class)->reveal() + ); $linkResult = new LinkResult('page', '/'); $linkResult = $linkResult->withLinkText('|'); @@ -149,4 +172,46 @@ public function test__invokeModifingExternalSite() self::assertSame('https://front.typo3.tld', $event->getLinkResult()->getUrl()); } + + public function test__SitemapLink() + { + $resolver = $this->prophesize(Resolver::class); + $resolver->evaluate(Argument::any())->willReturn(true); + + $site = new Site('test', 1, []); + + $urlUtility = $this->prophesize(UrlUtility::class); + $urlUtility->getFrontendUrlWithSite( + Argument::is('https://typo3.tld/sitemap-type/pages/sitemap.xml'), + Argument::is($site), + Argument::is('frontendApiProxy') + ) + ->willReturn('https://front.typo3.tld/headless/sitemap-type/pages/sitemap.xml'); + + $linkService = $this->prophesize(LinkService::class); + $linkService->resolve(Argument::any())->willReturn(['pageuid' => 5]); + + $cObj = $this->prophesize(ContentObjectRenderer::class); + $request = (new ServerRequest())->withAttribute('site', $site); + $cObj->getRequest()->willReturn($request); + + $urlUtility->withRequest($request)->willReturn($urlUtility->reveal()); + + $listener = new AfterLinkIsGeneratedListener($urlUtility->reveal(), $linkService->reveal()); + + $linkResult = new LinkResult('page', 'https://typo3.tld/sitemap-type/pages/sitemap.xml'); + $linkResult = $linkResult->withLinkConfiguration([ + 'parameter' => 't3://page?uid=current&type=1533906435&sitemap=pages', + 'forceAbsoluteUrl' => true, + 'additionalParams' => '&sitemap=pages', + ]); + + $event = new AfterLinkIsGeneratedEvent($linkResult, $cObj->reveal(), []); + $listener($event); + + self::assertSame( + 'https://front.typo3.tld/headless/sitemap-type/pages/sitemap.xml', + $event->getLinkResult()->getUrl() + ); + } } diff --git a/Tests/Unit/Event/Listener/AfterPagePreviewUriGeneratedListenerTest.php b/Tests/Unit/Event/Listener/AfterPagePreviewUriGeneratedListenerTest.php index 21e40f8e..a32090a3 100644 --- a/Tests/Unit/Event/Listener/AfterPagePreviewUriGeneratedListenerTest.php +++ b/Tests/Unit/Event/Listener/AfterPagePreviewUriGeneratedListenerTest.php @@ -49,7 +49,7 @@ public function testLink() $resolver = $this->prophesize(Resolver::class); $resolver->evaluate(Argument::any())->willReturn(true); $siteFinder = $this->prophesize(SiteFinder::class); - $siteFinder->getSiteByPageId(Argument::any())->willReturn($site = new Site('test', 1, ['headless' => HeadlessMode::MIXED, 'frontendBase' => 'https://front.test.tld'])); + $siteFinder->getSiteByPageId(Argument::any())->willReturn($site = new Site('test', 1, ['headless' => HeadlessMode::MIXED, 'frontendBase' => 'https://front.test.tld', 'base' => 'https://test.tld'])); $listener = new AfterPagePreviewUriGeneratedListener(new UrlUtility( null, @@ -71,11 +71,11 @@ public function testLink() $GLOBALS['TYPO3_REQUEST'] = new ServerRequest(); $listener->__invoke($event); - self::assertSame('https://front.test.tld/page', (string)$event->getPreviewUri()); + self::assertSame('https://test.tld/page', (string)$event->getPreviewUri()); $GLOBALS['BE_USER'] = new BackendUserAuthentication(); $listener->__invoke($event); - self::assertSame('https://front.test.tld/page', (string)$event->getPreviewUri()); + self::assertSame('https://test.tld/page', (string)$event->getPreviewUri()); } public function testSiteNotFound() diff --git a/Tests/Unit/Middleware/SiteBaseRedirectResolverTest.php b/Tests/Unit/Middleware/SiteBaseRedirectResolverTest.php index 711ab913..4353a0f2 100644 --- a/Tests/Unit/Middleware/SiteBaseRedirectResolverTest.php +++ b/Tests/Unit/Middleware/SiteBaseRedirectResolverTest.php @@ -12,6 +12,8 @@ namespace FriendsOfTYPO3\Headless\Tests\Unit\Middleware; use FriendsOfTYPO3\Headless\Middleware\SiteBaseRedirectResolver; +use FriendsOfTYPO3\Headless\Utility\Headless; +use FriendsOfTYPO3\Headless\Utility\HeadlessMode; use FriendsOfTYPO3\Headless\Utility\UrlUtility; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; @@ -67,7 +69,7 @@ public function testJsonRedirect() GeneralUtility::setContainer($container); - $resolver = new SiteBaseRedirectResolver(); + $resolver = new SiteBaseRedirectResolver(new HeadlessMode()); $request = new ServerRequest(); $request = $request->withAttribute('site', $site); @@ -76,6 +78,7 @@ public function testJsonRedirect() $request = $request->withUri($uri); $request = $request->withAttribute('routing', new SiteRouteResult($uri, $site)); + $request = $request->withAttribute('headless', new Headless(HeadlessMode::FULL)); $response = $resolver->process($request, $this->prophesize(RequestHandler::class)->reveal()); diff --git a/Tests/Unit/Utility/HeadlessModeTest.php b/Tests/Unit/Utility/HeadlessModeTest.php index 56263701..066db5fd 100644 --- a/Tests/Unit/Utility/HeadlessModeTest.php +++ b/Tests/Unit/Utility/HeadlessModeTest.php @@ -13,6 +13,9 @@ use FriendsOfTYPO3\Headless\Utility\HeadlessMode; use PHPUnit\Framework\TestCase; use TYPO3\CMS\Core\Http\ServerRequest; +use TYPO3\CMS\Core\Http\Uri; +use TYPO3\CMS\Core\Site\Entity\Site; +use TYPO3\CMS\Core\Site\Entity\SiteLanguage; class HeadlessModeTest extends TestCase { @@ -20,7 +23,7 @@ public function testMixedModeWithoutHeader(): void { $mode = new HeadlessMode(); - $request = new ServerRequest(); + $request = new ServerRequest(); $request = $request->withAttribute('headless', new Headless(HeadlessMode::MIXED)); $mode = $mode->withRequest($request); @@ -32,7 +35,7 @@ public function testMixedModeWithHeader(): void { $mode = new HeadlessMode(); - $request = new ServerRequest(); + $request = new ServerRequest(); $request = $request->withHeader('Accept', 'application/json'); $request = $request->withAttribute('headless', new Headless(HeadlessMode::MIXED)); @@ -45,7 +48,7 @@ public function testDisabled(): void { $mode = new HeadlessMode(); - $request = new ServerRequest(); + $request = new ServerRequest(); $request = $request->withHeader('Accept', 'application/json'); $request = $request->withAttribute('headless', new Headless(HeadlessMode::NONE)); @@ -58,7 +61,7 @@ public function testNotSet(): void { $mode = new HeadlessMode(); - $request = new ServerRequest(); + $request = new ServerRequest(); $request = $request->withHeader('Accept', 'application/json'); $mode = $mode->withRequest($request); @@ -79,4 +82,35 @@ public function testFullMode(): void self::assertTrue($mode->isEnabled()); } + + public function testBackendRequestOverride(): void + { + $mode = new HeadlessMode(); + + $request = new ServerRequest(); + + $mode = $mode->withRequest($request); + + self::assertNull($request->getAttribute('headless')); + + $request = $mode->overrideBackendRequestBySite(new Site('test', 1, ['headless' => HeadlessMode::FULL])); + + self::assertSame(HeadlessMode::FULL, $request->getAttribute('headless')->getMode()); + + $request = $mode->overrideBackendRequestBySite(new Site('test', 1, ['headless' => HeadlessMode::MIXED])); + + self::assertSame(HeadlessMode::NONE, $request->getAttribute('headless')->getMode()); + + $request = $mode->overrideBackendRequestBySite( + new Site('test', 1, ['headless' => HeadlessMode::MIXED]), + new SiteLanguage( + 1, + 'en_US', + new Uri('/'), + [] + ) + ); + + self::assertSame(HeadlessMode::NONE, $request->getAttribute('headless')->getMode()); + } } diff --git a/Tests/Unit/Utility/UrlUtilityTest.php b/Tests/Unit/Utility/UrlUtilityTest.php index 827d7944..73f176e3 100644 --- a/Tests/Unit/Utility/UrlUtilityTest.php +++ b/Tests/Unit/Utility/UrlUtilityTest.php @@ -35,6 +35,7 @@ public function testFrontendUrls(): void $headlessMode = $this->createHeadlessMode(); $site = $this->prophesize(Site::class); + $site->getBase()->shouldBeCalled(2)->willReturn(new Uri('https://test-backend-api.tld')); $site->getConfiguration()->shouldBeCalled(3)->willReturn([ 'base' => 'https://www.typo3.org', 'languages' => [], @@ -101,6 +102,8 @@ public function testFrontendUrls(): void $siteFinder = $this->prophesize(SiteFinder::class); + $site->getBase()->shouldBeCalled(2)->willReturn(new Uri('https://test-backend3-api.tld')); + $urlUtility = new UrlUtility(null, $resolver->reveal(), $siteFinder->reveal(), null, $headlessMode); $urlUtility = $urlUtility->withSite($site->reveal()); @@ -108,6 +111,8 @@ public function testFrontendUrls(): void self::assertSame('https://test-frontend-api3.tld/headless', $urlUtility->getProxyUrl()); self::assertSame('https://test-frontend-api3.tld/headless/fileadmin', $urlUtility->getStorageProxyUrl()); self::assertSame('https://test-frontend3.tld/sitemap', $urlUtility->resolveKey('SpecialSitemapKey')); + self::assertSame('https://test-frontend-api3.tld/headless', $urlUtility->getFrontendUrlWithSite('https://test-backend3-api.tld', $site->reveal(), 'frontendApiProxy')); + self::assertSame('#fragment-123', $urlUtility->getFrontendUrlWithSite('#fragment-123', $site->reveal())); } public function testFrontendUrlsWithBaseProductionAndLocalOverride(): void diff --git a/composer.json b/composer.json index b32896d5..3b09128f 100644 --- a/composer.json +++ b/composer.json @@ -127,7 +127,12 @@ ], "ci:yaml:lint": "find . ! -path '*.Build/*' -name '*.yml' | xargs php ./.Build/vendor/bin/yaml-lint", "docs:generate": [ - "docker run --rm t3docs/render-documentation show-shell-commands > tempfile.sh; echo 'dockrun_t3rd makehtml' >> tempfile.sh; bash tempfile.sh; rm tempfile.sh" + "@docs:generate:pullimage", + "docker run --rm ghcr.io/t3docs/render-documentation show-shell-commands > tempfile.sh; echo 'dockrun_t3rd makehtml' >> tempfile.sh; bash tempfile.sh; rm tempfile.sh" + ], + "docs:generate:pullimage": [ + "docker pull ghcr.io/t3docs/render-documentation", + "docker tag ghcr.io/t3docs/render-documentation t3docs/render-documentation" ], "fix:php:cs-fixer": [ "php-cs-fixer fix -v --using-cache no --config .php-cs-fixer.php" diff --git a/ext_emconf.php b/ext_emconf.php index a4e4e071..1866c8d0 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -15,7 +15,7 @@ 'author_email' => 'extensions@macopedia.pl', 'author_company' => 'Macopedia Sp. z o.o.', 'category' => 'fe', - 'version' => '4.2.3', + 'version' => '4.2.7', 'constraints' => [ 'depends' => [ 'frontend' => '12.4.3-12.5.99',