Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into refactor-autogene…
Browse files Browse the repository at this point in the history
…rate-feature
  • Loading branch information
kitzberger committed Mar 5, 2024
2 parents bd702b3 + b4d6021 commit 641483d
Show file tree
Hide file tree
Showing 49 changed files with 286 additions and 81 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -62,7 +62,7 @@ jobs:
- "ts:lint"
- "php:cs-fixer"
php-version:
- 8.1
- 8.2
tests:
runs-on: ubuntu-latest
strategy:
Expand All @@ -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 }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codecoverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 9 additions & 4 deletions Classes/ContentObject/JsonContentContentObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
28 changes: 11 additions & 17 deletions Classes/DataProcessing/DatabaseQueryProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;

Expand All @@ -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.'])) {
Expand All @@ -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);
Expand Down
17 changes: 15 additions & 2 deletions Classes/Event/Listener/AfterLinkIsGeneratedListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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);
}
}

Expand Down
14 changes: 4 additions & 10 deletions Classes/Event/Listener/AfterPagePreviewUriGeneratedListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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)));
Expand Down
2 changes: 2 additions & 0 deletions Classes/Middleware/RedirectHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down
7 changes: 4 additions & 3 deletions Classes/Middleware/SiteBaseRedirectResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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;
}

Expand Down
20 changes: 20 additions & 0 deletions Classes/Utility/HeadlessMode.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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));
}
}
9 changes: 9 additions & 0 deletions Classes/Utility/UrlUtility.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use TYPO3\CMS\Core\Utility\GeneralUtility;

use function array_merge;
use function ltrim;
use function rtrim;
use function str_contains;

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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] !== '/') {
Expand Down
2 changes: 1 addition & 1 deletion Classes/ViewHelpers/LoginFormViewHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
12 changes: 11 additions & 1 deletion Classes/XClass/Controller/PreviewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
}
9 changes: 8 additions & 1 deletion Classes/XClass/Preview/PreviewUriBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
Loading

0 comments on commit 641483d

Please sign in to comment.