diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 06285280..bff49230 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -63,14 +63,67 @@ jobs:
- "php:cs-fixer"
php-version:
- 8.2
- tests:
+ testV12:
runs-on: ubuntu-latest
strategy:
max-parallel: 2
matrix:
- php-versions: [8.1]
+ php-versions: [ 8.1, 8.2 ]
typo3-versions:
- - {typo3: 12, testing: ^7.0@dev}
+ - { typo3: 12, testing: ^7.0, phpunit: ^11, yaml: ^6 }
+
+ name: "Run tests with PHP ${{ matrix.php-versions }}
+ using TYPO3 ${{ matrix.typo3-versions.typo3 }}
+ with testing framework version ${{ matrix.typo3-versions.testing }}"
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-versions }}
+ extensions: intl, mbstring, pdo_sqlite
+
+ - name: "Cache composer dependencies"
+ uses: actions/cache@v4
+ with:
+ path: ~/.composer/cache
+ key: php-${{ matrix.php-versions }}
+ -typo3-${{ matrix.typo3-versions.typo3 }}
+ -phpunit-${{ matrix.typo3-versions.phpunit }}
+ -yaml-${{ matrix.typo3-versions.yaml }}
+ -testing-${{ matrix.typo3-versions.testing }}
+ -composer-${{ hashFiles('composer.json') }}
+ restore-keys: |
+ php-${{ matrix.php-versions }}
+ -typo3-${{ matrix.typo3-versions.typo3 }}
+ -phpunit-${{ matrix.typo3-versions.phpunit }}
+ -phpcov-${{ matrix.typo3-versions.phpcov }}
+ -yaml-${{ matrix.typo3-versions.yaml }}
+ -testing-${{ matrix.typo3-versions.testing }}composer-
+ php-${{ matrix.php-versions }}-typo3-
+
+ - name: "Install composer dependencies"
+ run: composer require typo3/minimal
+ "^${{ matrix.typo3-versions.typo3 }}"
+ typo3/testing-framework "${{ matrix.typo3-versions.testing }}"
+ phpunit/phpunit "${{ matrix.typo3-versions.phpunit }}"
+ symfony/yaml "${{ matrix.typo3-versions.yaml }}"
+ --prefer-dist --no-progress --no-suggest
+
+ - name: "Run Unit tests"
+ run: composer ci:test:unit
+
+ - name: "Functional tests"
+ run: composer ci:test:functional
+
+ testsV13:
+ runs-on: ubuntu-latest
+ strategy:
+ max-parallel: 2
+ matrix:
+ php-versions: [8.2, 8.3]
+ typo3-versions:
+ - {typo3: 13, testing: ^8.0, phpunit: ^11, yaml: ^7 }
name: "Run tests with PHP ${{ matrix.php-versions }}
using TYPO3 ${{ matrix.typo3-versions.typo3 }}
@@ -89,19 +142,26 @@ jobs:
path: ~/.composer/cache
key: php-${{ matrix.php-versions }}
-typo3-${{ matrix.typo3-versions.typo3 }}
+ -phpunit-${{ matrix.typo3-versions.phpunit }}
+ -phpcov-${{ matrix.typo3-versions.phpcov }}
+ -yaml-${{ matrix.typo3-versions.yaml }}
-testing-${{ matrix.typo3-versions.testing }}
-composer-${{ hashFiles('composer.json') }}
restore-keys: |
php-${{ matrix.php-versions }}
-typo3-${{ matrix.typo3-versions.typo3 }}
+ -phpunit-${{ matrix.typo3-versions.phpunit }}
+ -yaml-${{ matrix.typo3-versions.yaml }}
-testing-${{ matrix.typo3-versions.testing }}composer-
php-${{ matrix.php-versions }}-typo3-
- name: "Install composer dependencies"
- run: composer require typo3/minimal
+ run: composer remove php-coveralls/php-coveralls --dev --no-progress && composer require typo3/minimal
"^${{ matrix.typo3-versions.typo3 }}"
typo3/testing-framework "${{ matrix.typo3-versions.testing }}"
- --prefer-dist --no-progress --no-suggest
+ phpunit/phpunit "${{ matrix.typo3-versions.phpunit }}"
+ symfony/yaml "${{ matrix.typo3-versions.yaml }}"
+ --prefer-dist --no-progress
- name: "Run Unit tests"
run: composer ci:test:unit
diff --git a/Classes/ContentObject/JsonContentContentObject.php b/Classes/ContentObject/JsonContentContentObject.php
index 3f717984..5437deeb 100755
--- a/Classes/ContentObject/JsonContentContentObject.php
+++ b/Classes/ContentObject/JsonContentContentObject.php
@@ -14,7 +14,10 @@
use FriendsOfTYPO3\Headless\Json\JsonEncoder;
use FriendsOfTYPO3\Headless\Json\JsonEncoderInterface;
use FriendsOfTYPO3\Headless\Utility\HeadlessUserInt;
+use Psr\EventDispatcher\EventDispatcherInterface;
use TYPO3\CMS\Backend\View\BackendLayoutView;
+use TYPO3\CMS\Core\Information\Typo3Version;
+use TYPO3\CMS\Core\TimeTracker\TimeTracker;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentContentObject;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
@@ -23,6 +26,7 @@
use function count;
use function is_array;
use function json_decode;
+use function json_encode;
use function str_contains;
use function trim;
@@ -102,11 +106,18 @@ class JsonContentContentObject extends ContentContentObject
{
private HeadlessUserInt $headlessUserInt;
private JsonEncoderInterface $jsonEncoder;
+ /**
+ * @var mixed|object|\Psr\Log\LoggerAwareInterface|\TYPO3\CMS\Core\SingletonInterface|TimeTracker|(TimeTracker&\Psr\Log\LoggerAwareInterface)|(TimeTracker&\TYPO3\CMS\Core\SingletonInterface)|null
+ */
+ private TimeTracker $timeTracker;
+ private EventDispatcherInterface $eventDispatcher;
public function __construct()
{
$this->headlessUserInt = GeneralUtility::makeInstance(HeadlessUserInt::class);
$this->jsonEncoder = GeneralUtility::makeInstance(JsonEncoder::class);
+ $this->timeTracker = GeneralUtility::makeInstance(TimeTracker::class);
+ $this->eventDispatcher = GeneralUtility::makeInstance(EventDispatcherInterface::class);
}
/**
@@ -199,6 +210,8 @@ protected function groupContentElementsByColPos(array $contentElements, array $c
*/
private function prepareValue(array $conf): array
{
+ $t3v13andAbove = (new Typo3Version())->getMajorVersion() >= 13;
+
$frontendController = $this->getTypoScriptFrontendController();
$theValue = [];
$originalRec = $frontendController->currentRecord;
@@ -233,20 +246,44 @@ private function prepareValue(array $conf): array
$tmpValue = '';
do {
- $records = $this->cObj->getRecords($conf['table'], $conf['select.']);
+ if ($t3v13andAbove) {
+ $modifyRecordsEvent = $this->eventDispatcher->dispatch(
+ new \TYPO3\CMS\Frontend\ContentObject\Event\ModifyRecordsAfterFetchingContentEvent(
+ $this->cObj->getRecords($conf['table'], $conf['select.']),
+ json_encode($theValue, JSON_THROW_ON_ERROR),
+ $slide,
+ $slideCollect,
+ $slideCollectReverse,
+ $slideCollectFuzzy,
+ $conf
+ )
+ );
+
+ $records = $modifyRecordsEvent->getRecords();
+ $theValue = json_decode($modifyRecordsEvent->getFinalContent(), true, 512, JSON_THROW_ON_ERROR);
+ $slide = $modifyRecordsEvent->getSlide();
+ $slideCollect = $modifyRecordsEvent->getSlideCollect();
+ $slideCollectReverse = $modifyRecordsEvent->getSlideCollectReverse();
+ $slideCollectFuzzy = $modifyRecordsEvent->getSlideCollectFuzzy();
+ $conf = $modifyRecordsEvent->getConfiguration();
+ } else {
+ $records = $this->cObj->getRecords($conf['table'], $conf['select.']);
+ }
$cobjValue = [];
if (!empty($records)) {
- $this->getTimeTracker()->setTSlogMessage('NUMROWS: ' . count($records));
+ $this->timeTracker->setTSlogMessage('NUMROWS: ' . count($records));
$cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class, $frontendController);
$cObj->setParent($this->cObj->data, $this->cObj->currentRecord);
$this->cObj->currentRecordNumber = 0;
foreach ($records as $row) {
- // Call hook for possible manipulation of database row for cObj->data
- foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content_content.php']['modifyDBRow'] ?? [] as $className) {
- $_procObj = GeneralUtility::makeInstance($className);
- $_procObj->modifyDBRow($row, $conf['table']);
+ if (!$t3v13andAbove) {
+ // Call hook for possible manipulation of database row for cObj->data
+ foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content_content.php']['modifyDBRow'] ?? [] as $className) {
+ $_procObj = GeneralUtility::makeInstance($className);
+ $_procObj->modifyDBRow($row, $conf['table']);
+ }
}
$registerField = $conf['table'] . ':' . ($row['uid'] ?? 0);
if (!($frontendController->recordRegister[$registerField] ?? false)) {
@@ -282,7 +319,7 @@ private function prepareValue(array $conf): array
}
$again = (string)$conf['select.']['pidInList'] !== '';
}
- } while ($again && $slide && ((string)$tmpValue === '' && $slideCollectFuzzy || $slideCollect));
+ } while ($again && $slide && (((string)$tmpValue === '' && $slideCollectFuzzy) || $slideCollect));
$theValue = $this->groupContentElementsByColPos($theValue, $conf);
// Restore
diff --git a/Classes/Middleware/ShortcutAndMountPointRedirect.php b/Classes/Middleware/ShortcutAndMountPointRedirect.php
index 8c644bfa..0c8b15b9 100644
--- a/Classes/Middleware/ShortcutAndMountPointRedirect.php
+++ b/Classes/Middleware/ShortcutAndMountPointRedirect.php
@@ -12,29 +12,16 @@
namespace FriendsOfTYPO3\Headless\Middleware;
use FriendsOfTYPO3\Headless\Utility\HeadlessMode;
+use FriendsOfTYPO3\Headless\Utility\UrlUtility;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
-use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
-use Psr\Log\LoggerAwareInterface;
-use Psr\Log\LoggerAwareTrait;
-use TYPO3\CMS\Core\Domain\Repository\PageRepository;
-use TYPO3\CMS\Core\Http\ImmediateResponseException;
use TYPO3\CMS\Core\Http\JsonResponse;
use TYPO3\CMS\Core\Http\RedirectResponse;
-use TYPO3\CMS\Core\Routing\PageArguments;
use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Frontend\Controller\ErrorController;
-use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons;
-
-use function is_array;
-use function parse_url;
-
-class ShortcutAndMountPointRedirect implements MiddlewareInterface, LoggerAwareInterface
+class ShortcutAndMountPointRedirect extends \TYPO3\CMS\Frontend\Middleware\ShortcutAndMountPointRedirect
{
- use LoggerAwareTrait;
-
public function __construct(private readonly HeadlessMode $headlessMode) {}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
@@ -46,96 +33,18 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
return $handler->handle($request);
}
- $exposeInformation = $GLOBALS['TYPO3_CONF_VARS']['FE']['exposeRedirectInformation'] ?? false;
-
- // Check for shortcut page and mount point redirect
- try {
- $redirectToUri = $this->getRedirectUri($request);
- } catch (ImmediateResponseException $e) {
- return $e->getResponse();
- }
- if ($redirectToUri !== null && $redirectToUri !== (string)$request->getUri()) {
- /** @var PageArguments $pageArguments */
- $pageArguments = $request->getAttribute('routing', null);
- $message = 'TYPO3 Shortcut/Mountpoint' . ($exposeInformation ? ' at page with ID ' . $pageArguments->getPageId() : '');
-
- if ($this->isHeadlessEnabled($request)) {
- $parsed = parse_url($redirectToUri);
- if (is_array($parsed)) {
- $path = $parsed['path'] ?? '/';
- return new JsonResponse(['redirectUrl' => $path, 'statusCode' => 307]);
- }
- }
-
- return new RedirectResponse(
- $redirectToUri,
- 307,
- ['X-Redirect-By' => $message]
- );
- }
-
- // See if the current page is of doktype "External URL", if so, do a redirect as well.
- $controller = $request->getAttribute('frontend.controller');
- if ((int)$controller->page['doktype'] === PageRepository::DOKTYPE_LINK) {
- $externalUrl = $this->prefixExternalPageUrl(
- $controller->page['url'],
- $request->getAttribute('normalizedParams')->getSiteUrl()
- );
- $message = 'TYPO3 External URL' . ($exposeInformation ? ' at page with ID ' . $controller->page['uid'] : '');
- if (!empty($externalUrl)) {
- if ($this->isHeadlessEnabled($request)) {
- return new JsonResponse(['redirectUrl' => $externalUrl, 'statusCode' => 303]);
- }
+ $coreResponse = parent::process($request, $handler);
- return new RedirectResponse(
- $externalUrl,
- 303,
- ['X-Redirect-By' => $message]
- );
- }
- $this->logger->error(
- 'Page of type "External URL" could not be resolved properly',
- [
- 'page' => $controller->page,
- ]
- );
- return GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
- $request,
- 'Page of type "External URL" could not be resolved properly',
- $controller->getPageAccessFailureReasons(PageAccessFailureReasons::INVALID_EXTERNAL_URL)
- );
+ if ($coreResponse instanceof RedirectResponse && $this->isHeadlessEnabled($request)) {
+ return new JsonResponse([
+ 'redirectUrl' => GeneralUtility::makeInstance(UrlUtility::class)
+ ->withRequest($request)
+ ->prepareRelativeUrlIfPossible($coreResponse->getHeader('location')[0] ?? ''),
+ 'statusCode' => $coreResponse->getStatusCode(),
+ ]);
}
- return $handler->handle($request);
- }
-
- protected function getRedirectUri(ServerRequestInterface $request): ?string
- {
- $controller = $request->getAttribute('frontend.controller');
- $redirectToUri = $controller->getRedirectUriForShortcut($request);
- return $redirectToUri ?? $controller->getRedirectUriForMountPoint($request);
- }
-
- /**
- * Returns the redirect URL for the input page row IF the doktype is set to 3.
- *
- * @param string $redirectTo The page row to return URL type for
- * @param string $sitePrefix if no protocol or relative path given, the site prefix is added
- * @return string The URL from based on the external page URL given with a prefix.
- */
- protected function prefixExternalPageUrl(string $redirectTo, string $sitePrefix): string
- {
- $uI = parse_url($redirectTo);
- // If relative path, prefix Site URL
- // If it's a valid email without protocol, add "mailto:"
- if (!($uI['scheme'] ?? false)) {
- if (GeneralUtility::validEmail($redirectTo)) {
- $redirectTo = 'mailto:' . $redirectTo;
- } elseif (!str_starts_with($redirectTo, '/')) {
- $redirectTo = $sitePrefix . $redirectTo;
- }
- }
- return $redirectTo;
+ return $coreResponse;
}
private function isHeadlessEnabled(ServerRequestInterface $request): bool
diff --git a/Classes/Seo/CanonicalGenerator.php b/Classes/Seo/CanonicalGenerator.php
index fafb93cc..e24f9cf6 100644
--- a/Classes/Seo/CanonicalGenerator.php
+++ b/Classes/Seo/CanonicalGenerator.php
@@ -12,73 +12,42 @@
namespace FriendsOfTYPO3\Headless\Seo;
use FriendsOfTYPO3\Headless\Utility\HeadlessMode;
-use Psr\EventDispatcher\EventDispatcherInterface;
-use TYPO3\CMS\Core\Domain\Page;
-use TYPO3\CMS\Core\Domain\Repository\PageRepository;
use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
-use TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent;
+use TYPO3\CMS\Seo\Canonical\CanonicalGenerator as CoreCanonicalGenerator;
use function htmlspecialchars;
use function json_encode;
/**
- * Overridden core version with headless implementation
+ * Decorate Core version with headless flavor
*
* @codeCoverageIgnore
*/
-class CanonicalGenerator extends \TYPO3\CMS\Seo\Canonical\CanonicalGenerator
+class CanonicalGenerator
{
- protected TypoScriptFrontendController $typoScriptFrontendController;
- protected PageRepository $pageRepository;
- protected EventDispatcherInterface $eventDispatcher;
-
public function handle(array &$params): string
{
- if ($this->typoScriptFrontendController->config['config']['disableCanonical'] ?? false) {
- return '';
- }
+ $canonical = GeneralUtility::makeInstance(CoreCanonicalGenerator::class)->generate($params);
- $event = new ModifyUrlForCanonicalTagEvent('', $params['request'], new Page($params['page']));
- $event = $this->eventDispatcher->dispatch($event);
- $href = $event->getUrl();
-
- if (empty($href) && (int)$this->typoScriptFrontendController->page['no_index'] === 1) {
+ if ($canonical === '') {
return '';
}
- if (empty($href)) {
- // 1) Check if page has canonical URL set
- $href = $this->checkForCanonicalLink();
- }
- if (empty($href)) {
- // 2) Check if page show content from other page
- $href = $this->checkContentFromPid();
- }
- if (empty($href)) {
- // 3) Fallback, create canonical URL
- $href = $this->checkDefaultCanonical();
- }
+ if (GeneralUtility::makeInstance(HeadlessMode::class)->withRequest($params['request'])->isEnabled()) {
+ $canonical = [
+ 'href' => $this->processCanonical($canonical),
+ 'rel' => 'canonical',
+ ];
- if (!empty($href)) {
- if (GeneralUtility::makeInstance(HeadlessMode::class)->withRequest($params['request'])->isEnabled()) {
- $canonical = [
- 'href' => htmlspecialchars($href),
- 'rel' => 'canonical',
- ];
+ $params['_seoLinks'][] = $canonical;
+ $canonical = json_encode($canonical);
+ }
- $params['_seoLinks'][] = $canonical;
- $canonical = json_encode($canonical);
- } else {
- $canonical = ' 'canonical',
- 'href' => $href,
- ], true) . '/>' . LF;
- $this->typoScriptFrontendController->additionalHeaderData[] = $canonical;
- }
+ return $canonical;
+ }
- return $canonical;
- }
- return '';
+ protected function processCanonical(string $canonical): string
+ {
+ return htmlspecialchars(GeneralUtility::get_tag_attributes($canonical)['href'] ?? '');
}
}
diff --git a/Classes/Seo/MetaHandler.php b/Classes/Seo/MetaHandler.php
index d8b7f799..1f1aa2b3 100644
--- a/Classes/Seo/MetaHandler.php
+++ b/Classes/Seo/MetaHandler.php
@@ -36,7 +36,7 @@ public function process(ServerRequestInterface $request, TypoScriptFrontendContr
GeneralUtility::callUserFunction($_funcRef, $_params, $_ref);
}
- $content['seo']['title'] = $controller->generatePageTitle();
+ $content['seo']['title'] = $controller->generatePageTitle($request);
$this->generateMetaTagsFromTyposcript(
$controller->pSetup['meta.'] ?? [],
diff --git a/Classes/XClass/Controller/FormFrontendController.php b/Classes/XClass/Controller/FormFrontendController.php
index bc62fb04..64c13a8e 100644
--- a/Classes/XClass/Controller/FormFrontendController.php
+++ b/Classes/XClass/Controller/FormFrontendController.php
@@ -18,39 +18,34 @@
use FriendsOfTYPO3\Headless\Utility\HeadlessMode;
use FriendsOfTYPO3\Headless\XClass\FormRuntime;
use Psr\Http\Message\ResponseInterface;
+use TYPO3\CMS\Core\Information\Typo3Version;
use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface as ExtbaseConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Error\Error;
-use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
+use TYPO3\CMS\Extbase\Mvc\ExtbaseRequestParameters;
use TYPO3\CMS\Form\Domain\Factory\ArrayFormFactory;
use TYPO3\CMS\Form\Domain\Model\FormDefinition;
use function array_merge;
use function array_pop;
use function base64_encode;
+use function class_exists;
use function count;
use function in_array;
+use function is_array;
use function json_decode;
use function serialize;
use function str_replace;
/**
- * The frontend controller
+ * Overridden form implementation with headless flavor
*
- * Scope: frontend
* @internal
* @codeCoverageIgnore
*/
class FormFrontendController extends \TYPO3\CMS\Form\Controller\FormFrontendController
{
- private Translator $jsonFormTranslator;
-
- public function __construct()
- {
- $this->hashService = GeneralUtility::makeInstance(HashService::class);
- $this->jsonFormTranslator = GeneralUtility::makeInstance(Translator::class);
- }
-
/**
* Take the form which should be rendered from the plugin settings
* and overlay the formDefinition with additional data from
@@ -64,13 +59,28 @@ public function renderAction(): ResponseInterface
{
$headlessMode = GeneralUtility::makeInstance(HeadlessMode::class);
- if (!$headlessMode->withRequest($GLOBALS['TYPO3_REQUEST'])->isEnabled()) {
+ if (!$headlessMode->withRequest($this->request)->isEnabled()) {
return parent::renderAction();
}
$formDefinition = [];
if (!empty($this->settings['persistenceIdentifier'])) {
- $formDefinition = $this->formPersistenceManager->load($this->settings['persistenceIdentifier']);
+ $formSettings = [];
+ $typoScriptSettings = [];
+
+ if ((new Typo3Version())->getMajorVersion() >= 13) {
+ $typoScriptSettings = $this->configurationManager->getConfiguration(
+ ExtbaseConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
+ 'form'
+ );
+ $formSettings = $this->extFormConfigurationManager->getYamlConfiguration($typoScriptSettings, true);
+ }
+
+ $formDefinition = $this->formPersistenceManager->load(
+ $this->settings['persistenceIdentifier'],
+ $formSettings,
+ $typoScriptSettings
+ );
$formDefinition['persistenceIdentifier'] = $this->settings['persistenceIdentifier'];
$formDefinition = $this->overrideByFlexFormSettings($formDefinition);
$formDefinition = ArrayUtility::setValueByPath(
@@ -80,10 +90,7 @@ public function renderAction(): ResponseInterface
'.'
);
- $formId = ($this->configurationManager->getContentObject() !== null ?
- ($this->configurationManager->getContentObject()->data['uid'] ?? 0) : 0);
-
- $formDefinition['identifier'] .= '-' . $formId;
+ $formDefinition['identifier'] .= '-' . ($this->request->getAttribute('currentContentObject')?->data['uid'] ?? '');
}
$i18n = [];
@@ -128,14 +135,21 @@ public function renderAction(): ResponseInterface
$honeyPot = array_pop($elements);
}
- $stateHash = $this->hashService->appendHmac(base64_encode(serialize($formState)));
+ $stateHash = $this->getHashService()->appendHmac(
+ base64_encode(serialize($formState)),
+ class_exists(\TYPO3\CMS\Form\Security\HashScope::class) ? \TYPO3\CMS\Form\Security\HashScope::FormState->prefix() : ''
+ );
$currentPageIndex = $formRuntime->getCurrentPage() ? $formRuntime->getCurrentPage()->getIndex() : 0;
$currentPageId = $currentPageIndex + 1;
$formFields = $formDefinition['renderables'][$currentPageIndex]['renderables'] ?? [];
// provides support for custom options providers (dynamic selects/radio/checkboxes)
- $formFieldsNames = $this->generateFieldNamesAndReplaceCustomOptions($formFields, $formDefinition['identifier'], $formRuntime);
+ $formFieldsNames = $this->generateFieldNamesAndReplaceCustomOptions(
+ $formFields,
+ $formDefinition['identifier'],
+ $formRuntime
+ );
if ($honeyPot) {
$formFields[] = [
@@ -188,7 +202,7 @@ public function renderAction(): ResponseInterface
$formDefinition['renderables'][$currentPageIndex]['renderables'] = $formFields;
$formDefinition['i18n'] = count($i18n) ? $i18n : null;
- $formDefinition = $this->jsonFormTranslator->translate(
+ $formDefinition = $this->getFormTranslator()->translate(
$formDefinition,
$formRuntime->getFormDefinition()->getRenderingOptions(),
$formRuntime->getFormState() ? $formRuntime->getFormState()->getFormValues() : []
@@ -260,8 +274,11 @@ private function getNextPage(\TYPO3\CMS\Form\Domain\Runtime\FormRuntime $formRun
* @param array $formFields
* @return array
*/
- private function generateFieldNamesAndReplaceCustomOptions(array &$formFields, string $identifier, FormRuntime $formRuntime): array
- {
+ private function generateFieldNamesAndReplaceCustomOptions(
+ array &$formFields,
+ string $identifier,
+ FormRuntime $formRuntime
+ ): array {
$formFieldsNames = [];
foreach ($formFields as &$field) {
@@ -274,7 +291,13 @@ private function generateFieldNamesAndReplaceCustomOptions(array &$formFields, s
);
} else {
if (!empty($field['properties']['customOptions'])) {
- $customOptions = GeneralUtility::makeInstance($field['properties']['customOptions'], $field, $formFields, $identifier, $formRuntime);
+ $customOptions = GeneralUtility::makeInstance(
+ $field['properties']['customOptions'],
+ $field,
+ $formFields,
+ $identifier,
+ $formRuntime
+ );
if ($customOptions instanceof CustomOptionsInterface) {
$field['properties']['options'] = $customOptions->get();
@@ -295,4 +318,18 @@ private function generateFieldNamesAndReplaceCustomOptions(array &$formFields, s
return $formFieldsNames;
}
+
+ private function getHashService(): \TYPO3\CMS\Extbase\Security\Cryptography\HashService|\TYPO3\CMS\Core\Crypto\HashService
+ {
+ if ((new Typo3Version())->getMajorVersion() >= 13) {
+ return GeneralUtility::makeInstance(\TYPO3\CMS\Core\Crypto\HashService::class);
+ }
+
+ return GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Security\Cryptography\HashService::class);
+ }
+
+ private function getFormTranslator(): Translator
+ {
+ return GeneralUtility::makeInstance(Translator::class);
+ }
}
diff --git a/Classes/XClass/ResourceLocalDriver.php b/Classes/XClass/ResourceLocalDriver.php
index 285479af..a67207d5 100644
--- a/Classes/XClass/ResourceLocalDriver.php
+++ b/Classes/XClass/ResourceLocalDriver.php
@@ -16,6 +16,8 @@
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Http\ApplicationType;
use TYPO3\CMS\Core\Http\Uri;
+use TYPO3\CMS\Core\Information\Typo3Version;
+use TYPO3\CMS\Core\Resource\Capabilities;
use TYPO3\CMS\Core\Resource\Driver\LocalDriver;
use TYPO3\CMS\Core\Resource\ResourceStorage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -41,7 +43,7 @@ protected function determineBaseUrl(): void
return;
}
- if ($this->hasCapability(ResourceStorage::CAPABILITY_PUBLIC)) {
+ if ($this->hasCapability(((new Typo3Version())->getMajorVersion() < 13) ? ResourceStorage::CAPABILITY_PUBLIC : Capabilities::CAPABILITY_PUBLIC)) {
$urlUtility = GeneralUtility::makeInstance(UrlUtility::class)->withRequest($request);
$basePath = match (true) {
diff --git a/Configuration/SiteConfiguration/Overrides/site.php b/Configuration/SiteConfiguration/Overrides/site.php
index e3f14f98..03bfb80e 100644
--- a/Configuration/SiteConfiguration/Overrides/site.php
+++ b/Configuration/SiteConfiguration/Overrides/site.php
@@ -7,7 +7,6 @@
* LICENSE.md file that was distributed with this source code.
*/
-use FriendsOfTYPO3\Headless\Utility\Headless;
use FriendsOfTYPO3\Headless\Utility\HeadlessMode;
use TYPO3\CMS\Core\Configuration\Features;
use TYPO3\CMS\Core\Utility\GeneralUtility;
diff --git a/Tests/Unit/ContentObject/BooleanContentObjectTest.php b/Tests/Unit/ContentObject/BooleanContentObjectTest.php
index 76f1e289..e5d1c3b1 100644
--- a/Tests/Unit/ContentObject/BooleanContentObjectTest.php
+++ b/Tests/Unit/ContentObject/BooleanContentObjectTest.php
@@ -50,7 +50,7 @@ public function renderWithProviderTest($argument, bool $result)
self::assertEquals($result, $contentObject->render($argument));
}
- public function dataProvider(): array
+ public static function dataProvider(): array
{
return [
['test', false],
diff --git a/Tests/Unit/ContentObject/FloatContentObjectTest.php b/Tests/Unit/ContentObject/FloatContentObjectTest.php
index 9ffb9891..5ea09d01 100644
--- a/Tests/Unit/ContentObject/FloatContentObjectTest.php
+++ b/Tests/Unit/ContentObject/FloatContentObjectTest.php
@@ -47,7 +47,7 @@ public function renderWithProviderTest($argument, float $result)
self::assertEquals($result, $contentObject->render($argument));
}
- public function dataProvider(): array
+ public static function dataProvider(): array
{
return [
['test', 0.0],
diff --git a/Tests/Unit/ContentObject/IntegerContentObjectTest.php b/Tests/Unit/ContentObject/IntegerContentObjectTest.php
index 4abbbee8..662b6c33 100644
--- a/Tests/Unit/ContentObject/IntegerContentObjectTest.php
+++ b/Tests/Unit/ContentObject/IntegerContentObjectTest.php
@@ -50,7 +50,7 @@ public function renderWithProviderTest($argument, int $result)
self::assertEquals($result, $contentObject->render($argument));
}
- public function dataProvider(): array
+ public static function dataProvider(): array
{
return [
['test', 0],
diff --git a/Tests/Unit/ContentObject/JsonContentObjectTest.php b/Tests/Unit/ContentObject/JsonContentObjectTest.php
index 0d8addb9..c56a7aab 100644
--- a/Tests/Unit/ContentObject/JsonContentObjectTest.php
+++ b/Tests/Unit/ContentObject/JsonContentObjectTest.php
@@ -18,9 +18,13 @@
use FriendsOfTYPO3\Headless\ContentObject\JsonContentObject;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
+use Psr\EventDispatcher\EventDispatcherInterface;
use stdClass;
use Symfony\Component\DependencyInjection\Container;
+use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
+use TYPO3\CMS\Core\EventDispatcher\EventDispatcher;
use TYPO3\CMS\Core\Http\ServerRequest;
+use TYPO3\CMS\Core\LinkHandling\TypoLinkCodecService;
use TYPO3\CMS\Core\Service\MarkerBasedTemplateService;
use TYPO3\CMS\Core\TimeTracker\TimeTracker;
use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -86,6 +90,19 @@ protected function setUp(): void
'BOOL' => BooleanContentObject::class,
];
+ $container = new Container();
+
+ $eventDispatcher = $this->prophesize(EventDispatcher::class);
+ $eventDispatcher->dispatch(Argument::any())->willReturnArgument();
+
+ $container->set(MarkerBasedTemplateService::class, new MarkerBasedTemplateService($this->prophesize(FrontendInterface::class)->reveal(), $this->prophesize(FrontendInterface::class)->reveal()));
+ $container->set(TimeTracker::class, new TimeTracker(false));
+ $container->set(EventDispatcherInterface::class, $eventDispatcher->reveal());
+ $container->set(RecordsContentObject::class, new RecordsContentObject($container->get(TimeTracker::class)));
+ $container->set(ContentContentObject::class, new ContentContentObject($container->get(TimeTracker::class), $container->get(EventDispatcherInterface::class)));
+ GeneralUtility::setContainer($container);
+
+
$request = new ServerRequest();
$contentObjectRenderer = GeneralUtility::makeInstance(ContentObjectRenderer::class);
$contentObjectRenderer->setRequest($request);
@@ -101,7 +118,7 @@ protected function setUp(): void
return $obj;
});
- $container = new Container();
+ $container = GeneralUtility::getContainer();
$container->set(ContentObjectFactory::class, $factory->reveal());
GeneralUtility::setContainer($container);
@@ -113,9 +130,7 @@ protected function setUp(): void
}
GeneralUtility::makeInstance(JsonContentObject::class, $contentDataProcessor);
- GeneralUtility::makeInstance(ImageContentObject::class, $this->prophesize(MarkerBasedTemplateService::class)->reveal());
-
- GeneralUtility::makeInstance(TimeTracker::class, false);
+// GeneralUtility::makeInstance(ImageContentObject::class, $this->prophesize(MarkerBasedTemplateService::class)->reveal());
$tsfe = $this->prophesize(TypoScriptFrontendController::class);
$tsfe->uniqueHash()->willReturn(md5('123'));
@@ -144,7 +159,7 @@ public function renderWithProviderTest($argument, $result)
self::assertEquals($result, $this->contentObject->render($argument));
}
- public function dataProvider(): array
+ public static function dataProvider(): array
{
return [
[[], '[]'],
diff --git a/Tests/Unit/DataProcessing/DataProcessingTraitTest.php b/Tests/Unit/DataProcessing/DataProcessingTraitTest.php
index c41b0750..8019b4f2 100644
--- a/Tests/Unit/DataProcessing/DataProcessingTraitTest.php
+++ b/Tests/Unit/DataProcessing/DataProcessingTraitTest.php
@@ -96,7 +96,7 @@ public function isMenuProcessor()
));
}
- public function dataProvider(): array
+ public static function dataProvider(): array
{
return [
[
diff --git a/Tests/Unit/Event/Listener/AfterCacheableContentIsGeneratedListenerTest.php b/Tests/Unit/Event/Listener/AfterCacheableContentIsGeneratedListenerTest.php
index 55cb0f80..3c8579d4 100644
--- a/Tests/Unit/Event/Listener/AfterCacheableContentIsGeneratedListenerTest.php
+++ b/Tests/Unit/Event/Listener/AfterCacheableContentIsGeneratedListenerTest.php
@@ -84,7 +84,7 @@ public function testNotModifiedWhileValidJson(): void
$controller = $this->prophesize(TypoScriptFrontendController::class);
$controller->content = $content;
- $controller->generatePageTitle()->willReturn('Modified title via PageTitleManager');
+ $controller->generatePageTitle($request)->willReturn('Modified title via PageTitleManager');
$event = new AfterCacheableContentIsGeneratedEvent($request->reveal(), $controller->reveal(), 'abc', false);
@@ -106,7 +106,7 @@ public function testNotModifiedWhenUserIntContent(): void
$controller = $this->prophesize(TypoScriptFrontendController::class);
$controller->content = $content;
- $controller->generatePageTitle()->willReturn('Modified title via PageTitleManager');
+ $controller->generatePageTitle($request)->willReturn('Modified title via PageTitleManager');
$event = new AfterCacheableContentIsGeneratedEvent($request->reveal(), $controller->reveal(), 'abc', false);
@@ -131,7 +131,7 @@ public function testModifiedPageTitle(): void
$controller = $this->prophesize(TypoScriptFrontendController::class);
$controller->content = json_encode(['meta' => ['title' => 'test before event'], 'seo' => ['title' => 'test before event']]);
$controller->cObj = $this->prophesize(ContentObjectRenderer::class)->reveal();
- $controller->generatePageTitle()->willReturn('Modified title via PageTitleProviderManager');
+ $controller->generatePageTitle($request)->willReturn('Modified title via PageTitleProviderManager');
$event = new AfterCacheableContentIsGeneratedEvent($request->reveal(), $controller->reveal(), 'abc', false);
@@ -162,7 +162,7 @@ public function testHreflangs(): void
$controller = $this->prophesize(TypoScriptFrontendController::class);
$controller->content = json_encode(['meta' => ['title' => 'test before event'], 'seo' => ['title' => 'test before event']]);
$controller->cObj = $this->prophesize(ContentObjectRenderer::class)->reveal();
- $controller->generatePageTitle()->willReturn('Modified title via PageTitleProviderManager');
+ $controller->generatePageTitle($request)->willReturn('Modified title via PageTitleProviderManager');
$registry = GeneralUtility::makeInstance(MetaTagManagerRegistry::class);
$registry->registerManager('html5', Html5MetaTagManager::class);
diff --git a/Tests/Unit/Event/Listener/AfterLinkIsGeneratedListenerTest.php b/Tests/Unit/Event/Listener/AfterLinkIsGeneratedListenerTest.php
index f5397f48..318741da 100644
--- a/Tests/Unit/Event/Listener/AfterLinkIsGeneratedListenerTest.php
+++ b/Tests/Unit/Event/Listener/AfterLinkIsGeneratedListenerTest.php
@@ -13,6 +13,7 @@
use FriendsOfTYPO3\Headless\Utility\UrlUtility;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
+use Psr\EventDispatcher\EventDispatcherInterface;
use TYPO3\CMS\Core\ExpressionLanguage\Resolver;
use TYPO3\CMS\Core\Http\ServerRequest;
use TYPO3\CMS\Core\LinkHandling\LinkService;
@@ -39,7 +40,7 @@ public function test__construct()
$this->prophesize(Logger::class)->reveal(),
new UrlUtility(null, $resolver->reveal(), $siteFinder->reveal()),
$this->prophesize(LinkService::class)->reveal(),
- new TypoLinkCodecService(),
+ new TypoLinkCodecService($this->prophesize(EventDispatcherInterface::class)->reveal()),
$this->prophesize(SiteFinder::class)->reveal()
);
@@ -56,7 +57,7 @@ public function test__invokeNotModifingAnything()
$this->prophesize(Logger::class)->reveal(),
new UrlUtility(null, $resolver->reveal(), $siteFinder->reveal()),
$this->prophesize(LinkService::class)->reveal(),
- new TypoLinkCodecService(),
+ new TypoLinkCodecService($this->prophesize(EventDispatcherInterface::class)->reveal()),
$this->prophesize(SiteFinder::class)->reveal()
);
@@ -109,7 +110,7 @@ public function test__invokeModifingFromPageUid()
$this->prophesize(Logger::class)->reveal(),
$urlUtility->reveal(),
$this->prophesize(LinkService::class)->reveal(),
- new TypoLinkCodecService(),
+ new TypoLinkCodecService($this->prophesize(EventDispatcherInterface::class)->reveal()),
$this->prophesize(SiteFinder::class)->reveal()
);
@@ -146,7 +147,7 @@ public function test__invokeModifingExternalSite()
$this->prophesize(Logger::class)->reveal(),
$urlUtility->reveal(),
$linkService->reveal(),
- new TypoLinkCodecService(),
+ new TypoLinkCodecService($this->prophesize(EventDispatcherInterface::class)->reveal()),
$this->prophesize(SiteFinder::class)->reveal()
);
$linkResult = new LinkResult('page', '/');
@@ -186,11 +187,14 @@ public function test__SitemapLink()
$urlUtility->withRequest($request)->willReturn($urlUtility->reveal());
+ $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
+ $eventDispatcher->dispatch(Argument::any())->willReturnArgument();
+
$listener = new AfterLinkIsGeneratedListener(
$this->prophesize(Logger::class)->reveal(),
$urlUtility->reveal(),
$linkService->reveal(),
- new TypoLinkCodecService(),
+ new TypoLinkCodecService($eventDispatcher->reveal()),
$siteFinder->reveal()
);
diff --git a/Tests/Unit/Event/Listener/RedirectUrlAdditionalParamsListenerTest.php b/Tests/Unit/Event/Listener/RedirectUrlAdditionalParamsListenerTest.php
index 92df106e..d3fe7e6a 100644
--- a/Tests/Unit/Event/Listener/RedirectUrlAdditionalParamsListenerTest.php
+++ b/Tests/Unit/Event/Listener/RedirectUrlAdditionalParamsListenerTest.php
@@ -19,6 +19,7 @@
use InvalidArgumentException;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
+use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Http\Message\UriInterface;
use TYPO3\CMS\Core\ExpressionLanguage\Resolver;
use TYPO3\CMS\Core\Http\ServerRequest;
@@ -40,8 +41,11 @@ class RedirectUrlAdditionalParamsListenerTest extends UnitTestCase
*/
public function invokeTest()
{
+ $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
+ $eventDispatcher->dispatch(Argument::any())->willReturnArgument();
+
$listener = new RedirectUrlAdditionalParamsListener(
- new TypoLinkCodecService(),
+ new TypoLinkCodecService($eventDispatcher->reveal()),
new LinkService(),
$this->getUrlUtility()
);
@@ -119,7 +123,7 @@ public function invokeTest()
$mockListener->method('getPageRouterForSite')
->willReturn($pageRouter->reveal());
$mockListener->__construct(
- new TypoLinkCodecService(),
+ new TypoLinkCodecService($eventDispatcher->reveal()),
new LinkService(),
$this->getUrlUtility()
);
@@ -133,6 +137,9 @@ public function invokeTest()
*/
public function invokeWithLanguageTest()
{
+ $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
+ $eventDispatcher->dispatch(Argument::any())->willReturnArgument();
+
$targetUrl = 'https://test.domain2.tld/123';
$additionalParams = 'tx_test[action]=test&tx_test[controller]=Test&tx_test[test]=123';
$expectedUri = new Uri($targetUrl . '&' . $additionalParams);
@@ -180,7 +187,7 @@ public function invokeWithLanguageTest()
->willReturn($pageRouter->reveal());
$mockListener->__construct(
- new TypoLinkCodecService(),
+ new TypoLinkCodecService($eventDispatcher->reveal()),
new LinkService(),
$this->getUrlUtility($site)
);
diff --git a/Tests/Unit/Hooks/HeadlessUserIntTest.php b/Tests/Unit/Hooks/HeadlessUserIntTest.php
index 5b121945..dbc9d824 100644
--- a/Tests/Unit/Hooks/HeadlessUserIntTest.php
+++ b/Tests/Unit/Hooks/HeadlessUserIntTest.php
@@ -31,15 +31,7 @@ public function processingOnPlainTextWithNewline()
$testProcessed = 'PlainText' . PHP_EOL . 'NextLine';
$testContent = 'HEADLESS_INT_START<<' . $testProcessed . '>>HEADLESS_INT_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();
@@ -57,15 +49,7 @@ public function processingOnQuotedText()
$testProcessed = '"PlainText' . PHP_EOL . 'NextLine"';
$testContent = 'HEADLESS_INT_START<<' . $testProcessed . '>>HEADLESS_INT_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();
@@ -84,14 +68,8 @@ public function processingOnQuotedContent()
$testContent = '"HEADLESS_INT_START<<' . $testProcessed . '>>HEADLESS_INT_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();
@@ -113,15 +91,7 @@ public function processingOnQuotedJsonContent()
);
$testContent = '"HEADLESS_INT_START<<' . $testProcessed . '>>HEADLESS_INT_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();
@@ -141,15 +111,7 @@ public function processingEmptyPluginResponse()
);
$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();
@@ -163,15 +125,7 @@ public function processingEmptyPluginResponse()
);
$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();
@@ -217,12 +171,7 @@ public function processingOnNestedJsonContent()
$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();
@@ -276,15 +225,8 @@ public function processingOnMultipleUserIntOnPageJsonContent()
$testContent = '["HEADLESS_INT_START<<' . $testProcessed . '>>HEADLESS_INT_END","HEADLESS_INT_START<<' . $testProcessed2 . '>>HEADLESS_INT_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();
diff --git a/Tests/Unit/Json/JsonDecoderTest.php b/Tests/Unit/Json/JsonDecoderTest.php
index 090adce2..3203bb98 100644
--- a/Tests/Unit/Json/JsonDecoderTest.php
+++ b/Tests/Unit/Json/JsonDecoderTest.php
@@ -71,7 +71,7 @@ public function testDecoding(): void
self::assertEquals(json_decode($encoded), $jsonDecoder->decode(['teststring']));
}
- public function possibleJsonProvider(): array
+ public static function possibleJsonProvider(): array
{
return [
[' "12"', false],
diff --git a/Tests/Unit/Json/JsonEncoderTest.php b/Tests/Unit/Json/JsonEncoderTest.php
index e911970c..3515f917 100644
--- a/Tests/Unit/Json/JsonEncoderTest.php
+++ b/Tests/Unit/Json/JsonEncoderTest.php
@@ -50,7 +50,7 @@ public function testPrettyEncoding(): void
self::assertSame(json_encode($encodeValue, JSON_PRETTY_PRINT), $encoder->encode($encodeValue));
}
- public function jsonProvider(): array
+ public static function jsonProvider(): array
{
return [
[[], '[]'],
diff --git a/Tests/Unit/Middleware/ShortcutAndMountPointRedirectTest.php b/Tests/Unit/Middleware/ShortcutAndMountPointRedirectTest.php
index 687cb7d1..bce4181a 100644
--- a/Tests/Unit/Middleware/ShortcutAndMountPointRedirectTest.php
+++ b/Tests/Unit/Middleware/ShortcutAndMountPointRedirectTest.php
@@ -14,16 +14,31 @@
use FriendsOfTYPO3\Headless\Middleware\ShortcutAndMountPointRedirect;
use FriendsOfTYPO3\Headless\Utility\Headless;
use FriendsOfTYPO3\Headless\Utility\HeadlessMode;
+use FriendsOfTYPO3\Headless\Utility\UrlUtility;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
+use Psr\EventDispatcher\EventDispatcherInterface;
+use Psr\Log\LoggerInterface;
+use Symfony\Component\DependencyInjection\Container;
+use TYPO3\CMS\Core\Cache\CacheManager;
+use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
+use TYPO3\CMS\Core\Context\Context;
+use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Domain\Repository\PageRepository;
+use TYPO3\CMS\Core\ExpressionLanguage\Resolver;
use TYPO3\CMS\Core\Http\HtmlResponse;
use TYPO3\CMS\Core\Http\NormalizedParams;
use TYPO3\CMS\Core\Http\RedirectResponse;
+use TYPO3\CMS\Core\Http\Response;
use TYPO3\CMS\Core\Http\ServerRequest;
use TYPO3\CMS\Core\Http\Uri;
+use TYPO3\CMS\Core\Information\Typo3Version;
+use TYPO3\CMS\Core\Page\PageLayoutResolver;
+use TYPO3\CMS\Core\Routing\PageArguments;
use TYPO3\CMS\Core\Site\Entity\Site;
-use TYPO3\CMS\Core\TypoScript\TemplateService;
+use TYPO3\CMS\Core\Site\SiteFinder;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\RootlineUtility;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
use TYPO3\CMS\Frontend\Http\RequestHandler;
use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
@@ -32,11 +47,21 @@ class ShortcutAndMountPointRedirectTest extends UnitTestCase
{
use ProphecyTrait;
+ protected bool $resetSingletonInstances = true;
/**
- * @test
*/
public function processTest()
{
+ $request = new ServerRequest();
+
+ $urlUtility = new UrlUtility(null, $this->createMock(Resolver::class), $this->createMock(SiteFinder::class), null);
+ $urlUtility->withRequest($request);
+
+ $container = new Container();
+ $container->set(UrlUtility::class, $urlUtility);
+
+ GeneralUtility::setContainer($container);
+
$genericHtml = 'test';
$linkRedirect = 'https://test.domain2.tld';
$genericResponse = new HtmlResponse($genericHtml);
@@ -76,7 +101,7 @@ public function processTest()
['mode' => HeadlessMode::FULL]
)));
$shortcutJsonDecoded = [
- 'redirectUrl' => '/shortcut-target',
+ 'redirectUrl' => 'https://test.domain.tld/shortcut-target',
'statusCode' => 307,
];
@@ -159,13 +184,12 @@ public function processTest()
self::assertEquals($genericHtml, $normalResponse->getBody()->__toString());
}
- public function redirectProvider(): array
+ public static function redirectProvider(): array
{
$domain = 'https://test.redirect.domain.tld';
return [
['user@tes@t', $domain . 'user@tes@t'],
['user@test.com', 'mailto:user@test.com'],
- ['/false/url:1', '/false/url:1'],
['/relative-url', '/relative-url'],
];
}
@@ -174,7 +198,6 @@ public function redirectProvider(): array
* @param $url
* @param $expectedValue
*
- * @test
* @dataProvider redirectProvider
*/
public function linkRedirectTest($url, $expectedValue): void
@@ -225,6 +248,8 @@ protected function getTestRequest(
$request = new ServerRequest();
$request = $request->withUri(new Uri('/'));
+ $request = $request->withAttribute('routing', new PageArguments(1, '0', []));
+
if ($withQueryParams !== []) {
$request = $request->withQueryParams($withQueryParams);
}
@@ -239,6 +264,47 @@ protected function getTestRequest(
$request = $request->withAttribute('frontend.controller', $withTsfe);
}
+ if ((new Typo3Version())->getMajorVersion() >= 13) {
+ $container = new Container();
+ $cacheRuntime = $this->prophesize(FrontendInterface::class);
+ $cacheRuntime->getIdentifier()->willReturn('runtime');
+
+ $cacheManager = (new CacheManager(true));
+ $cacheManager->registerCache($cacheRuntime->reveal());
+
+ $rootLine = $this->prophesize(RootlineUtility::class);
+ $rootLine->get()->willReturn([['id' =>1]]);
+ $container->set(CacheManager::class, $cacheManager);
+ $container->set(RootlineUtility::class, $rootLine->reveal());
+// $container->set(ConnectionPool::class, $this->prophesize(ConnectionPool::class)->reveal());
+
+ $pageRepository = $this->prophesize(PageRepository::class);
+ $pageRepository->getPage(Argument::type('integer'), Argument::any())->willReturn(['id' => 1, 'doktype'=> 1]);
+
+ $container->set(PageRepository::class, $pageRepository->reveal());
+
+ GeneralUtility::setContainer($container);
+
+ $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
+ $eventDispatcher->dispatch(Argument::any())->willReturnArgument();
+
+
+ $errorController = $this->prophesize(\TYPO3\CMS\Frontend\Controller\ErrorController::class);
+ $errorController->pageNotFoundAction(Argument::any(), Argument::any(), Argument::any())->willReturn(new Response());
+
+ $pageInfoFactory = new \TYPO3\CMS\Frontend\Page\PageInformationFactory(
+ $this->prophesize(Context::class)->reveal(),
+ $eventDispatcher->reveal(),
+ $this->prophesize(LoggerInterface::class)->reveal(),
+ $this->prophesize(\TYPO3\CMS\Core\Domain\Access\RecordAccessVoter::class)->reveal(),
+ $errorController->reveal(),
+ new \TYPO3\CMS\Core\TypoScript\IncludeTree\SysTemplateRepository($eventDispatcher->reveal(), $this->prophesize(ConnectionPool::class)->reveal(), $this->prophesize(Context::class)->reveal()),
+ $this->prophesize(PageLayoutResolver::class)->reveal()
+ );
+
+ $request = $request->withAttribute('frontend.page.information', $pageInfoFactory->create($request));
+ }
+
$request = $request->withAttribute('headless', new Headless());
if ($withEnabledHeadless) {
@@ -254,11 +320,13 @@ protected function getTsfeProphecy(string $staticTemplate = '1', array $pageData
$setup = [];
$setup['plugin.']['tx_headless.']['staticTemplate'] = $staticTemplate;
- $tmpl = $this->prophesize(TemplateService::class);
- $tmpl->setup = $setup;
-
$tsfe = $this->prophesize(TypoScriptFrontendController::class);
- $tsfe->tmpl = $tmpl->reveal();
+
+ if ((new Typo3Version())->getMajorVersion() < 13) {
+ $tmpl = $this->prophesize(\TYPO3\CMS\Core\TypoScript\TemplateService::class);
+ $tmpl->setup = $setup;
+ $tsfe->tmpl = $tmpl->reveal();
+ }
if ($pageData === []) {
$pageData = ['id' => 1, 'doktype' => PageRepository::DOKTYPE_LINK, 'url' => 'https://test.domain2.tld'];
diff --git a/Tests/Unit/Middleware/UserIntMiddlewareTest.php b/Tests/Unit/Middleware/UserIntMiddlewareTest.php
index 1f679d54..6ba384d8 100644
--- a/Tests/Unit/Middleware/UserIntMiddlewareTest.php
+++ b/Tests/Unit/Middleware/UserIntMiddlewareTest.php
@@ -113,7 +113,7 @@ public function processTest()
protected function getMockHandlerWithResponse($response)
{
- $handler = $this->createPartialMock(RequestHandler::class, ['handle']);
+ $handler = $this->createMock(RequestHandler::class, ['handle']);
$handler->method('handle')->willReturn($response);
return $handler;
}
diff --git a/composer.json b/composer.json
index 3eada16e..4a8d10bf 100644
--- a/composer.json
+++ b/composer.json
@@ -28,24 +28,24 @@
],
"require": {
"ext-json": "*",
- "typo3/cms-core": "^12.4",
- "typo3/cms-install": "^12.4"
+ "typo3/cms-core": "^12.4 || ^13.3",
+ "typo3/cms-install": "^12.4 || ^13.3"
},
"require-dev": {
- "ergebnis/composer-normalize": "^2.15.0",
- "friendsofphp/php-cs-fixer": "^3.1",
+ "ergebnis/composer-normalize": "^2.43",
+ "friendsofphp/php-cs-fixer": "^v3",
"helmich/typo3-typoscript-lint": "^v3",
- "justinrainbow/json-schema": "^5.2",
- "php-coveralls/php-coveralls": "^2.5.2",
- "phpspec/prophecy-phpunit": "^2.0",
+ "justinrainbow/json-schema": "^5",
+ "php-coveralls/php-coveralls": "^2",
+ "phpspec/prophecy-phpunit": "^2",
"phpstan/extension-installer": "^1.1",
- "phpstan/phpstan": "^1.9",
- "phpunit/phpcov": "^8.2",
+ "phpstan/phpstan": "^1.12",
+ "phpunit/phpcov": "^8 || ^9 || ^10",
"saschaegerer/phpstan-typo3": "^1.1",
- "seld/jsonlint": "^1.8",
- "symfony/yaml": "^6.1",
- "typo3/cms-form": "^12.4",
- "typo3/testing-framework": "^7.0",
+ "seld/jsonlint": "^1.11",
+ "symfony/yaml": "^6.1 || ^7.1",
+ "typo3/cms-form": "^12.4 || ^13.3",
+ "typo3/testing-framework": "^8.0",
"typo3/coding-standards": "^0.8"
},
"conflict": {