diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 560f064..a8e46c6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -13,15 +13,13 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- php: [ '7.4', '7.3', '7.2' ]
- TYPO3: [ '10' ]
+ php: [ '7.4', '8.0', '8.1' ]
+ TYPO3: [ '11' ]
include:
- - TYPO3: '11'
+ - TYPO3: '12'
php: '8.1'
- - TYPO3: '11'
- php: '8.0'
- - TYPO3: '11'
- php: '7.4'
+ - TYPO3: '13'
+ php: '8.3'
steps:
- name: Checkout
uses: actions/checkout@v2
diff --git a/Build/phpstan10.neon b/Build/phpstan10.neon
deleted file mode 100644
index 8bcb0ab..0000000
--- a/Build/phpstan10.neon
+++ /dev/null
@@ -1,14 +0,0 @@
-parameters:
- level: 5
-
- paths:
- - %currentWorkingDirectory%/Classes
- - %currentWorkingDirectory%/Tests
-
- ignoreErrors:
- -
- message: '#Constant ORIGINAL_ROOT not found.#'
- path: %currentWorkingDirectory%/Tests
- -
- message: '#Call to an undefined method Prophecy\\Prophecy\\ObjectProphecy::.*#'
- path: %currentWorkingDirectory%/Tests
diff --git a/Build/phpstan11.neon b/Build/phpstan11.neon
index a9bf0e4..8bf0294 100644
--- a/Build/phpstan11.neon
+++ b/Build/phpstan11.neon
@@ -4,14 +4,15 @@ parameters:
paths:
- %currentWorkingDirectory%/Classes
- %currentWorkingDirectory%/Tests
-
+ excludePaths:
+ - %currentWorkingDirectory%/Tests/Unit/Domain/Repository/MenuRepositoryTest.php
ignoreErrors:
-
- message: '#.*TYPO3\\CMS\\Frontend\\Page\\PageRepository.*#'
- path: %currentWorkingDirectory%/Classes/Domain/Repository/MenuRepository.php
+ message: '#Cannot call method getLanguageCode\(\) on string.#'
+ path: %currentWorkingDirectory%/Classes/Compiler/LanguageMenuCompiler.php
-
- message: '#Constant ORIGINAL_ROOT not found.#'
- path: %currentWorkingDirectory%/Tests
+ message: '#Class TYPO3\\CMS\\Frontend\\Cache\\CacheLifetimeCalculator not found.#'
+ path: %currentWorkingDirectory%/Classes/CacheHelper.php
-
- message: '#Call to an undefined method Prophecy\\Prophecy\\ObjectProphecy::.*#'
- path: %currentWorkingDirectory%/Tests
+ message: '#.*unknown class TYPO3\\CMS\\Core\\TypoScript\\FrontendTypoScript.#'
+ path: %currentWorkingDirectory%/Classes/CacheHelper.php
diff --git a/Build/phpstan12.neon b/Build/phpstan12.neon
new file mode 100644
index 0000000..e8f1027
--- /dev/null
+++ b/Build/phpstan12.neon
@@ -0,0 +1,18 @@
+parameters:
+ level: 5
+
+ paths:
+ - %currentWorkingDirectory%/Classes
+ - %currentWorkingDirectory%/Tests
+ excludePaths:
+ - %currentWorkingDirectory%/Tests/Unit/Domain/Repository/MenuRepositoryTest.php
+ ignoreErrors:
+ -
+ message: '#Call to an undefined static method TYPO3\\CMS\\Frontend\\ContentObject\\AbstractContentObject::__construct\(\).#'
+ path: %currentWorkingDirectory%/Classes/ContentObject/*
+ -
+ message: '#Property TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController::\$id \(int\) does not accept string.#'
+ path: %currentWorkingDirectory%/Tests/Functional/Compiler/LanguageMenuCompilerTest.php
+ -
+ message: '#Call to an undefined method TYPO3\\CMS\\Core\\TypoScript\\FrontendTypoScript::getConfigArray\(\).#'
+ path: %currentWorkingDirectory%/Classes/CacheHelper.php
diff --git a/Build/phpstan13.neon b/Build/phpstan13.neon
new file mode 100644
index 0000000..e396ce1
--- /dev/null
+++ b/Build/phpstan13.neon
@@ -0,0 +1,27 @@
+parameters:
+ level: 5
+
+ paths:
+ - %currentWorkingDirectory%/Classes
+ - %currentWorkingDirectory%/Tests
+ excludePaths:
+ - %currentWorkingDirectory%/Tests/Unit/Domain/Repository/MenuRepositoryTest.php
+ ignoreErrors:
+ -
+ message: '#Call to an undefined method TYPO3\\CMS\\Core\\Site\\Entity\\SiteLanguage::getTwoLetterIsoCode\(\).#'
+ path: %currentWorkingDirectory%/Classes/Compiler/LanguageMenuCompiler.php
+ -
+ message: '#Access to undefined constant TYPO3\\CMS\\Core\\Domain\\Repository\\PageRepository::DOKTYPE_RECYCLER.#'
+ path: %currentWorkingDirectory%/Classes/Domain/Repository/MenuRepository.php
+ -
+ message: '#Access to undefined constant TYPO3\\CMS\\Core\\Domain\\Repository\\PageRepository::DOKTYPE_RECYCLER.#'
+ path: %currentWorkingDirectory%/Tests/Unit/Domain/Repository/MenuRepositoryTest.php
+ -
+ message: '#.*get_cache_timeout\(\).*#'
+ path: %currentWorkingDirectory%/Classes/CacheHelper.php
+ -
+ message: '#Call to an undefined static method TYPO3\\CMS\\Frontend\\ContentObject\\AbstractContentObject::__construct\(\).#'
+ path: %currentWorkingDirectory%/Classes/ContentObject/*
+ -
+ message: '#Property TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController::\$id \(int\) does not accept string.#'
+ path: %currentWorkingDirectory%/Tests/Functional/Compiler/LanguageMenuCompilerTest.php
diff --git a/Build/phpunit/FunctionalTests.xml b/Build/phpunit/FunctionalTests.xml
index 17f81d2..ded3940 100644
--- a/Build/phpunit/FunctionalTests.xml
+++ b/Build/phpunit/FunctionalTests.xml
@@ -24,6 +24,5 @@
-
diff --git a/Build/phpunit/UnitTestsBootstrap.php b/Build/phpunit/UnitTestsBootstrap.php
index 9e9222f..a91159e 100644
--- a/Build/phpunit/UnitTestsBootstrap.php
+++ b/Build/phpunit/UnitTestsBootstrap.php
@@ -12,28 +12,9 @@
* The TYPO3 project - inspiring people to share!
*/
-use TYPO3\CMS\Core\Information\Typo3Version;
-
call_user_func(function () {
- if (!class_exists(\TYPO3\CMS\Frontend\Page\PageRepository::class)) {
- class_alias(\TYPO3\CMS\Core\Domain\Repository\PageRepository::class, \TYPO3\CMS\Frontend\Page\PageRepository::class);
- }
$testbase = new \TYPO3\TestingFramework\Core\Testbase();
- // These if's are for core testing (package typo3/cms) only. cms-composer-installer does
- // not create the autoload-include.php file that sets these env vars and sets composer
- // mode to true. testing-framework can not be used without composer anyway, so it is safe
- // to do this here. This way it does not matter if 'bin/phpunit' or 'vendor/phpunit/phpunit/phpunit'
- // is called to run the tests since the 'relative to entry script' path calculation within
- // SystemEnvironmentBuilder is not used. However, the binary must be called from the document
- // root since getWebRoot() uses 'getcwd()'.
- if (!getenv('TYPO3_PATH_ROOT')) {
- putenv('TYPO3_PATH_ROOT=' . rtrim($testbase->getWebRoot(), '/'));
- }
- if (!getenv('TYPO3_PATH_WEB')) {
- putenv('TYPO3_PATH_WEB=' . rtrim($testbase->getWebRoot(), '/'));
- }
-
$testbase->defineSitePath();
$requestType = \TYPO3\CMS\Core\Core\SystemEnvironmentBuilder::REQUESTTYPE_BE | \TYPO3\CMS\Core\Core\SystemEnvironmentBuilder::REQUESTTYPE_CLI;
@@ -57,17 +38,10 @@ class_alias(\TYPO3\CMS\Core\Domain\Repository\PageRepository::class, \TYPO3\CMS\
new \TYPO3\CMS\Core\Cache\Backend\NullBackend('production', [])
);
// Set all packages to active
- if (version_compare((new Typo3Version())->getVersion(), '11.3.0', '>')) {
- $packageManager = \TYPO3\CMS\Core\Core\Bootstrap::createPackageManager(
- \TYPO3\CMS\Core\Package\UnitTestPackageManager::class,
- \TYPO3\CMS\Core\Core\Bootstrap::createPackageCache($cache)
- );
- } else {
- $packageManager = \TYPO3\CMS\Core\Core\Bootstrap::createPackageManager(
- \TYPO3\CMS\Core\Package\UnitTestPackageManager::class,
- $cache
- );
- }
+ $packageManager = \TYPO3\CMS\Core\Core\Bootstrap::createPackageManager(
+ \TYPO3\CMS\Core\Package\UnitTestPackageManager::class,
+ \TYPO3\CMS\Core\Core\Bootstrap::createPackageCache($cache)
+ );
\TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance(\TYPO3\CMS\Core\Package\PackageManager::class, $packageManager);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::setPackageManager($packageManager);
diff --git a/Build/testing-docker/docker-compose.yml b/Build/testing-docker/docker-compose.yml
index f1b2d26..3cf5d8b 100644
--- a/Build/testing-docker/docker-compose.yml
+++ b/Build/testing-docker/docker-compose.yml
@@ -82,10 +82,15 @@ services:
set -x
fi
php -v | grep '^PHP';
- if [ ${TYPO3} -eq 10 ]; then
- composer install --no-progress --no-interaction;
+ if [ ${TYPO3} -eq 11 ]; then
+ composer require typo3/cms-install:^11.5 typo3/cms-fluid-styled-content:^11.5 --dev -W --no-progress --no-interaction
+ composer prepare-tests
+ elif [ ${TYPO3} -eq 12 ]; then
+ composer require typo3/cms-install:^12.4 typo3/cms-fluid-styled-content:^12.4 --dev -W --no-progress --no-interaction
+ composer prepare-tests
else
- composer remove typo3/cms* --dev --no-progress --no-interaction && composer require typo3/cms-install:^11.5 typo3/cms-fluid-styled-content:^11.5 --dev -W --no-progress --no-interaction
+ composer install --no-progress --no-interaction
+ composer prepare-tests
fi
"
@@ -122,7 +127,7 @@ services:
typo3DatabaseUsername: root
typo3DatabasePassword: funcp
typo3DatabaseHost: mariadb10
- working_dir: ${ROOT_DIR}/.Build
+ working_dir: ${ROOT_DIR}
command: >
/bin/sh -c "
if [ ${SCRIPT_VERBOSE} -eq 1 ]; then
@@ -136,13 +141,13 @@ services:
php -v | grep '^PHP';
if [ ${PHP_XDEBUG_ON} -eq 0 ]; then
export XDEBUG_MODE=\"off\"
- bin/phpunit -c Web/typo3conf/ext/menus/Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE};
+ .Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE};
else
DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'`
export XDEBUG_MODE=\"debug,develop\" \
XDEBUG_TRIGGER=\"foo\" \
XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\"
- bin/phpunit -c Web/typo3conf/ext/menus/Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE};
+ .Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE};
fi
"
lint:
@@ -188,7 +193,7 @@ services:
- ${HOST_HOME}:${HOST_HOME}
- /etc/passwd:/etc/passwd:ro
- /etc/group:/etc/group:ro
- working_dir: ${ROOT_DIR}/.Build
+ working_dir: ${ROOT_DIR}
command: >
/bin/sh -c "
if [ ${SCRIPT_VERBOSE} -eq 1 ]; then
@@ -197,12 +202,12 @@ services:
php -v | grep '^PHP';
if [ ${PHP_XDEBUG_ON} -eq 0 ]; then
XDEBUG_MODE=\"off\" \
- bin/phpunit -c Web/typo3conf/ext/menus/Build/phpunit/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE};
+ .Build/bin/phpunit -c Build/phpunit/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE};
else
DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'`
XDEBUG_MODE=\"debug,develop\" \
XDEBUG_TRIGGER=\"foo\" \
XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\" \
- bin/phpunit -c Web/typo3conf/ext/menus/Build/phpunit/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE};
+ .Build/bin/phpunit -c menus/Build/phpunit/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE};
fi
"
diff --git a/Classes/CacheHelper.php b/Classes/CacheHelper.php
index c9bb9bf..4fedd6e 100644
--- a/Classes/CacheHelper.php
+++ b/Classes/CacheHelper.php
@@ -11,13 +11,15 @@
* of the License, or any later version.
*/
-use TYPO3\CMS\Core\Cache\CacheManager;
+use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
use TYPO3\CMS\Core\Information\Typo3Version;
use TYPO3\CMS\Core\SingletonInterface;
+use TYPO3\CMS\Core\TypoScript\FrontendTypoScript;
use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Cache\CacheLifetimeCalculator;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
/**
@@ -28,23 +30,14 @@
*/
class CacheHelper implements SingletonInterface
{
- /**
- * @var FrontendInterface
- */
- protected $cache;
-
- protected $disableCaching = false;
+ protected FrontendInterface $cache;
+ protected bool $disableCaching = false;
+ protected Context $context;
- public function __construct(FrontendInterface $cache = null, Context $context = null)
+ public function __construct(FrontendInterface $cache, Context $context)
{
- if ((new Typo3Version())->getMajorVersion() < 10) {
- $this->cache = $cache ?? GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_hash');
- } else {
- $this->cache = $cache ?? GeneralUtility::makeInstance(CacheManager::class)->getCache('hash');
- }
- if ($context === null) {
- $context = GeneralUtility::makeInstance(Context::class);
- }
+ $this->context = $context;
+ $this->cache = $cache;
try {
$this->disableCaching = $context->getPropertyFromAspect('workspace', 'id', 0) > 0;
} catch (AspectNotFoundException $e) {
@@ -60,10 +53,6 @@ public function __construct(FrontendInterface $cache = null, Context $context =
/**
* Looks up the items inside the cache, if it exists, takes the cached entry, otherwise computes the data
* via the $loader().
- *
- * @param string $cacheIdentifier
- * @param callable $loader
- * @return array
*/
public function get(string $cacheIdentifier, callable $loader): array
{
@@ -81,7 +70,8 @@ public function get(string $cacheIdentifier, callable $loader): array
// Calculate tags + lifetime
$tags = $this->buildTagsAndAddThemToPageCache($pages);
- $maximumLifeTime = $this->getMaxLifetimeOfPages($pages, $this->getFrontendController()->get_cache_timeout());
+ $defaultMaxLifeTime = $this->getDefaultMaxLifeTime();
+ $maximumLifeTime = $this->getMaxLifetimeOfPages($pages, $defaultMaxLifeTime);
$this->cache->set($cacheIdentifier, $pages, $tags, $maximumLifeTime);
return $pages;
}
@@ -126,15 +116,58 @@ protected function getAllPageIdsFromItems(array $pages): array
return $pageIds;
}
+ protected function getDefaultMaxLifeTime(): int
+ {
+ if (GeneralUtility::makeInstance(Typo3Version::class)->getMajorVersion() < 13) {
+ $maxLifetime = (int)$this->getFrontendController()->get_cache_timeout();
+ } else {
+ $request = $this->getServerRequest();
+ $pageInformation = $request->getAttribute('frontend.page.information');
+ /** @var ?FrontendTypoScript $typoScript */
+ $typoScript = $request->getAttribute('frontend.typoscript');
+ if ($typoScript === null || $pageInformation === null) {
+ return 0;
+ }
+ $typoScriptConfigArray = $typoScript->getConfigArray();
+ $maxLifetime = GeneralUtility::makeInstance(CacheLifetimeCalculator::class)
+ ->calculateLifetimeForPage(
+ $pageInformation->getId(),
+ $pageInformation->getPageRecord(),
+ $typoScriptConfigArray,
+ 0,
+ $this->context
+ );
+ }
+ return $maxLifetime;
+ }
+
/**
* pages.cache_timeout is not used here, as this is supposed to be relevant for content of a page, not the
* metadata.
*/
- protected function getMaxLifetimeOfPages(array $pages, int $maxLifetime = null): ?int
+ protected function getMaxLifetimeOfPages(array $pages, int $maxLifetime): int
{
foreach ($pages as $page) {
if (!empty($page['endtime'])) {
- $maxLifetimeOfPage = $page['endtime'] - $GLOBALS['EXEC_TIME'];
+ $maxLifetimeOfPage = (int)$page['endtime'] - $GLOBALS['EXEC_TIME'];
+ if (GeneralUtility::makeInstance(Typo3Version::class)->getMajorVersion() === 13) {
+ $request = $this->getServerRequest();
+ /** @var ?FrontendTypoScript $typoScript */
+ $typoScript = $request->getAttribute('frontend.typoscript');
+ if ($typoScript === null) {
+ $typoScriptConfigArray = [];
+ } else {
+ $typoScriptConfigArray = $typoScript->getConfigArray();
+ }
+ $maxLifetimeOfPage = GeneralUtility::makeInstance(CacheLifetimeCalculator::class)
+ ->calculateLifetimeForPage(
+ $page['uid'],
+ $page,
+ $typoScriptConfigArray,
+ 0,
+ $this->context
+ );
+ }
if ($maxLifetimeOfPage < $maxLifetime) {
$maxLifetime = $maxLifetimeOfPage;
}
@@ -146,9 +179,11 @@ protected function getMaxLifetimeOfPages(array $pages, int $maxLifetime = null):
return $maxLifetime;
}
- /**
- * @return TypoScriptFrontendController
- */
+ protected function getServerRequest(): ServerRequestInterface
+ {
+ return $GLOBALS['TYPO3_REQUEST'];
+ }
+
protected function getFrontendController(): TypoScriptFrontendController
{
return $GLOBALS['TSFE'];
diff --git a/Classes/Compiler/AbstractMenuCompiler.php b/Classes/Compiler/AbstractMenuCompiler.php
index a55fa9b..850159c 100644
--- a/Classes/Compiler/AbstractMenuCompiler.php
+++ b/Classes/Compiler/AbstractMenuCompiler.php
@@ -17,6 +17,7 @@
use TYPO3\CMS\Core\Context\LanguageAspect;
use TYPO3\CMS\Core\Context\UserAspect;
use TYPO3\CMS\Core\Context\VisibilityAspect;
+use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Site\Entity\SiteInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
@@ -24,36 +25,21 @@
/**
* MenuCompiler sorts out all relevant parts in the constructor which most menu compilers need.
*/
-abstract class AbstractMenuCompiler
+abstract class AbstractMenuCompiler implements SingletonInterface
{
- /**
- * @var MenuRepository
- */
- protected $menuRepository;
-
- /**
- * @var CacheHelper
- */
- protected $cache;
+ protected MenuRepository $menuRepository;
+ protected CacheHelper $cache;
+ protected Context $context;
- /**
- * @var Context
- */
- protected $context;
-
- public function __construct(Context $context = null, CacheHelper $cache = null)
+ public function __construct(Context $context, CacheHelper $cache, MenuRepository $menuRepository)
{
- $this->context = $context ?? GeneralUtility::makeInstance(Context::class);
- $this->menuRepository = GeneralUtility::makeInstance(MenuRepository::class, $this->context);
- $this->cache = $cache ?? GeneralUtility::makeInstance(CacheHelper::class);
+ $this->context = $context;
+ $this->menuRepository = $menuRepository;
+ $this->cache = $cache;
}
/**
* Fetch the related pages and caches it via the cache helper.
- *
- * @param ContentObjectRenderer $contentObjectRenderer
- * @param array $configuration
- * @return array
*/
abstract public function compile(ContentObjectRenderer $contentObjectRenderer, array $configuration): array;
@@ -80,7 +66,7 @@ protected function generateCacheIdentifierForMenu(string $prefix, array $configu
$visibilityAspect = $this->context->getAspect('visibility');
$visibility = $visibilityAspect->includeHiddenPages() ? '-with-hidden' : '';
$root = $this->getCurrentSite()->getRootPageId();
- $identifier = $prefix . '-root-' . $root . '-language-' . $language . '-groups-' . implode('_', $groupIds) . '-' . $visibility . '-' . substr(md5(json_encode($configuration)), 0, 10);
+ $identifier = $prefix . '-root-' . $root . '-language-' . $language . '-groups-' . md5(implode('_', $groupIds)) . '-' . $visibility . '-' . substr(md5(json_encode($configuration)), 0, 10);
return $identifier;
}
@@ -91,12 +77,8 @@ protected function getCurrentSite(): ?SiteInterface
/**
* Function to parse typoscript config with stdWrap
- * @param string $content
- * @param string $configuration
- *
- * @return string
*/
- public function parseStdWrap($content, $configuration): string
+ public function parseStdWrap(string $content, array $configuration): string
{
$return = GeneralUtility::makeInstance(ContentObjectRenderer::class)->stdWrap($content, $configuration);
if ($return !== null) {
diff --git a/Classes/Compiler/LanguageMenuCompiler.php b/Classes/Compiler/LanguageMenuCompiler.php
index efbe5a7..27c1725 100644
--- a/Classes/Compiler/LanguageMenuCompiler.php
+++ b/Classes/Compiler/LanguageMenuCompiler.php
@@ -13,6 +13,8 @@
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Context\LanguageAspectFactory;
+use TYPO3\CMS\Core\Information\Typo3Version;
+use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
@@ -23,7 +25,7 @@ class LanguageMenuCompiler extends AbstractMenuCompiler
*/
public function compile(ContentObjectRenderer $contentObjectRenderer, array $configuration): array
{
- $cacheIdentifier = $this->generateCacheIdentifierForMenu('list', $configuration);
+ $cacheIdentifier = $this->generateCacheIdentifierForMenu('language', $configuration);
$excludedLanguages = $contentObjectRenderer->stdWrap($configuration['excludeLanguages'] ?? '', $configuration['excludeLanguages.'] ?? []);
$excludedLanguages = GeneralUtility::trimExplode(',', $excludedLanguages, true);
@@ -38,7 +40,7 @@ public function compile(ContentObjectRenderer $contentObjectRenderer, array $con
$context = clone GeneralUtility::makeInstance(Context::class);
$pages = [];
foreach ($site->getLanguages() as $language) {
- if (in_array($language->getTwoLetterIsoCode(), $excludedLanguages, true)) {
+ if (in_array($this->getLanguageCode($language), $excludedLanguages, true)) {
continue;
}
if (in_array((string)$language->getLanguageId(), $excludedLanguages, true)) {
@@ -62,4 +64,12 @@ public function compile(ContentObjectRenderer $contentObjectRenderer, array $con
return $pages;
});
}
+
+ protected function getLanguageCode(SiteLanguage $language): string
+ {
+ if (GeneralUtility::makeInstance(Typo3Version::class)->getMajorVersion() === 11) {
+ return $language->getTwoLetterIsoCode();
+ }
+ return $language->getLocale()->getLanguageCode();
+ }
}
diff --git a/Classes/Compiler/ListMenuCompiler.php b/Classes/Compiler/ListMenuCompiler.php
index 254f951..b4eabed 100644
--- a/Classes/Compiler/ListMenuCompiler.php
+++ b/Classes/Compiler/ListMenuCompiler.php
@@ -24,7 +24,7 @@ public function compile(ContentObjectRenderer $contentObjectRenderer, array $con
$cacheIdentifier = $this->generateCacheIdentifierForMenu('list', $configuration);
$pageIds = $contentObjectRenderer->stdWrap($configuration['pages'] ?? $this->getCurrentSite()->getRootPageId(), $configuration['pages.'] ?? []);
- $pageIds = GeneralUtility::intExplode(',', $pageIds);
+ $pageIds = GeneralUtility::intExplode(',', (string)$pageIds);
$cacheIdentifier .= '-' . substr(md5(json_encode([$pageIds])), 0, 10);
diff --git a/Classes/Compiler/TreeMenuCompiler.php b/Classes/Compiler/TreeMenuCompiler.php
index 2b70171..5e0117c 100644
--- a/Classes/Compiler/TreeMenuCompiler.php
+++ b/Classes/Compiler/TreeMenuCompiler.php
@@ -25,7 +25,7 @@ public function compile(ContentObjectRenderer $contentObjectRenderer, array $con
$includeStartPageIds = $contentObjectRenderer->stdWrap($configuration['includeRootPages'] ?? false, $configuration['includeRootPages.'] ?? []);
$startPageIds = $contentObjectRenderer->stdWrap($configuration['entryPoints'] ?? $this->getCurrentSite()->getRootPageId(), $configuration['entryPoints.'] ?? []);
- $startPageIds = GeneralUtility::intExplode(',', $startPageIds);
+ $startPageIds = GeneralUtility::intExplode(',', (string)$startPageIds);
$depth = (int)$contentObjectRenderer->stdWrap($configuration['depth'] ?? 1, $configuration['depth.'] ?? []);
$excludePages = $this->parseStdWrap($configuration['excludePages'] ?? '', $configuration['excludePages.'] ?? []);
$configuration['excludePages'] = $excludePages;
diff --git a/Classes/ContentObject/BreadcrumbsContentObject.php b/Classes/ContentObject/BreadcrumbsContentObject.php
index a514e84..5038c9c 100644
--- a/Classes/ContentObject/BreadcrumbsContentObject.php
+++ b/Classes/ContentObject/BreadcrumbsContentObject.php
@@ -13,6 +13,7 @@
use B13\Menus\Domain\Repository\MenuRepository;
use B13\Menus\PageStateMarker;
+use TYPO3\CMS\Core\Information\Typo3Version;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\AbstractContentObject;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
@@ -22,23 +23,19 @@
*/
class BreadcrumbsContentObject extends AbstractContentObject
{
- /**
- * @var MenuRepository
- */
- protected $menuRepository;
+ protected MenuRepository $menuRepository;
- /**
- * @param ContentObjectRenderer $cObj
- */
public function __construct(ContentObjectRenderer $cObj)
{
- $this->menuRepository = GeneralUtility::makeInstance(MenuRepository::class);
- parent::__construct($cObj);
+ if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() < 12) {
+ parent::__construct($cObj);
+ }
+ $this->menuRepository = (GeneralUtility::makeInstance(ContentObjectServiceContainer::class))->getMenuRepository();
}
/**
* @param array $conf
- * @return string|void
+ * @return string
*/
public function render($conf = [])
{
@@ -49,7 +46,7 @@ public function render($conf = [])
foreach ($pages as $page) {
PageStateMarker::markStates($page, $rootLevelCount--);
$cObjForItems->start($page, 'pages');
- $content .= $cObjForItems->cObjGetSingle($conf['renderObj'], $conf['renderObj.']);
+ $content .= $cObjForItems->cObjGetSingle($conf['renderObj'] ?? '', $conf['renderObj.'] ?? []);
}
return $this->cObj->stdWrap($content, $conf);
}
diff --git a/Classes/ContentObject/ContentObjectServiceContainer.php b/Classes/ContentObject/ContentObjectServiceContainer.php
new file mode 100644
index 0000000..5f595f8
--- /dev/null
+++ b/Classes/ContentObject/ContentObjectServiceContainer.php
@@ -0,0 +1,62 @@
+languageMenuCompiler = $languageMenuCompiler;
+ $this->menuRepository = $menuRepository;
+ $this->listMenuCompiler = $listMenuCompiler;
+ $this->treeMenuCompiler = $treeMenuCompiler;
+ }
+
+ public function getLanguageMenuCompiler(): LanguageMenuCompiler
+ {
+ return $this->languageMenuCompiler;
+ }
+
+ public function getMenuRepository(): MenuRepository
+ {
+ return $this->menuRepository;
+ }
+
+ public function getListMenuCompiler(): ListMenuCompiler
+ {
+ return $this->listMenuCompiler;
+ }
+
+ public function getTreeMenuCompiler(): TreeMenuCompiler
+ {
+ return $this->treeMenuCompiler;
+ }
+}
diff --git a/Classes/ContentObject/LanguageMenuContentObject.php b/Classes/ContentObject/LanguageMenuContentObject.php
index 24ed1a5..f4cd43d 100644
--- a/Classes/ContentObject/LanguageMenuContentObject.php
+++ b/Classes/ContentObject/LanguageMenuContentObject.php
@@ -13,6 +13,7 @@
use B13\Menus\Compiler\LanguageMenuCompiler;
use B13\Menus\PageStateMarker;
+use TYPO3\CMS\Core\Information\Typo3Version;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\AbstractContentObject;
@@ -23,13 +24,23 @@
*/
class LanguageMenuContentObject extends AbstractContentObject
{
+ protected LanguageMenuCompiler $languageMenuCompiler;
+
+ public function __construct(ContentObjectRenderer $cObj)
+ {
+ if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() < 12) {
+ parent::__construct($cObj);
+ }
+ $this->languageMenuCompiler = (GeneralUtility::makeInstance(ContentObjectServiceContainer::class))->getLanguageMenuCompiler();
+ }
+
/**
* @param array $conf
- * @return string|void
+ * @return string
*/
public function render($conf = [])
{
- $pages = GeneralUtility::makeInstance(LanguageMenuCompiler::class)->compile($this->cObj, $conf);
+ $pages = $this->languageMenuCompiler->compile($this->cObj, $conf);
$content = $this->renderItems($pages, $conf);
return $this->cObj->stdWrap($content, $conf);
}
@@ -47,7 +58,7 @@ protected function renderItems(array $pages, array $conf): string
$page['isActiveLanguage'] = false;
}
$cObjForItems->start($page, 'pages');
- $content .= $cObjForItems->cObjGetSingle($conf['renderObj'], $conf['renderObj.']);
+ $content .= $cObjForItems->cObjGetSingle($conf['renderObj'] ?? '', $conf['renderObj.'] ?? []);
}
return $content;
}
diff --git a/Classes/ContentObject/ListMenuContentObject.php b/Classes/ContentObject/ListMenuContentObject.php
index 44d732f..8d2433a 100644
--- a/Classes/ContentObject/ListMenuContentObject.php
+++ b/Classes/ContentObject/ListMenuContentObject.php
@@ -13,6 +13,7 @@
use B13\Menus\Compiler\ListMenuCompiler;
use B13\Menus\PageStateMarker;
+use TYPO3\CMS\Core\Information\Typo3Version;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\AbstractContentObject;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
@@ -22,13 +23,23 @@
*/
class ListMenuContentObject extends AbstractContentObject
{
+ protected ListMenuCompiler $listMenuCompiler;
+
+ public function __construct(ContentObjectRenderer $cObj)
+ {
+ if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() < 12) {
+ parent::__construct($cObj);
+ }
+ $this->listMenuCompiler = (GeneralUtility::makeInstance(ContentObjectServiceContainer::class))->getListMenuCompiler();
+ }
+
/**
* @param array $conf
- * @return string|void
+ * @return string
*/
public function render($conf = [])
{
- $pages = GeneralUtility::makeInstance(ListMenuCompiler::class)->compile($this->cObj, $conf);
+ $pages = $this->listMenuCompiler->compile($this->cObj, $conf);
$content = $this->renderItems($pages, $conf);
return $this->cObj->stdWrap($content, $conf);
}
@@ -40,7 +51,7 @@ protected function renderItems(array $pages, array $conf): string
foreach ($pages as $page) {
PageStateMarker::markStates($page);
$cObjForItems->start($page, 'pages');
- $content .= $cObjForItems->cObjGetSingle($conf['renderObj'], $conf['renderObj.']);
+ $content .= $cObjForItems->cObjGetSingle($conf['renderObj'] ?? '', $conf['renderObj.'] ?? []);
}
return $content;
}
diff --git a/Classes/ContentObject/TreeMenuContentObject.php b/Classes/ContentObject/TreeMenuContentObject.php
index ea1d1ca..0e96274 100644
--- a/Classes/ContentObject/TreeMenuContentObject.php
+++ b/Classes/ContentObject/TreeMenuContentObject.php
@@ -13,6 +13,7 @@
use B13\Menus\Compiler\TreeMenuCompiler;
use B13\Menus\PageStateMarker;
+use TYPO3\CMS\Core\Information\Typo3Version;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\AbstractContentObject;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
@@ -22,13 +23,23 @@
*/
class TreeMenuContentObject extends AbstractContentObject
{
+ protected TreeMenuCompiler $treeMenuCompiler;
+
+ public function __construct(ContentObjectRenderer $cObj)
+ {
+ if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() < 12) {
+ parent::__construct($cObj);
+ }
+ $this->treeMenuCompiler = (GeneralUtility::makeInstance(ContentObjectServiceContainer::class))->getTreeMenuCompiler();
+ }
+
/**
* @param array $conf
- * @return string|void
+ * @return string
*/
public function render($conf = [])
{
- $tree = GeneralUtility::makeInstance(TreeMenuCompiler::class)->compile($this->cObj, $conf);
+ $tree = $this->treeMenuCompiler->compile($this->cObj, $conf);
$content = $this->renderItems($tree, 0, $conf['renderObj.'] ?? []);
return $this->cObj->stdWrap($content, $conf);
}
@@ -47,7 +58,7 @@ protected function renderItems(array $pages, int $level, array $renderConfigurat
$page['subpageContent'] = $this->renderItems($page['subpages'], $level++, $renderConfiguration);
}
$cObjForItems->start($page, 'pages');
- $content .= $cObjForItems->cObjGetSingle($renderConfiguration['level' . $level], $renderConfiguration['level' . $level . '.']);
+ $content .= $cObjForItems->cObjGetSingle($renderConfiguration['level' . $level] ?? '', $renderConfiguration['level' . $level . '.'] ?? []);
}
return $content;
}
diff --git a/Classes/DataProcessing/AbstractMenu.php b/Classes/DataProcessing/AbstractMenu.php
index d995111..2d2e88c 100644
--- a/Classes/DataProcessing/AbstractMenu.php
+++ b/Classes/DataProcessing/AbstractMenu.php
@@ -21,28 +21,14 @@
*/
abstract class AbstractMenu implements DataProcessorInterface
{
+ protected ContentDataProcessor $contentDataProcessor;
- /**
- * @var ContentDataProcessor
- */
- protected $contentDataProcessor;
-
- /**
- * Constructor
- */
- public function __construct(ContentDataProcessor $contentDataProcessor = null)
+ public function __construct(ContentDataProcessor $contentDataProcessor)
{
- $this->contentDataProcessor = $contentDataProcessor ?? GeneralUtility::makeInstance(ContentDataProcessor::class);
+ $this->contentDataProcessor = $contentDataProcessor;
}
- /**
- * Process additional data processors
- *
- * @param array $page
- * @param array $processorConfiguration
- * @return array
- */
- protected function processAdditionalDataProcessors(&$page, $processorConfiguration)
+ protected function processAdditionalDataProcessors(array &$page, array $processorConfiguration): array
{
if (isset($page['subpages']) && is_array($page['subpages'])) {
foreach ($page['subpages'] as &$item) {
diff --git a/Classes/DataProcessing/BreadcrumbsMenu.php b/Classes/DataProcessing/BreadcrumbsMenu.php
index 6166d7a..ae5a85a 100644
--- a/Classes/DataProcessing/BreadcrumbsMenu.php
+++ b/Classes/DataProcessing/BreadcrumbsMenu.php
@@ -13,7 +13,6 @@
use B13\Menus\Domain\Repository\MenuRepository;
use B13\Menus\PageStateMarker;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentDataProcessor;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
@@ -22,15 +21,12 @@
*/
class BreadcrumbsMenu extends AbstractMenu
{
- /**
- * @var MenuRepository
- */
- protected $menuRepository;
+ protected MenuRepository $menuRepository;
- public function __construct(ContentDataProcessor $contentDataProcessor = null, MenuRepository $menuRepository = null)
+ public function __construct(ContentDataProcessor $contentDataProcessor, MenuRepository $menuRepository)
{
parent::__construct($contentDataProcessor);
- $this->menuRepository = $menuRepository ?? GeneralUtility::makeInstance(MenuRepository::class);
+ $this->menuRepository = $menuRepository;
}
/**
diff --git a/Classes/DataProcessing/LanguageMenu.php b/Classes/DataProcessing/LanguageMenu.php
index 44d93cd..754643a 100644
--- a/Classes/DataProcessing/LanguageMenu.php
+++ b/Classes/DataProcessing/LanguageMenu.php
@@ -14,7 +14,7 @@
use B13\Menus\Compiler\LanguageMenuCompiler;
use B13\Menus\PageStateMarker;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\ContentObject\ContentDataProcessor;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
@@ -22,6 +22,14 @@
*/
class LanguageMenu extends AbstractMenu
{
+ protected $languageMenuCompliler;
+
+ public function __construct(ContentDataProcessor $contentDataProcessor, LanguageMenuCompiler $languageMenuCompiler)
+ {
+ $this->languageMenuCompliler = $languageMenuCompiler;
+ parent::__construct($contentDataProcessor);
+ }
+
/**
* @inheritDoc
*/
@@ -30,7 +38,7 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu
if (isset($processorConfiguration['if.']) && !$cObj->checkIf($processorConfiguration['if.'])) {
return $processedData;
}
- $pages = GeneralUtility::makeInstance(LanguageMenuCompiler::class)->compile($cObj, $processorConfiguration);
+ $pages = $this->languageMenuCompliler->compile($cObj, $processorConfiguration);
$currentLanguage = $this->getCurrentSiteLanguage();
foreach ($pages as &$page) {
PageStateMarker::markStates($page);
@@ -48,9 +56,6 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu
return $processedData;
}
- /**
- * @return SiteLanguage|null
- */
protected function getCurrentSiteLanguage(): ?SiteLanguage
{
return $GLOBALS['TYPO3_REQUEST']->getAttribute('language');
diff --git a/Classes/DataProcessing/ListMenu.php b/Classes/DataProcessing/ListMenu.php
index 8e7c32e..0535eac 100644
--- a/Classes/DataProcessing/ListMenu.php
+++ b/Classes/DataProcessing/ListMenu.php
@@ -13,7 +13,7 @@
use B13\Menus\Compiler\ListMenuCompiler;
use B13\Menus\PageStateMarker;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\ContentObject\ContentDataProcessor;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
@@ -21,6 +21,14 @@
*/
class ListMenu extends AbstractMenu
{
+ protected ListMenuCompiler $listMenuCompiler;
+
+ public function __construct(ContentDataProcessor $contentDataProcessor, ListMenuCompiler $listMenuCompiler)
+ {
+ $this->listMenuCompiler = $listMenuCompiler;
+ parent::__construct($contentDataProcessor);
+ }
+
/**
* @inheritDoc
*/
@@ -30,7 +38,7 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu
return $processedData;
}
- $pages = GeneralUtility::makeInstance(ListMenuCompiler::class)->compile($cObj, $processorConfiguration);
+ $pages = $this->listMenuCompiler->compile($cObj, $processorConfiguration);
foreach ($pages as &$page) {
PageStateMarker::markStates($page);
}
diff --git a/Classes/DataProcessing/TreeMenu.php b/Classes/DataProcessing/TreeMenu.php
index 9d7bfa3..1e2de85 100644
--- a/Classes/DataProcessing/TreeMenu.php
+++ b/Classes/DataProcessing/TreeMenu.php
@@ -13,7 +13,7 @@
use B13\Menus\Compiler\TreeMenuCompiler;
use B13\Menus\PageStateMarker;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\ContentObject\ContentDataProcessor;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
@@ -21,6 +21,13 @@
*/
class TreeMenu extends AbstractMenu
{
+ protected TreeMenuCompiler $treeMenuCompiler;
+
+ public function __construct(ContentDataProcessor $contentDataProcessor, TreeMenuCompiler $treeMenuCompiler)
+ {
+ $this->treeMenuCompiler = $treeMenuCompiler;
+ parent::__construct($contentDataProcessor);
+ }
/**
* @inheritDoc
@@ -30,7 +37,7 @@ public function process(ContentObjectRenderer $cObj, array $contentObjectConfigu
if (isset($processorConfiguration['if.']) && !$cObj->checkIf($processorConfiguration['if.'])) {
return $processedData;
}
- $pages = GeneralUtility::makeInstance(TreeMenuCompiler::class)->compile($cObj, $processorConfiguration);
+ $pages = $this->treeMenuCompiler->compile($cObj, $processorConfiguration);
foreach ($pages as &$page) {
PageStateMarker::markStatesRecursively($page, 1);
}
diff --git a/Classes/Domain/Repository/MenuRepository.php b/Classes/Domain/Repository/MenuRepository.php
index 042a6b8..b9579a3 100644
--- a/Classes/Domain/Repository/MenuRepository.php
+++ b/Classes/Domain/Repository/MenuRepository.php
@@ -11,10 +11,13 @@
* of the License, or any later version.
*/
+use B13\Menus\Event\PopulatePageInformationEvent;
+use Psr\EventDispatcher\EventDispatcherInterface;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Context\LanguageAspect;
+use TYPO3\CMS\Core\Domain\Repository\PageRepository;
+use TYPO3\CMS\Core\Information\Typo3Version;
use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Frontend\Page\PageRepository;
/**
* Responsible for interacting with the PageRepository class, in addition, should be responsible for overlays
@@ -22,27 +25,24 @@
*/
class MenuRepository
{
- /**
- * @var Context
- */
- protected $context;
-
- /**
- * @var PageRepository
- */
- protected $pageRepository;
+ protected Context $context;
+ protected PageRepository $pageRepository;
+ protected EventDispatcherInterface $eventDispatcher;
// Never show or query them.
protected $excludedDoktypes = [
PageRepository::DOKTYPE_BE_USER_SECTION,
- PageRepository::DOKTYPE_RECYCLER,
PageRepository::DOKTYPE_SYSFOLDER,
];
- public function __construct(Context $context = null, PageRepository $pageRepository = null)
+ public function __construct(Context $context, PageRepository $pageRepository, EventDispatcherInterface $eventDispatcher)
{
- $this->context = $context ?? GeneralUtility::makeInstance(Context::class);
- $this->pageRepository = $pageRepository ?? GeneralUtility::makeInstance(PageRepository::class, $this->context);
+ $this->context = $context;
+ $this->pageRepository = $pageRepository;
+ $this->eventDispatcher = $eventDispatcher;
+ if (GeneralUtility::makeInstance(Typo3Version::class)->getMajorVersion() < 13) {
+ $this->excludedDoktypes[] = PageRepository::DOKTYPE_RECYCLER;
+ }
}
public function getBreadcrumbsMenu(array $originalRootLine, array $configuration): array
@@ -108,37 +108,25 @@ public function getPageTree(int $startPageId, int $depth, array $configuration):
return $page;
}
- /**
- * @param array $configuration
- * @return array
- */
protected function getExcludeDoktypes(array $configuration): array
{
if (!empty($configuration['excludeDoktypes'])) {
- $excludedDoktypes = array_unique(array_merge($this->excludedDoktypes, GeneralUtility::intExplode(',', $configuration['excludeDoktypes'])));
+ $excludedDoktypes = array_unique(array_merge($this->excludedDoktypes, GeneralUtility::intExplode(',', (string)$configuration['excludeDoktypes'])));
} else {
$excludedDoktypes = $this->excludedDoktypes;
}
return $excludedDoktypes;
}
- /**
- * @param array $configuration
- * @return array
- */
protected function getExcludePages(array $configuration): ?array
{
$excludePages = null;
if (!empty($configuration['excludePages'])) {
- $excludePages = array_unique(GeneralUtility::intExplode(',', $configuration['excludePages']));
+ $excludePages = array_unique(GeneralUtility::intExplode(',', (string)$configuration['excludePages']));
}
return empty($excludePages) ? null : $excludePages;
}
- /**
- * @param array $configuration
- * @return bool
- */
protected function getIncludeNotInMenu(array $configuration): bool
{
return (int)($configuration['includeNotInMenu'] ?? 0) === 1;
@@ -149,7 +137,7 @@ public function getSubPagesOfPage(int $pageId, int $depth, array $configuration)
$whereClause = '';
if (!empty($configuration['excludePages'])) {
- $excludedPagesArray = GeneralUtility::intExplode(',', $configuration['excludePages']);
+ $excludedPagesArray = GeneralUtility::intExplode(',', (string)$configuration['excludePages']);
$whereClause .= ' AND uid NOT IN (' . implode(',', $excludedPagesArray) . ')';
}
$excludedDoktypes = $this->getExcludeDoktypes($configuration);
@@ -195,5 +183,9 @@ protected function populateAdditionalKeysForPage(array &$page): void
$page['isSpacer'] = true;
}
$page['nav_title'] = $page['nav_title'] ?: $page['title'];
+
+ $event = new PopulatePageInformationEvent($page);
+ $this->eventDispatcher->dispatch($event);
+ $page = $event->getPage();
}
}
diff --git a/Classes/Event/PopulatePageInformationEvent.php b/Classes/Event/PopulatePageInformationEvent.php
new file mode 100644
index 0000000..cb9c9e5
--- /dev/null
+++ b/Classes/Event/PopulatePageInformationEvent.php
@@ -0,0 +1,25 @@
+page = $page;
+ }
+
+ public function getPage(): array
+ {
+ return $this->page;
+ }
+
+ public function setPage(array $page): void
+ {
+ $this->page = $page;
+ }
+}
diff --git a/Classes/Hooks/DataHandlerHook.php b/Classes/Hooks/DataHandlerHook.php
index e5b8035..6e1e00f 100644
--- a/Classes/Hooks/DataHandlerHook.php
+++ b/Classes/Hooks/DataHandlerHook.php
@@ -14,7 +14,6 @@
use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\DataHandling\DataHandler;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* This hook is triggered before caches for a page get flushed.
@@ -23,6 +22,13 @@
*/
class DataHandlerHook
{
+ protected CacheManager $cacheManager;
+
+ public function __construct(CacheManager $cacheManager)
+ {
+ $this->cacheManager = $cacheManager;
+ }
+
public function clearMenuCaches(array $params, DataHandler $dataHandler): void
{
$pageId = (int)($params['uid_page'] ?? 0);
@@ -36,9 +42,6 @@ public function clearMenuCaches(array $params, DataHandler $dataHandler): void
if ($parentPageId > 0) {
$menuTags[] = 'menuId_' . $parentPageId;
}
-
- /** @var CacheManager $cacheManager */
- $cacheManager = GeneralUtility::makeInstance(CacheManager::class);
- $cacheManager->flushCachesByTags($menuTags);
+ $this->cacheManager->flushCachesByTags($menuTags);
}
}
diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml
new file mode 100644
index 0000000..cf0247c
--- /dev/null
+++ b/Configuration/Services.yaml
@@ -0,0 +1,41 @@
+services:
+ _defaults:
+ autowire: true
+ autoconfigure: true
+ public: false
+
+ B13\Menus\:
+ resource: '../Classes/*'
+
+ B13\Menus\DataProcessing\BreadcrumbsMenu:
+ public: true
+ B13\Menus\DataProcessing\LanguageMenu:
+ public: true
+ B13\Menus\DataProcessing\ListMenu:
+ public: true
+ B13\Menus\DataProcessing\TreeMenu:
+ public: true
+ B13\Menus\ContentObject\ContentObjectServiceContainer:
+ public: true
+ B13\Menus\CacheHelper:
+ arguments:
+ $cache: '@cache.hash'
+ B13\Menus\Hooks\DataHandlerHook:
+ public: true
+
+ B13\Menus\ContentObject\TreeMenuContentObject:
+ tags:
+ - name: frontend.contentobject
+ identifier: 'TREEMENU'
+ B13\Menus\ContentObject\ListMenuContentObject:
+ tags:
+ - name: frontend.contentobject
+ identifier: 'LISTMENU'
+ B13\Menus\ContentObject\LanguageMenuContentObject:
+ tags:
+ - name: frontend.contentobject
+ identifier: 'LANGUAGEMENU'
+ B13\Menus\ContentObject\BreadcrumbsContentObject:
+ tags:
+ - name: frontend.contentobject
+ identifier: 'BREADCRUMBS'
diff --git a/README.md b/README.md
index c003556..986f7d4 100644
--- a/README.md
+++ b/README.md
@@ -78,11 +78,11 @@ Pure TypoScript-based solution:
page.10.excludePages = 4,51
# 0: default, 1 to include nav_hide = 1 pages
page.10.includeNotInMenu = 0
- page.10.renderObj.level1 = TEXT
- page.10.renderObj.level1.typolink.parameter.data = field:uid
- page.10.renderObj.level1.typolink.ATagParams = class="active"
- page.10.renderObj.level1.typolink.ATagParams.if.isTrue = field:isInRootLine
- page.10.renderObj.level1.dataWrap =
|
+ page.10.renderObj.level0 = TEXT
+ page.10.renderObj.level0.typolink.parameter.data = field:uid
+ page.10.renderObj.level0.typolink.ATagParams = class="active"
+ page.10.renderObj.level0.typolink.ATagParams.if.isTrue.field = isInRootLine
+ page.10.renderObj.level0.dataWrap = |
Fluid-based solution:
@@ -125,9 +125,11 @@ Pure TypoScript solution:
# add all siteLanguages to menu even if page is not available in language (default 0)
page.10.addAllSiteLanguages = 1
page.10.wrap =
- page.10.renderObj = TEXT
page.10.renderObj.typolink.parameter.data = field:uid
- page.10.renderObj.data = field:language_title // field:language_two_letter_iso_code
+ page.10.renderObj.typolink.additionalParams.data = field:language|languageId
+ page.10.renderObj.typolink.additionalParams.intval = 1
+ page.10.renderObj.typolink.additionalParams.wrap = &L=|
+ page.10.renderObj.data = field:language|title // field:language|twoLetterIsoCode
page.10.renderObj.wrap = |
The stdWrap `data` is the information of the current page plus the information merged from the selected SiteLanguage.
@@ -146,7 +148,7 @@ Fluid-based solution:
Usage in Fluid:
-
+
{item.language.title}
@@ -164,6 +166,10 @@ Pure TypoScript-based solution:
page.10.pages = 13,14,15
# 0: default, 1 to include nav_hide = 1 pages
page.10.includeNotInMenu = 0
+ page.10.wrap =
+ page.10.renderObj = TEXT
+ page.10.renderObj.typolink.parameter.data = field:uid
+ page.10.renderObj.wrap = |
Fluid-based solution:
@@ -199,7 +205,7 @@ Fluid-based solution:
page.10 = FLUIDTEMPLATE
page.10.dataProcessing.10 = B13\Menus\DataProcessing\BreadcrumbsMenu
- page.10.dataProcessors.10.excludePages = 4,51
+ page.10.dataProcessing.10.excludePages = 4,51
# 0: default, 1 to include nav_hide = 1 pages
page.10.dataProcessing.10.includeNotInMenu = 0
page.10.dataProcessing.10.as = breadcrumbs
@@ -223,7 +229,7 @@ If you want to get a menu of the direct siblings of a page, no matter what page
as = listOfJobPages
}
-By using the `.data` property of the entryPointy attribute we can access each property of the currently build page. And so we can render the siblings of the page.
+By using the `.data` property of the `entryPoints` attribute we can access each property of the currently build page. And so we can render the siblings of the page.
## Technical Details
diff --git a/Tests/Functional/Compiler/LanguageMenuCompilerTest.php b/Tests/Functional/Compiler/LanguageMenuCompilerTest.php
index d90b738..8869ac4 100644
--- a/Tests/Functional/Compiler/LanguageMenuCompilerTest.php
+++ b/Tests/Functional/Compiler/LanguageMenuCompilerTest.php
@@ -1,5 +1,7 @@
'typo3conf/sites',
];
- protected $defaultPageDataSet = [
+ protected array $defaultPageDataSet = [
'defaultPage' => [
'uid' => 1,
'pid' => 0,
@@ -231,25 +239,43 @@ protected function compileMenu(array $pageDataset, array $configuration = []): a
foreach ($pageDataset as $page) {
$connection->insert('pages', $page);
}
- $controller = $this->getAccessibleMock(
- TypoScriptFrontendController::class,
- ['get_cache_timeout'],
- [],
- '',
- false
- );
+ $controller = $this->getMockBuilder($this->buildAccessibleProxy(TypoScriptFrontendController::class))
+ ->onlyMethods(['get_cache_timeout'])
+ ->disableOriginalConstructor()
+ ->getMock();
$GLOBALS['TSFE'] = $controller;
- $GLOBALS['TSFE']->id = '1';
+ if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() < 12) {
+ $GLOBALS['TSFE']->id = '1';
+ } else {
+ $GLOBALS['TSFE']->id = 1;
+ }
$contentObjectRenderer = new ContentObjectRenderer();
$siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
$site = $siteFinder->getSiteByIdentifier('main');
- $languageMenuCompiler = $this->getAccessibleMock(
- LanguageMenuCompiler::class,
- [
- 'generateCacheIdentifierForMenu',
- 'getCurrentSite',
- ]
- );
+ $context = $this->getMockBuilder(Context::class)
+ ->getMock();
+ $pageRepository = GeneralUtility::makeInstance(PageRepository::class);
+ $menuRepository = GeneralUtility::makeInstance(MenuRepository::class, $context, $pageRepository, $this->createMock(EventDispatcherInterface::class));
+ $cacheHelper = $this->getMockBuilder($this->buildAccessibleProxy(CacheHelper::class))
+ ->onlyMethods([])
+ ->disableOriginalConstructor()
+ ->getMock();
+ $cacheHelper->_set('disableCaching', true);
+ $languageMenuCompiler = $this->getMockBuilder(LanguageMenuCompiler::class)
+ ->onlyMethods(
+ [
+ 'generateCacheIdentifierForMenu',
+ 'getCurrentSite',
+ ]
+ )
+ ->setConstructorArgs(
+ [
+ $context,
+ $cacheHelper,
+ $menuRepository,
+ ]
+ )
+ ->getMock();
$languageMenuCompiler->expects(self::any())->method('generateCacheIdentifierForMenu')->willReturn('foo');
$languageMenuCompiler->expects(self::any())->method('getCurrentSite')->willReturn($site);
$menu = $languageMenuCompiler->compile($contentObjectRenderer, $configuration);
diff --git a/Tests/Functional/DataProcessing/BreadcrumbsMenuTest.php b/Tests/Functional/DataProcessing/BreadcrumbsMenuTest.php
index 1c635ff..f62373a 100644
--- a/Tests/Functional/DataProcessing/BreadcrumbsMenuTest.php
+++ b/Tests/Functional/DataProcessing/BreadcrumbsMenuTest.php
@@ -1,5 +1,7 @@
importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/menus/Tests/Functional/Fixtures/pages.xml');
+ $this->importCSVDataSet(__DIR__ . '/../Fixtures/pages.csv');
}
protected function reduceResults(array $results): array
@@ -65,33 +56,40 @@ protected function reduceResultsRecursive(array &$results): void
$results = $this->reduceResults($results);
}
- protected function getTypoScriptFrontendController(SiteInterface $site, int $pageId): TypoScriptFrontendController
+ protected function getTypoScriptFrontendController(Site $site, int $pageId): TypoScriptFrontendController
{
if ((new Typo3Version())->getMajorVersion() < 11) {
return GeneralUtility::makeInstance(TypoScriptFrontendController::class, null, $site, $site->getLanguageById(0));
}
- $context = $this->prophesize(Context::class);
- $context->hasAspect('frontend.preview')->willReturn(false);
- $context->setAspect('frontend.preview', Argument::any());
- $siteLanguage = $this->prophesize(SiteLanguage::class);
- $siteLanguage->getTypo3Language()->willReturn('default');
- $pageArguments = $this->prophesize(PageArguments::class);
- $pageArguments->getPageid()->willReturn($pageId);
- $pageArguments->getPageType()->willReturn(0);
- $pageArguments->getArguments()->willReturn([]);
- $frontendUserAuth = $this->prophesize(FrontendUserAuthentication::class);
-
- $controller = $this->getAccessibleMock(
- TypoScriptFrontendController::class,
- ['get_cache_timeout'],
- [
- $context->reveal(),
- $site,
- $siteLanguage->reveal(),
- $pageArguments->reveal(),
- $frontendUserAuth->reveal(),
- ]
- );
+ $context = $this->getMockBuilder(Context::class)
+ ->getMock();
+ $context->expects(self::any())->method('hasAspect')->with('frontend.preview')->willReturn(false);
+ $context->expects(self::any())->method('setAspect');
+ $siteLanguage = $this->getMockBuilder(SiteLanguage::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $siteLanguage->expects(self::any())->method('getTypo3Language')->willReturn('default');
+ $pageArguments = $this->getMockBuilder(PageArguments::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $pageArguments->expects(self::any())->method('getPageId')->willReturn($pageId);
+ $pageArguments->expects(self::any())->method('getPageType')->willReturn('0');
+ $pageArguments->expects(self::any())->method('getArguments')->willReturn([]);
+ $frontendUserAuth = $this->getMockBuilder(FrontendUserAuthentication::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $controller = $this->getMockBuilder($this->buildAccessibleProxy(TypoScriptFrontendController::class))
+ ->onlyMethods(['get_cache_timeout'])
+ ->setConstructorArgs(
+ [
+ $context,
+ $site,
+ $siteLanguage,
+ $pageArguments,
+ $frontendUserAuth,
+ ]
+ )
+ ->getMock();
$controller->expects(self::any())->method('get_cache_timeout')->willReturn(1);
return $controller;
}
diff --git a/Tests/Functional/DataProcessing/ListMenuProcessorTest.php b/Tests/Functional/DataProcessing/ListMenuProcessorTest.php
index 8ba302e..5459d22 100644
--- a/Tests/Functional/DataProcessing/ListMenuProcessorTest.php
+++ b/Tests/Functional/DataProcessing/ListMenuProcessorTest.php
@@ -1,6 +1,8 @@
withAttribute('site', $site);
$request = $request->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE);
@@ -335,7 +335,7 @@ public function processTest(array $tsfe, array $configuration, array $expected)
/**
* @return array
*/
- public function cacheDataProvider()
+ public static function cacheDataProvider()
{
return [
[
@@ -367,7 +367,7 @@ public function cacheDataProvider()
*/
public function menuIdTagsAreAddedToPageCache(array $tsfe, array $configuration, array $expectedTags)
{
- $site = GeneralUtility::makeInstance(NullSite::class);
+ $site = GeneralUtility::makeInstance(Site::class, 'main', $tsfe['id'], []);
$request = GeneralUtility::makeInstance(ServerRequest::class);
$request = $request->withAttribute('site', $site);
$request = $request->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE);
diff --git a/Tests/Functional/DataProcessing/TreeMenuProcessorTest.php b/Tests/Functional/DataProcessing/TreeMenuProcessorTest.php
index ca4df06..62d1b4f 100644
--- a/Tests/Functional/DataProcessing/TreeMenuProcessorTest.php
+++ b/Tests/Functional/DataProcessing/TreeMenuProcessorTest.php
@@ -1,5 +1,7 @@
withAttribute('site', $site);
$request = $request->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE);
@@ -415,7 +417,7 @@ public function processTest(array $tsfe, array $configuration, array $expected):
/**
* @return array
*/
- public function cacheDataProvider()
+ public static function cacheDataProvider()
{
return [
// entry point 2
@@ -460,7 +462,7 @@ public function cacheDataProvider()
*/
public function menuIdTagsAreAddedToPageCache(array $tsfe, int $entryPoints, array $expectedTags): void
{
- $site = GeneralUtility::makeInstance(NullSite::class);
+ $site = GeneralUtility::makeInstance(Site::class, 'main', $tsfe['id'], []);
$request = GeneralUtility::makeInstance(ServerRequest::class);
$request = $request->withAttribute('site', $site);
$request = $request->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE);
diff --git a/Tests/Functional/Domain/Repository/Fixtures/translated_page_with_nav_hide.csv b/Tests/Functional/Domain/Repository/Fixtures/translated_page_with_nav_hide.csv
new file mode 100644
index 0000000..3db18cf
--- /dev/null
+++ b/Tests/Functional/Domain/Repository/Fixtures/translated_page_with_nav_hide.csv
@@ -0,0 +1,4 @@
+"pages"
+,"uid","pid","title","sys_language_uid",nav_hide,l10n_parent
+,1,0,"page-1",0,0,0
+,2,0,"page-1",1,1,1
diff --git a/Tests/Functional/Domain/Repository/Fixtures/translated_page_with_nav_hide.xml b/Tests/Functional/Domain/Repository/Fixtures/translated_page_with_nav_hide.xml
deleted file mode 100644
index 7e1c83b..0000000
--- a/Tests/Functional/Domain/Repository/Fixtures/translated_page_with_nav_hide.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
- 1
- 0
- de
-
-
- 1
- 0
- 0
- page-1
- 0
- 0
-
-
- 2
- 0
- 1
- page-1-de
- 1
- 1
-
-
diff --git a/Tests/Functional/Domain/Repository/MenuRepositoryTest.php b/Tests/Functional/Domain/Repository/MenuRepositoryTest.php
index d3689ec..d0aca6c 100644
--- a/Tests/Functional/Domain/Repository/MenuRepositoryTest.php
+++ b/Tests/Functional/Domain/Repository/MenuRepositoryTest.php
@@ -11,31 +11,28 @@
*/
use B13\Menus\Domain\Repository\MenuRepository;
+use Psr\EventDispatcher\EventDispatcherInterface;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Context\LanguageAspect;
+use TYPO3\CMS\Core\Domain\Repository\PageRepository;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
class MenuRepositoryTest extends FunctionalTestCase
{
-
- /**
- * @var array
- */
- protected $testExtensionsToLoad = [
- 'typo3conf/ext/menus',
- ];
+ protected array $testExtensionsToLoad = ['typo3conf/ext/menus'];
/**
* @test
*/
public function translatedPageIsNotInMenuIfNavHideIsSet(): void
{
- $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/menus/Tests/Functional/Domain/Repository/Fixtures/translated_page_with_nav_hide.xml');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/translated_page_with_nav_hide.csv');
$languageAspect = GeneralUtility::makeInstance(LanguageAspect::class, 1);
$context = GeneralUtility::makeInstance(Context::class);
$context->setAspect('language', $languageAspect);
- $menuRepository = GeneralUtility::makeInstance(MenuRepository::class);
+ $pageRepository = GeneralUtility::makeInstance(PageRepository::class);
+ $menuRepository = GeneralUtility::makeInstance(MenuRepository::class, $context, $pageRepository, $this->createMock(EventDispatcherInterface::class));
$page = $menuRepository->getPage(1, []);
$pageInLanguage = $menuRepository->getPageInLanguage(1, $context, []);
self::assertSame([], $page);
@@ -47,11 +44,12 @@ public function translatedPageIsNotInMenuIfNavHideIsSet(): void
*/
public function translatedPageIsInMenuIfNavHideAndIgnoreNavHideIsSet(): void
{
- $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/menus/Tests/Functional/Domain/Repository/Fixtures/translated_page_with_nav_hide.xml');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/translated_page_with_nav_hide.csv');
$languageAspect = GeneralUtility::makeInstance(LanguageAspect::class, 1);
$context = GeneralUtility::makeInstance(Context::class);
$context->setAspect('language', $languageAspect);
- $menuRepository = GeneralUtility::makeInstance(MenuRepository::class);
+ $pageRepository = GeneralUtility::makeInstance(PageRepository::class);
+ $menuRepository = GeneralUtility::makeInstance(MenuRepository::class, $context, $pageRepository, $this->createMock(EventDispatcherInterface::class));
$page = $menuRepository->getPage(1, ['includeNotInMenu' => 1]);
$pageInLanguage = $menuRepository->getPageInLanguage(1, $context, ['includeNotInMenu' => 1]);
$page = $this->reduceResults($page);
diff --git a/Tests/Functional/Fixtures/be_users.csv b/Tests/Functional/Fixtures/be_users.csv
new file mode 100644
index 0000000..bfc3c6b
--- /dev/null
+++ b/Tests/Functional/Fixtures/be_users.csv
@@ -0,0 +1,4 @@
+"be_users"
+,"uid","pid","tstamp","username","password","admin","disable","starttime","endtime","options","crdate","workspace_perms","deleted","TSconfig","lastlogin","workspace_id"
+# The password is "password"
+,1,0,1366642540,"admin","$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1",1,0,0,0,0,1366642540,1,0,,1371033743,0
\ No newline at end of file
diff --git a/Tests/Functional/Fixtures/caches.csv b/Tests/Functional/Fixtures/caches.csv
new file mode 100644
index 0000000..1984f52
--- /dev/null
+++ b/Tests/Functional/Fixtures/caches.csv
@@ -0,0 +1,7 @@
+"cache_pages"
+,"identifier"
+,"foo"
+"cache_pages_tags"
+,"identifier","tag"
+,"foo","pageId_1"
+,"foo","menuId_2"
diff --git a/Tests/Functional/Fixtures/caches.xml b/Tests/Functional/Fixtures/caches.xml
deleted file mode 100644
index a39244f..0000000
--- a/Tests/Functional/Fixtures/caches.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- foo
-
-
- foo
- pageId_1
-
-
- foo
- menuId_2
-
-
diff --git a/Tests/Functional/Fixtures/pages.csv b/Tests/Functional/Fixtures/pages.csv
new file mode 100644
index 0000000..ffdef0f
--- /dev/null
+++ b/Tests/Functional/Fixtures/pages.csv
@@ -0,0 +1,8 @@
+"pages"
+,"uid","pid","title","slug",nav_hide,doktype
+,1,0,"page-1","/page-1",0,0
+,2,1,"page-2","/page-1/page-2",0,99
+,3,2,"page-3","/page-1/page-2/page-3",0,0
+,4,1,"page-4","/page-1/page-4",0,0
+,5,2,"page-5","/page-1/page-2/page-5",1,0
+,6,1,"page-6","/page-1/page-6",1,0
diff --git a/Tests/Functional/Fixtures/pages.xml b/Tests/Functional/Fixtures/pages.xml
deleted file mode 100644
index 11d1eb3..0000000
--- a/Tests/Functional/Fixtures/pages.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
-
- 1
- 0
- page-1
- /page-1
- 0
-
-
- 2
- 1
- 99
- page-2
- /page-1/page-2
- 0
-
-
- 3
- 2
- page-3
- /page-1/page-2/page-3
- 0
-
-
- 4
- 1
- page-4
- /page-1/page-4
- 0
-
-
- 5
- 2
- page-5
- /page-1/page-2/page-5
- 1
-
-
- 6
- 1
- page-6
- /page-1/page-6
- 1
-
-
diff --git a/Tests/Functional/Frontend/BreadcrumbMenuContentObjectTest.php b/Tests/Functional/Frontend/BreadcrumbMenuContentObjectTest.php
new file mode 100644
index 0000000..72f153f
--- /dev/null
+++ b/Tests/Functional/Frontend/BreadcrumbMenuContentObjectTest.php
@@ -0,0 +1,47 @@
+ 'typo3conf/sites'];
+
+ /**
+ * @test
+ */
+ public function menuOnRootPage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/breadcrumb_menu_content_object_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/'));
+ $expected = 'root ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+
+ /**
+ * @test
+ */
+ public function menuOnSubpage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/breadcrumb_menu_content_object_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/page-1'));
+ $expected = 'root page-1 ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+}
diff --git a/Tests/Functional/Frontend/BreadcrumbMenuFluidTest.php b/Tests/Functional/Frontend/BreadcrumbMenuFluidTest.php
new file mode 100644
index 0000000..a028ab9
--- /dev/null
+++ b/Tests/Functional/Frontend/BreadcrumbMenuFluidTest.php
@@ -0,0 +1,47 @@
+ 'typo3conf/sites'];
+
+ /**
+ * @test
+ */
+ public function menuOnRootPage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/breadcrumb_menu_fluid_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/'));
+ $expected = 'root ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+
+ /**
+ * @test
+ */
+ public function menuOnSubpage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/breadcrumb_menu_fluid_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/page-1'));
+ $expected = 'root page-1 ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+}
diff --git a/Tests/Functional/Frontend/Fixtures/Templates/Breadcrumbs.html b/Tests/Functional/Frontend/Fixtures/Templates/Breadcrumbs.html
new file mode 100644
index 0000000..a5df2bf
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/Templates/Breadcrumbs.html
@@ -0,0 +1,7 @@
+
+
+
+ {page.title}
+
+
+
diff --git a/Tests/Functional/Frontend/Fixtures/Templates/LanguageMenu.html b/Tests/Functional/Frontend/Fixtures/Templates/LanguageMenu.html
new file mode 100644
index 0000000..dc81751
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/Templates/LanguageMenu.html
@@ -0,0 +1,7 @@
+
+
+
+ {item.language.title}
+
+
+
diff --git a/Tests/Functional/Frontend/Fixtures/Templates/ListMenu.html b/Tests/Functional/Frontend/Fixtures/Templates/ListMenu.html
new file mode 100644
index 0000000..243f308
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/Templates/ListMenu.html
@@ -0,0 +1,7 @@
+
+
+
+ {page.title}
+
+
+
diff --git a/Tests/Functional/Frontend/Fixtures/Templates/TreeMenu.html b/Tests/Functional/Frontend/Fixtures/Templates/TreeMenu.html
new file mode 100644
index 0000000..fea496d
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/Templates/TreeMenu.html
@@ -0,0 +1,7 @@
+
+
+
+ {page.title}
+
+
+
diff --git a/Tests/Functional/Frontend/Fixtures/access_restriction.csv b/Tests/Functional/Frontend/Fixtures/access_restriction.csv
new file mode 100644
index 0000000..0830e1f
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/access_restriction.csv
@@ -0,0 +1,11 @@
+"pages"
+,"uid","pid","title","slug","fe_group"
+,1,0,"root","/",""
+,2,1,"page-1","/page-1",""
+,3,1,"page-2","/page-2","1"
+"fe_groups"
+,"uid","pid"
+,1,1
+"fe_users"
+,"uid","pid","usergroup"
+,1,1,"1"
diff --git a/Tests/Functional/Frontend/Fixtures/breadcrumb_menu_content_object_typoscript.csv b/Tests/Functional/Frontend/Fixtures/breadcrumb_menu_content_object_typoscript.csv
new file mode 100644
index 0000000..8c34e8e
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/breadcrumb_menu_content_object_typoscript.csv
@@ -0,0 +1,8 @@
+"sys_template"
+,"uid","pid","root","config"
+,1,1,1,"page = PAGE
+page.config.disableAllHeaderCode = 1
+page.20 = BREADCRUMBS
+page.20.renderObj = TEXT
+page.20.renderObj.typolink.parameter.data = field:uid
+"
diff --git a/Tests/Functional/Frontend/Fixtures/breadcrumb_menu_fluid_typoscript.csv b/Tests/Functional/Frontend/Fixtures/breadcrumb_menu_fluid_typoscript.csv
new file mode 100644
index 0000000..495eb3b
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/breadcrumb_menu_fluid_typoscript.csv
@@ -0,0 +1,9 @@
+"sys_template"
+,"uid","pid","root","config"
+,1,1,1,"page = PAGE
+page.config.disableAllHeaderCode = 1
+page.10 = FLUIDTEMPLATE
+page.10.templateRootPaths.10 = EXT:menus/Tests/Functional/Frontend/Fixtures/Templates
+page.10.templateName = Breadcrumbs.html
+page.10.dataProcessing.10 = B13\Menus\DataProcessing\BreadcrumbsMenu
+"
diff --git a/Tests/Functional/Frontend/Fixtures/language_menu_content_object_typoscript.csv b/Tests/Functional/Frontend/Fixtures/language_menu_content_object_typoscript.csv
new file mode 100644
index 0000000..4e3f4d8
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/language_menu_content_object_typoscript.csv
@@ -0,0 +1,14 @@
+"sys_template"
+,"uid","pid","root","config"
+,1,1,1,"page = PAGE
+page.config.disableAllHeaderCode = 1
+page.20 = LANGUAGEMENU
+page.20.renderObj = TEXT
+page.20.renderObj.typolink.parameter.data = field:uid
+page.20.renderObj.typolink.ATagParams = class='active'
+page.20.renderObj.typolink.ATagParams.if.isTrue.field = isActiveLanguage
+page.20.renderObj.typolink.additionalParams.data = field:language|languageId
+page.20.renderObj.typolink.additionalParams.intval = 1
+page.20.renderObj.typolink.additionalParams.wrap = &L=|
+page.20.renderObj.data = field:language|title // field:language|twoLetterIsoCode
+"
diff --git a/Tests/Functional/Frontend/Fixtures/language_menu_fluid_typoscript.csv b/Tests/Functional/Frontend/Fixtures/language_menu_fluid_typoscript.csv
new file mode 100644
index 0000000..beb6fe6
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/language_menu_fluid_typoscript.csv
@@ -0,0 +1,10 @@
+"sys_template"
+,"uid","pid","root","config"
+,1,1,1,"page = PAGE
+page.config.disableAllHeaderCode = 1
+page.10 = FLUIDTEMPLATE
+page.10.templateRootPaths.10 = EXT:menus/Tests/Functional/Frontend/Fixtures/Templates
+page.10.templateName = LanguageMenu.html
+page.10.dataProcessing.10 = B13\Menus\DataProcessing\LanguageMenu
+page.10.dataProcessing.10.as = menu
+"
diff --git a/Tests/Functional/Frontend/Fixtures/list_menu_content_object_typoscript.csv b/Tests/Functional/Frontend/Fixtures/list_menu_content_object_typoscript.csv
new file mode 100644
index 0000000..6fd3927
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/list_menu_content_object_typoscript.csv
@@ -0,0 +1,9 @@
+"sys_template"
+,"uid","pid","root","config"
+,1,1,1,"page = PAGE
+page.config.disableAllHeaderCode = 1
+page.20 = LISTMENU
+page.20.pages = 2
+page.20.renderObj = TEXT
+page.20.renderObj.typolink.parameter.data = field:uid
+"
diff --git a/Tests/Functional/Frontend/Fixtures/list_menu_fluid_typoscript.csv b/Tests/Functional/Frontend/Fixtures/list_menu_fluid_typoscript.csv
new file mode 100644
index 0000000..b45e981
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/list_menu_fluid_typoscript.csv
@@ -0,0 +1,11 @@
+"sys_template"
+,"uid","pid","root","config"
+,1,1,1,"page = PAGE
+page.config.disableAllHeaderCode = 1
+page.10 = FLUIDTEMPLATE
+page.10.templateRootPaths.10 = EXT:menus/Tests/Functional/Frontend/Fixtures/Templates
+page.10.templateName = ListMenu.html
+page.10.dataProcessing.10 = B13\Menus\DataProcessing\ListMenu
+page.10.dataProcessing.10.pages = 2
+page.10.dataProcessing.10.as = menu
+"
diff --git a/Tests/Functional/Frontend/Fixtures/pages.csv b/Tests/Functional/Frontend/Fixtures/pages.csv
new file mode 100644
index 0000000..f2918cf
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/pages.csv
@@ -0,0 +1,5 @@
+"pages"
+,"uid","pid","title","slug"
+,1,0,"root","/"
+,2,1,"page-1","/page-1"
+,3,1,"page-2","/page-2"
diff --git a/Tests/Functional/Frontend/Fixtures/translated_pages.csv b/Tests/Functional/Frontend/Fixtures/translated_pages.csv
new file mode 100644
index 0000000..ae3a9b6
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/translated_pages.csv
@@ -0,0 +1,5 @@
+"pages"
+,"uid","pid","title","slug","l10n_parent","sys_language_uid"
+,11,0,"root-de","/",1,1
+,12,1,"page-de-1","/page-1",2,1
+,13,1,"page-de-2","/page-2",3,1
diff --git a/Tests/Functional/Frontend/Fixtures/tree_menu_content_object_typoscript.csv b/Tests/Functional/Frontend/Fixtures/tree_menu_content_object_typoscript.csv
new file mode 100644
index 0000000..8a37b2d
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/tree_menu_content_object_typoscript.csv
@@ -0,0 +1,10 @@
+"sys_template"
+,"uid","pid","root","config"
+,1,1,1,"page = PAGE
+page.config.disableAllHeaderCode = 1
+page.20 = TREEMENU
+page.20.renderObj.level0 = TEXT
+page.20.renderObj.level0.typolink.parameter.data = field:uid
+page.20.renderObj.level0.typolink.ATagParams = class='active'
+page.20.renderObj.level0.typolink.ATagParams.if.isTrue.field = isInRootLine
+"
diff --git a/Tests/Functional/Frontend/Fixtures/tree_menu_fluid_typoscript.csv b/Tests/Functional/Frontend/Fixtures/tree_menu_fluid_typoscript.csv
new file mode 100644
index 0000000..58e1bf9
--- /dev/null
+++ b/Tests/Functional/Frontend/Fixtures/tree_menu_fluid_typoscript.csv
@@ -0,0 +1,10 @@
+"sys_template"
+,"uid","pid","root","config"
+,1,1,1,"page = PAGE
+page.config.disableAllHeaderCode = 1
+page.10 = FLUIDTEMPLATE
+page.10.templateRootPaths.10 = EXT:menus/Tests/Functional/Frontend/Fixtures/Templates
+page.10.templateName = TreeMenu.html
+page.10.dataProcessing.10 = B13\Menus\DataProcessing\TreeMenu
+page.10.dataProcessing.10.as = menu
+"
diff --git a/Tests/Functional/Frontend/LanguageMenuContentObjectTest.php b/Tests/Functional/Frontend/LanguageMenuContentObjectTest.php
new file mode 100644
index 0000000..23fac1c
--- /dev/null
+++ b/Tests/Functional/Frontend/LanguageMenuContentObjectTest.php
@@ -0,0 +1,49 @@
+ 'typo3conf/sites'];
+
+ /**
+ * @test
+ */
+ public function menuOnRootPage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/translated_pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/language_menu_content_object_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/'));
+ $expected = 'english german ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+
+ /**
+ * @test
+ */
+ public function menuOnSubpage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/translated_pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/language_menu_content_object_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/de/'));
+ $expected = 'english german ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+}
diff --git a/Tests/Functional/Frontend/LanguageMenuFluidTest.php b/Tests/Functional/Frontend/LanguageMenuFluidTest.php
new file mode 100644
index 0000000..181a0f7
--- /dev/null
+++ b/Tests/Functional/Frontend/LanguageMenuFluidTest.php
@@ -0,0 +1,49 @@
+ 'typo3conf/sites'];
+
+ /**
+ * @test
+ */
+ public function menuOnRootPage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/translated_pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/language_menu_fluid_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/'));
+ $expected = 'english german ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+
+ /**
+ * @test
+ */
+ public function menuOnSubpage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/translated_pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/language_menu_fluid_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/de/'));
+ $expected = 'english german ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+}
diff --git a/Tests/Functional/Frontend/ListMenuContentObjectTest.php b/Tests/Functional/Frontend/ListMenuContentObjectTest.php
new file mode 100644
index 0000000..2f8cf88
--- /dev/null
+++ b/Tests/Functional/Frontend/ListMenuContentObjectTest.php
@@ -0,0 +1,47 @@
+ 'typo3conf/sites'];
+
+ /**
+ * @test
+ */
+ public function menuOnRootPage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/list_menu_content_object_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/'));
+ $expected = 'page-1 ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+
+ /**
+ * @test
+ */
+ public function menuOnSubpage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/list_menu_content_object_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/page-1'));
+ $expected = 'page-1 ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+}
diff --git a/Tests/Functional/Frontend/ListMenuFluidTest.php b/Tests/Functional/Frontend/ListMenuFluidTest.php
new file mode 100644
index 0000000..270851d
--- /dev/null
+++ b/Tests/Functional/Frontend/ListMenuFluidTest.php
@@ -0,0 +1,47 @@
+ 'typo3conf/sites'];
+
+ /**
+ * @test
+ */
+ public function menuOnRootPage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/list_menu_fluid_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/'));
+ $expected = 'page-1 ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+
+ /**
+ * @test
+ */
+ public function menuOnSubpage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/list_menu_fluid_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/page-1'));
+ $expected = 'page-1 ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+}
diff --git a/Tests/Functional/Frontend/TreeMenuContentObjectTest.php b/Tests/Functional/Frontend/TreeMenuContentObjectTest.php
new file mode 100644
index 0000000..0a979f9
--- /dev/null
+++ b/Tests/Functional/Frontend/TreeMenuContentObjectTest.php
@@ -0,0 +1,47 @@
+ 'typo3conf/sites'];
+
+ /**
+ * @test
+ */
+ public function menuOnRootPage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/tree_menu_content_object_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/'));
+ $expected = 'page-1 page-2 ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+
+ /**
+ * @test
+ */
+ public function menuOnSubpage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/tree_menu_content_object_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/page-1'));
+ $expected = 'page-1 page-2 ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+}
diff --git a/Tests/Functional/Frontend/TreeMenuFluidTest.php b/Tests/Functional/Frontend/TreeMenuFluidTest.php
new file mode 100644
index 0000000..c1bf894
--- /dev/null
+++ b/Tests/Functional/Frontend/TreeMenuFluidTest.php
@@ -0,0 +1,76 @@
+ 'typo3conf/sites'];
+
+ /**
+ * @test
+ */
+ public function menuOnRootPage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/tree_menu_fluid_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/'));
+ $expected = 'page-1 page-2 ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+
+ /**
+ * @test
+ */
+ public function menuOnSubpage(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/tree_menu_fluid_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/page-1'));
+ $expected = 'page-1 page-2 ';
+ $body = (string)$response->getBody();
+ self::assertStringContainsString($expected, $body);
+ }
+
+ /**
+ * @test
+ */
+ public function menuWithAccessRestrictionForNotLoggedinUser(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/access_restriction.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/tree_menu_fluid_typoscript.csv');
+ $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/'));
+ $body = (string)$response->getBody();
+ self::assertStringContainsString('page-1 ', $body);
+ self::assertStringNotContainsString('page-2 ', $body);
+ }
+
+ /**
+ * @test
+ */
+ public function menuWithAccessRestrictionForLoggedinUser(): void
+ {
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/access_restriction.csv');
+ $this->importCSVDataSet(__DIR__ . '/Fixtures/tree_menu_fluid_typoscript.csv');
+ $context = (new InternalRequestContext())->withFrontendUserId(1);
+ $request = new InternalRequest('http://localhost/');
+ $response = $this->executeFrontendSubRequest($request, $context);
+ $body = (string)$response->getBody();
+ self::assertStringContainsString('page-1 ', $body);
+ self::assertStringContainsString('page-2 ', $body);
+ }
+}
diff --git a/Tests/Functional/Hooks/DataHandlerTest.php b/Tests/Functional/Hooks/DataHandlerTest.php
index bc18e6e..3887bc1 100644
--- a/Tests/Functional/Hooks/DataHandlerTest.php
+++ b/Tests/Functional/Hooks/DataHandlerTest.php
@@ -11,51 +11,44 @@
*/
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
-use TYPO3\CMS\Core\Core\Bootstrap;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Information\Typo3Version;
+use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
class DataHandlerTest extends FunctionalTestCase
{
+ protected DataHandler $dataHandler;
+ protected BackendUserAuthentication $backendUser;
- /**
- * @var DataHandler
- */
- protected $dataHandler;
+ protected array $testExtensionsToLoad = ['typo3conf/ext/menus'];
- /**
- * @var BackendUserAuthentication
- */
- protected $backendUser;
-
- /**
- * @var array
- */
- protected $testExtensionsToLoad = [
- 'typo3conf/ext/menus',
+ protected array $configurationToUseInTestInstance = [
+ 'SYS' => [
+ 'caching' => [
+ 'cacheConfigurations' => [
+ 'pages' => [
+ 'backend' => \TYPO3\CMS\Core\Cache\Backend\Typo3DatabaseBackend::class,
+ ],
+ ],
+ ],
+ ],
];
- /**
- * @throws \Doctrine\DBAL\DBALException
- * @throws \TYPO3\TestingFramework\Core\Exception
- */
protected function setUp(): void
{
parent::setUp();
- $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/menus/Tests/Functional/Fixtures/pages.xml');
- $this->importDataSet(ORIGINAL_ROOT . 'typo3conf/ext/menus/Tests/Functional/Fixtures/caches.xml');
- $this->backendUser = $this->setUpBackendUserFromFixture(1);
- Bootstrap::initializeLanguageObject();
+ $this->importCSVDataSet(__DIR__ . '/../Fixtures/pages.csv');
+ $this->importCSVDataSet(__DIR__ . '/../Fixtures/caches.csv');
+ $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
+ $this->backendUser = $GLOBALS['BE_USER'] = $this->setUpBackendUser(1);
+ $GLOBALS['LANG'] = GeneralUtility::makeInstance(LanguageServiceFactory::class)->createFromUserPreferences($GLOBALS['BE_USER']);
$this->dataHandler = GeneralUtility::makeInstance(DataHandler::class);
}
- /**
- * @return array
- */
- public function cmdmapDataProvider()
+ public static function cmdmapDataProvider(): array
{
return [
'copy page' => ['cmdmap' => ['pages' => [
@@ -111,8 +104,8 @@ protected function assertCacheIsEmpty(): void
}
$rows = $queryBuilder->select('*')
->from('cache_pages')
- ->execute()
- ->fetchAll();
+ ->executeQuery()
+ ->fetchAllAssociative();
self::assertSame(0, count($rows));
}
}
diff --git a/Tests/Unit/DataProcessing/BreadcrumbsMenuTest.php b/Tests/Unit/DataProcessing/BreadcrumbsMenuTest.php
index e1d51d8..0b3ec7b 100644
--- a/Tests/Unit/DataProcessing/BreadcrumbsMenuTest.php
+++ b/Tests/Unit/DataProcessing/BreadcrumbsMenuTest.php
@@ -1,5 +1,7 @@
2],
];
$GLOBALS['TSFE']->id = 2;
- $menuRepository = $this->prophesize(MenuRepository::class);
- $menuRepository->getBreadcrumbsMenu($GLOBALS['TSFE']->rootLine, [])->willReturn($pages);
- $contentDataProcessor = $this->prophesize(ContentDataProcessor::class);
- $contentObjectRenderer = $this->prophesize(ContentObjectRenderer::class);
+ $menuRepository = $this->getMockBuilder(MenuRepository::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $menuRepository->expects(self::once())->method('getBreadcrumbsMenu')->with($GLOBALS['TSFE']->rootLine, [])->willReturn($pages);
+ $contentDataProcessor = $this->getMockBuilder(ContentDataProcessor::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $contentObjectRenderer = $this->getMockBuilder(ContentObjectRenderer::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $contentObjectRenderer->expects(self::once())->method('stdWrapValue')->with('as', [], 'breadcrumbs')->willReturn('breadcrumbs');
$breadcrumbsMenuDataProcessor = $this->getMockBuilder(BreadcrumbsMenu::class)
- ->setMethods(['processAdditionalDataProcessors'])
- ->setConstructorArgs([$contentDataProcessor->reveal(), $menuRepository->reveal()])
+ ->onlyMethods(['processAdditionalDataProcessors'])
+ ->setConstructorArgs([$contentDataProcessor, $menuRepository])
->getMock();
- $contentObjectRenderer->stdWrapValue('as', [], 'breadcrumbs')->willReturn('breadcrumbs');
- $processedData = $breadcrumbsMenuDataProcessor->process($contentObjectRenderer->reveal(), [], [], []);
+ $processedData = $breadcrumbsMenuDataProcessor->process($contentObjectRenderer, [], [], []);
self::assertTrue($processedData['breadcrumbs'][0]['isInRootLine']);
self::assertTrue($processedData['breadcrumbs'][1]['isInRootLine']);
self::assertFalse($processedData['breadcrumbs'][0]['isCurrentPage']);
diff --git a/Tests/Unit/Domain/Repository/MenuRepositoryTest.php b/Tests/Unit/Domain/Repository/MenuRepositoryTest.php
index 36d635a..4c384ed 100644
--- a/Tests/Unit/Domain/Repository/MenuRepositoryTest.php
+++ b/Tests/Unit/Domain/Repository/MenuRepositoryTest.php
@@ -1,5 +1,7 @@
prophesize(Context::class);
- $context->getAspect('language')->willReturn($this->prophesize(LanguageAspect::class)->reveal());
- $pageRepository = $this->prophesize(PageRepository::class);
+ $languageAspect = $this->getMockBuilder(LanguageAspect::class)
+ ->getMock();
+ $context = $this->getMockBuilder(Context::class)
+ ->getMock();
+ $context->expects(self::once())->method('getAspect')->with('language')->willReturn($languageAspect);
+ $pageRepository = $this->getMockBuilder(PageRepository::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$excludedDoktypes = [
PageRepository::DOKTYPE_BE_USER_SECTION,
- PageRepository::DOKTYPE_RECYCLER,
PageRepository::DOKTYPE_SYSFOLDER,
];
- $pageRepository->getMenu(1, '*', 'sorting', Argument::any(), false)->willReturn([]);
- $pageRepository->getMenu(1, '*', 'sorting', 'AND doktype NOT IN (' . implode(',', $excludedDoktypes) . ') ', false)->shouldBeCalled()->willReturn([]);
-
- $menuRepository = $this->getMockBuilder(MenuRepository::class)
- ->setMethods(['foo'])
- ->setConstructorArgs([$context->reveal(), $pageRepository->reveal()])
- ->getMock();
+ if (GeneralUtility::makeInstance(Typo3Version::class)->getMajorVersion() < 13) {
+ $excludedDoktypes[] = PageRepository::DOKTYPE_RECYCLER;
+ }
+ $pageRepository->expects(self::once())->method('getMenu')
+ ->with(1, '*', 'sorting', 'AND doktype NOT IN (' . implode(',', $excludedDoktypes) . ') ', false)
+ ->willReturn([]);
+ $menuRepository = new MenuRepository($context, $pageRepository, $this->createMock(EventDispatcherInterface::class));
$menuRepository->getSubPagesOfPage(1, 1, []);
}
@@ -48,21 +57,25 @@ public function getSubPagesOfPageRestrictQueryToExcludeDoktypes(): void
*/
public function getSubPagesOfPageMergeExcludeDoktypesFromConfiguration(): void
{
- $context = $this->prophesize(Context::class);
- $context->getAspect('language')->willReturn($this->prophesize(LanguageAspect::class)->reveal());
- $pageRepository = $this->prophesize(PageRepository::class);
+ $languageAspect = $this->getMockBuilder(LanguageAspect::class)
+ ->getMock();
+ $context = $this->getMockBuilder(Context::class)
+ ->getMock();
+ $context->expects(self::once())->method('getAspect')->with('language')->willReturn($languageAspect);
+ $pageRepository = $this->getMockBuilder(PageRepository::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$excludedDoktypes = [
PageRepository::DOKTYPE_BE_USER_SECTION,
- PageRepository::DOKTYPE_RECYCLER,
PageRepository::DOKTYPE_SYSFOLDER,
];
- $pageRepository->getMenu(1, '*', 'sorting', Argument::any(), false)->willReturn([]);
- $pageRepository->getMenu(1, '*', 'sorting', 'AND doktype NOT IN (' . implode(',', $excludedDoktypes) . ',99) ', false)->shouldBeCalled()->willReturn([]);
-
- $menuRepository = $this->getMockBuilder(MenuRepository::class)
- ->setMethods(['foo'])
- ->setConstructorArgs([$context->reveal(), $pageRepository->reveal()])
- ->getMock();
+ if (GeneralUtility::makeInstance(Typo3Version::class)->getMajorVersion() < 13) {
+ $excludedDoktypes[] = PageRepository::DOKTYPE_RECYCLER;
+ }
+ $pageRepository->expects(self::once())->method('getMenu')
+ ->with(1, '*', 'sorting', 'AND doktype NOT IN (' . implode(',', $excludedDoktypes) . ',99) ', false)
+ ->willReturn([]);
+ $menuRepository = new MenuRepository($context, $pageRepository, $this->createMock(EventDispatcherInterface::class));
$menuRepository->getSubPagesOfPage(1, 1, ['excludeDoktypes' => 99]);
}
@@ -75,16 +88,52 @@ public function getBreadcrumbsMenuRespectConfiguredExcludeDoktypes(): void
['uid' => 1, 'doktype' => 99, 'nav_hide'=> 0],
['uid' => 2, 'doktype' => 98, 'nav_hide'=> 0],
];
- $context = $this->prophesize(Context::class);
- $context->getAspect('language')->willReturn($this->prophesize(LanguageAspect::class)->reveal());
- $pageRepository = $this->prophesize(PageRepository::class);
- $pageRepository->getPage(1)->willReturn($rootLine[0]);
- $pageRepository->getPage(2)->willReturn($rootLine[1]);
- $pageRepository->isPageSuitableForLanguage(Argument::any(), Argument::any())->willReturn(true);
+ $languageAspect = $this->getMockBuilder(LanguageAspect::class)
+ ->getMock();
+ $context = $this->getMockBuilder(Context::class)
+ ->getMock();
+ $context->expects(self::once())->method('getAspect')->with('language')->willReturn($languageAspect);
+
+ if (GeneralUtility::makeInstance(Typo3Version::class)->getMajorVersion() < 13) {
+ $pageRepository = new class() extends PageRepository {
+ public function getPage($uid, $disableGroupAccessCheck = false)
+ {
+ if ($uid === 1) {
+ // $rootLine[0]
+ return ['uid' => 1, 'doktype' => 99, 'nav_hide'=> 0];
+ }
+ if ($uid === 2) {
+ // $rootLine[0]
+ return ['uid' => 2, 'doktype' => 98, 'nav_hide'=> 0];
+ }
+ return [];
+ }
+ };
+ } else {
+ $pageRepository = new class() extends PageRepository {
+ public function getPage(int $uid, bool $disableGroupAccessCheck = false): array
+ {
+ if ($uid === 1) {
+ // $rootLine[0]
+ return ['uid' => 1, 'doktype' => 99, 'nav_hide'=> 0];
+ }
+ if ($uid === 2) {
+ // $rootLine[0]
+ return ['uid' => 2, 'doktype' => 98, 'nav_hide'=> 0];
+ }
+ return [];
+ }
+ protected function init(): void
+ {
+ }
+ };
+ }
+
$menuRepository = $this->getMockBuilder(MenuRepository::class)
- ->setMethods(['populateAdditionalKeysForPage'])
- ->setConstructorArgs([$context->reveal(), $pageRepository->reveal()])
+ ->onlyMethods(['populateAdditionalKeysForPage', 'isPageSuitableForLanguage'])
+ ->setConstructorArgs([$context, $pageRepository, $this->createMock(EventDispatcherInterface::class)])
->getMock();
+ $menuRepository->expects(self::any())->method('isPageSuitableForLanguage')->willReturn(true);
$breadcrumbs = $menuRepository->getBreadcrumbsMenu($rootLine, ['excludeDoktypes' => 99]);
self::assertSame(1, count($breadcrumbs));
}
diff --git a/Tests/Unit/PageStateMarkerTest.php b/Tests/Unit/PageStateMarkerTest.php
index 2a3d6b2..fc3ed41 100644
--- a/Tests/Unit/PageStateMarkerTest.php
+++ b/Tests/Unit/PageStateMarkerTest.php
@@ -1,5 +1,7 @@
'Menus',
'description' => 'Various Menu functionality for TYPO3 Frontend',
'category' => 'fe',
- 'version' => '0.5.1',
+ 'version' => '1.0.3',
'state' => 'stable',
'author' => 'Benni Mack',
'author_email' => 'typo3@b13.com',
'author_company' => 'b13 GmbH',
'constraints' => [
'depends' => [
- 'typo3' => '9.5.0-11.99.99',
+ 'typo3' => '10.4.0-12.99.99',
],
],
];
diff --git a/ext_localconf.php b/ext_localconf.php
index e86ab26..830c563 100644
--- a/ext_localconf.php
+++ b/ext_localconf.php
@@ -1,17 +1,15 @@
\B13\Menus\ContentObject\TreeMenuContentObject::class,
- 'LISTMENU' => \B13\Menus\ContentObject\ListMenuContentObject::class,
- 'LANGUAGEMENU' => \B13\Menus\ContentObject\LanguageMenuContentObject::class,
- 'BREADCRUMBS' => \B13\Menus\ContentObject\BreadcrumbsContentObject::class,
-]);
+defined('TYPO3') or die();
+
+if ((\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Information\Typo3Version::class))->getMajorVersion() < 12) {
+ $GLOBALS['TYPO3_CONF_VARS']['FE']['ContentObjects'] = array_merge($GLOBALS['TYPO3_CONF_VARS']['FE']['ContentObjects'], [
+ 'TREEMENU' => \B13\Menus\ContentObject\TreeMenuContentObject::class,
+ 'LISTMENU' => \B13\Menus\ContentObject\ListMenuContentObject::class,
+ 'LANGUAGEMENU' => \B13\Menus\ContentObject\LanguageMenuContentObject::class,
+ 'BREADCRUMBS' => \B13\Menus\ContentObject\BreadcrumbsContentObject::class,
+ ]);
+}
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearCachePostProc']['tx-menus'] =
\B13\Menus\Hooks\DataHandlerHook::class . '->clearMenuCaches';
-
-if (!class_exists(\TYPO3\CMS\Frontend\Page\PageRepository::class)) {
- class_alias(\TYPO3\CMS\Core\Domain\Repository\PageRepository::class, \TYPO3\CMS\Frontend\Page\PageRepository::class);
-}