From 89dd4e15b72d3cbe493e7ad82db8ca076e853b82 Mon Sep 17 00:00:00 2001 From: Lamm Date: Thu, 30 Apr 2026 09:26:46 +0200 Subject: [PATCH 1/3] Bugfix: TYPO3 v13 disable cache for subrequest --- Classes/Middleware/InternalSsiRedirectMiddleware.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Classes/Middleware/InternalSsiRedirectMiddleware.php b/Classes/Middleware/InternalSsiRedirectMiddleware.php index 9e05106..2dd7683 100644 --- a/Classes/Middleware/InternalSsiRedirectMiddleware.php +++ b/Classes/Middleware/InternalSsiRedirectMiddleware.php @@ -14,6 +14,7 @@ use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Http\HtmlResponse; use TYPO3\CMS\Core\Http\Uri; +use TYPO3\CMS\Frontend\Cache\CacheInstruction; class InternalSsiRedirectMiddleware implements MiddlewareInterface { @@ -35,8 +36,10 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface if (file_exists($absolutePath)) { $content = file_get_contents($absolutePath); } else { + $cacheInstruction = $request->getAttribute('frontend.cache.instruction', new CacheInstruction()); + $cacheInstruction->disableCache('EXT:ssi_include: Disabled cache for SSI sub-request.'); $subRequest = $request - ->withAttribute('noCache', true) + ->withAttribute('frontend.cache.instruction', $cacheInstruction) ->withQueryParams([]) ->withUri($request->getUri()->withPath($originalRequestUri->getPath())->withQuery($originalRequestUri->getQuery())); $handler->handle($subRequest); From a17e0aa4ead15f4caec19e30abf1250fa864594f Mon Sep 17 00:00:00 2001 From: Lamm Date: Thu, 30 Apr 2026 12:16:40 +0200 Subject: [PATCH 2/3] Breaking: Remove TYPO3 v11 and PHP 8.1, add PHP 8.5 --- .gitattributes | 13 ++++++ .github/workflows/tasks.yml | 32 +++++++------ .gitignore | 1 + .../Cache/Backend/SsiIncludeCacheBackend.php | 3 +- Classes/DataProcessing/LazyDataProcessor.php | 5 ++- .../InternalSsiRedirectMiddleware.php | 6 ++- Classes/Proxy/Proxy.php | 23 +++++++--- Classes/Utility/FilenameUtility.php | 4 +- Classes/Utility/IsCacheableUtility.php | 1 - .../ViewHelpers/RenderIncludeViewHelper.php | 6 ++- Configuration/RequestMiddlewares.php | 2 + Makefile | 16 ++++++- README.md | 3 ++ Tests/Classes/SsiIncludeCacheBackendTest.php | 44 +++++++----------- Tests/Classes/SsiIncludeCacheFrontendTest.php | 9 ++-- composer.json | 22 +++++---- ext_emconf.php | 2 +- ext_localconf.php | 8 +++- fractor.php | 18 ++++++++ phpstan-baseline.neon | 45 ------------------- phpunit.xml | 12 +++++ 21 files changed, 155 insertions(+), 120 deletions(-) create mode 100644 .gitattributes create mode 100644 fractor.php diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..cd01c13 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,13 @@ +# Exclude from release archives +/.github export-ignore +/Tests export-ignore +.gitattributes export-ignore +.gitignore export-ignore +grumphp.yml export-ignore +Makefile export-ignore +phpstan.neon export-ignore +phpstan-baseline.neon export-ignore +phpunit.xml export-ignore +rector.php export-ignore +/coverage export-ignore +fractor.php export-ignore diff --git a/.github/workflows/tasks.yml b/.github/workflows/tasks.yml index 2556e29..122c4a8 100644 --- a/.github/workflows/tasks.yml +++ b/.github/workflows/tasks.yml @@ -9,18 +9,13 @@ jobs: strategy: fail-fast: false matrix: - php: [ '8.1', '8.2', '8.3', '8.4' ] - typo3: [ '11', '12', '13' ] - exclude: - - php: '8.1' - typo3: '13' - - php: '8.4' - typo3: '11' + php: [ '82', '83', '84', '85' ] + typo3: [ '12', '13' ] + container: + image: ghcr.io/typo3/core-testing-php${{ matrix.php }}:latest steps: - - name: Setup PHP with PECL extension - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} + - name: Install dependencies + run: apk add --no-cache nodejs - uses: actions/checkout@v4 - uses: actions/cache@v4 with: @@ -29,8 +24,17 @@ jobs: restore-keys: | ${{ runner.os }}-${{ matrix.php }}-composer- - run: composer update --with typo3/minimal="^${{ matrix.typo3 }}" --no-interaction --no-progress -W --dev - - run: ./vendor/bin/grumphp run --ansi - + - run: git config --global --add safe.directory $GITHUB_WORKSPACE + - run: ./vendor/bin/grumphp run --ansi --no-interaction + - run: composer test + - name: Upload coverage reports to Codecov + if: ${{ env.CODECOV_TOKEN != '' }} + uses: codecov/codecov-action@v5 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + with: + token: ${{ secrets.CODECOV_TOKEN }} + slug: andersundsehr/ssi_include ter-release: name: TER release runs-on: ubuntu-latest @@ -52,7 +56,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.1' + php-version: '8.2' extensions: intl, mbstring, xml, soap, zip, curl tools: composer diff --git a/.gitignore b/.gitignore index bbe1f95..5808b79 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ vendor/ var/ .phpunit.result.cache .idea/ +coverage/ diff --git a/Classes/Cache/Backend/SsiIncludeCacheBackend.php b/Classes/Cache/Backend/SsiIncludeCacheBackend.php index 3beb826..9e62957 100644 --- a/Classes/Cache/Backend/SsiIncludeCacheBackend.php +++ b/Classes/Cache/Backend/SsiIncludeCacheBackend.php @@ -73,6 +73,7 @@ public function setStoreData(bool $storeData): void */ public function set($entryIdentifier, $data, array $tags = [], $lifetime = null): void { + /** @phpstan-ignore function.alreadyNarrowedType */ if (!is_string($data)) { throw new InvalidArgumentException('Data must be a string', 1616420133); } @@ -180,6 +181,6 @@ public function flushByTags(array $tags): void */ public function findIdentifiersByTag($tag): array { - return parent::findIdentifiersByTag($tag); + return array_values(parent::findIdentifiersByTag($tag)); } } diff --git a/Classes/DataProcessing/LazyDataProcessor.php b/Classes/DataProcessing/LazyDataProcessor.php index ea0b1f5..d9b7bfc 100644 --- a/Classes/DataProcessing/LazyDataProcessor.php +++ b/Classes/DataProcessing/LazyDataProcessor.php @@ -35,8 +35,9 @@ public function __construct() public function process(ContentObjectRenderer $cObj, array $contentObjectConfiguration, array $processorConfiguration, array $processedData): array { $realProcessedData = 'LazyDataProcessor $realProcessedData'; - $variables = $processorConfiguration['variables'] ?? ''; // given variable names to proxy - $variables .= ',' . $cObj->stdWrapValue('as', $processorConfiguration['proxiedProcessor.'] ?? [], ''); // invert variable name to proxy + $variables = (string)($processorConfiguration['variables'] ?? ''); // @phpstan-ignore cast.string + $proxiedProcessorConfig = $processorConfiguration['proxiedProcessor.'] ?? []; + $variables .= ',' . $cObj->stdWrapValue('as', is_array($proxiedProcessorConfig) ? $proxiedProcessorConfig : [], ''); // invert variable name to proxy foreach (GeneralUtility::trimExplode(',', $variables, true) as $variableName) { // don't overwrite existing variables with proxies diff --git a/Classes/Middleware/InternalSsiRedirectMiddleware.php b/Classes/Middleware/InternalSsiRedirectMiddleware.php index 2dd7683..96fff8a 100644 --- a/Classes/Middleware/InternalSsiRedirectMiddleware.php +++ b/Classes/Middleware/InternalSsiRedirectMiddleware.php @@ -36,7 +36,11 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface if (file_exists($absolutePath)) { $content = file_get_contents($absolutePath); } else { - $cacheInstruction = $request->getAttribute('frontend.cache.instruction', new CacheInstruction()); + $cacheInstruction = $request->getAttribute('frontend.cache.instruction'); + if (!$cacheInstruction instanceof CacheInstruction) { + $cacheInstruction = new CacheInstruction(); + } + $cacheInstruction->disableCache('EXT:ssi_include: Disabled cache for SSI sub-request.'); $subRequest = $request ->withAttribute('frontend.cache.instruction', $cacheInstruction) diff --git a/Classes/Proxy/Proxy.php b/Classes/Proxy/Proxy.php index d12f51f..7d637cb 100644 --- a/Classes/Proxy/Proxy.php +++ b/Classes/Proxy/Proxy.php @@ -31,46 +31,55 @@ private function processRealInstance(): void } } - public function __call($name, $arguments): mixed + /** + * @param array $arguments + */ + public function __call(string $name, array $arguments): mixed { $this->processRealInstance(); + /** @phpstan-ignore argument.type */ return call_user_func([$this->value, $name], $arguments); } - public function __invoke(...$arguments): mixed + public function __invoke(mixed ...$arguments): mixed { $this->processRealInstance(); return call_user_func($this->value, $arguments); } - public function __isset($name): bool + public function __isset(string $name): bool { $this->processRealInstance(); + /** @phpstan-ignore offsetAccess.nonOffsetAccessible */ return isset($this->value[$name]); } - public function __get($name): mixed + public function __get(string $name): mixed { $this->processRealInstance(); + /** @phpstan-ignore offsetAccess.nonOffsetAccessible */ return $this->value[$name]; } - public function __set($name, $value): void + public function __set(string $name, mixed $value): void { $this->processRealInstance(); + /** @phpstan-ignore offsetAccess.nonOffsetAccessible */ $this->value[$name] = $value; } - public function __unset($name): void + public function __unset(string $name): void { $this->processRealInstance(); + /** @phpstan-ignore offsetAccess.nonOffsetAccessible */ unset($this->value[$name]); } public function __toString(): string { $this->processRealInstance(); - return $this->value . ''; + // @phpstan-ignore cast.string + return (string)$this->value; } public function current(): mixed diff --git a/Classes/Utility/FilenameUtility.php b/Classes/Utility/FilenameUtility.php index 91a8f9e..0a6b050 100644 --- a/Classes/Utility/FilenameUtility.php +++ b/Classes/Utility/FilenameUtility.php @@ -24,7 +24,6 @@ private function getSsiIncludeDir(): string } $cacheManager = GeneralUtility::makeInstance(CacheManager::class); - assert($cacheManager instanceof CacheManager); $cache = $cacheManager->getCache('aus_ssi_include_cache'); $cacheBackend = $cache->getBackend(); assert($cacheBackend instanceof SsiIncludeCacheBackend); @@ -46,7 +45,8 @@ public function getAbsoluteFilename(string $filename): string */ public function getReqUrl(string $filename): string { - $reverseProxyPrefix = '/' . trim($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefix'] ?? '', '/') . '/'; + // @phpstan-ignore offsetAccess.nonOffsetAccessible, offsetAccess.nonOffsetAccessible, cast.string + $reverseProxyPrefix = '/' . trim((string)($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefix'] ?? ''), '/') . '/'; $includePath = rtrim($reverseProxyPrefix, '/') . $this->getSsiIncludeDir(); return $includePath . $filename . '?ssi_include=' . $filename . '&originalRequestUri=' . urlencode((string)GeneralUtility::getIndpEnv('REQUEST_URI')); } diff --git a/Classes/Utility/IsCacheableUtility.php b/Classes/Utility/IsCacheableUtility.php index 056182d..6ac11cf 100644 --- a/Classes/Utility/IsCacheableUtility.php +++ b/Classes/Utility/IsCacheableUtility.php @@ -27,7 +27,6 @@ public function usePageCache(?TypoScriptFrontendController $typoScriptFrontendCo } $context = GeneralUtility::makeInstance(Context::class); - assert($context instanceof Context); $backendUserContext = $context->getAspect('backend.user'); if ($backendUserContext->isLoggedIn()) { return false; diff --git a/Classes/ViewHelpers/RenderIncludeViewHelper.php b/Classes/ViewHelpers/RenderIncludeViewHelper.php index fc830be..3279b34 100644 --- a/Classes/ViewHelpers/RenderIncludeViewHelper.php +++ b/Classes/ViewHelpers/RenderIncludeViewHelper.php @@ -76,6 +76,7 @@ public function render(): string // Get frontend user groups for their group dependent include file $frontendUser = $this->context->getAspect('frontend.user'); + /** @phpstan-ignore instanceof.alwaysTrue, function.alreadyNarrowedType */ assert($frontendUser instanceof UserAspect); $groupString = ''; if ($frontendUser->isLoggedIn()) { @@ -96,8 +97,8 @@ public function render(): string $eventDispatcher->dispatch($renderedHtmlEvent); $html = $renderedHtmlEvent->getHtml(); - $cacheTags = $this->arguments['cacheTags']; - assert(is_array($cacheTags)); + /** @var list $cacheTags */ + $cacheTags = $this->arguments['cacheTags'] ?? []; $cacheTags[] = 'tx_ssiinclude_' . $name; $cacheLifeTime = $this->arguments['cacheLifeTime']; @@ -150,6 +151,7 @@ protected function isBackendUser(): bool protected function getSiteName(): string { + /** @phpstan-ignore method.nonObject */ return $GLOBALS['TYPO3_REQUEST']->getAttribute('site')->getIdentifier(); } } diff --git a/Configuration/RequestMiddlewares.php b/Configuration/RequestMiddlewares.php index f503e75..2c3cf51 100644 --- a/Configuration/RequestMiddlewares.php +++ b/Configuration/RequestMiddlewares.php @@ -1,5 +1,7 @@ &1 | tee /tmp/act-output.log; \ + echo ""; \ + echo "=== 🏁 Summary ==="; \ + grep "🏁" /tmp/act-output.log || true + + +clean: + docker rm -f $$(docker ps -aq --filter "name=act-") 2>/dev/null || true diff --git a/README.md b/README.md index 4c865e3..5e0662f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +[![CI](https://github.com/andersundsehr/ssi_include/actions/workflows/tasks.yml/badge.svg)](https://github.com/andersundsehr/ssi_include/actions/workflows/tasks.yml) +[![codecov](https://codecov.io/github/andersundsehr/ssi_include/branch/main/graph/badge.svg)](https://app.codecov.io/github/andersundsehr/ssi_include) + # EXT:ssi_include This Extension will help you to update your Menu's and other Partials faster if they are rendered the Same over all your Pages. diff --git a/Tests/Classes/SsiIncludeCacheBackendTest.php b/Tests/Classes/SsiIncludeCacheBackendTest.php index bf4311a..affdefb 100644 --- a/Tests/Classes/SsiIncludeCacheBackendTest.php +++ b/Tests/Classes/SsiIncludeCacheBackendTest.php @@ -4,6 +4,7 @@ namespace AUS\SsiInclude\Tests; +use PHPUnit\Framework\Attributes\Test; use TYPO3\CMS\Core\DataHandling\DataHandler; use AUS\SsiInclude\Cache\Backend\SsiIncludeCacheBackend; use AUS\SsiInclude\Cache\Frontend\SsiIncludeCacheFrontend; @@ -70,7 +71,6 @@ protected function tearDown(): void parent::tearDown(); $cacheManager = GeneralUtility::makeInstance(CacheManager::class); - assert($cacheManager instanceof CacheManager); $cacheManager->flushCaches(); } @@ -80,7 +80,6 @@ protected function tearDown(): void private function initializeCacheFramework(): void { $cacheManager = GeneralUtility::makeInstance(CacheManager::class); - assert($cacheManager instanceof CacheManager); $cacheManager->setCacheConfigurations([ 'aus_ssi_include_cache' => [ 'frontend' => SsiIncludeCacheFrontend::class, @@ -93,9 +92,9 @@ private function initializeCacheFramework(): void } /** - * @test * @throws Exception */ + #[Test] public function cacheTableExists(): void { $connection = $this->getConnectionPool()->getConnectionForTable('cache_aus_ssi_include_cache'); @@ -106,9 +105,9 @@ public function cacheTableExists(): void } /** - * @test * @throws NoSuchCacheException */ + #[Test] public function cacheEntryIsStoredAndRetrievedSuccessfully(): void { $entryIdentifier = 'test_entry.html'; @@ -116,7 +115,6 @@ public function cacheEntryIsStoredAndRetrievedSuccessfully(): void // Store cache entry $cacheManager = GeneralUtility::makeInstance(CacheManager::class); - assert($cacheManager instanceof CacheManager); $cache = $cacheManager->getCache('aus_ssi_include_cache'); $cache->set($entryIdentifier, $data); @@ -132,16 +130,15 @@ public function cacheEntryIsStoredAndRetrievedSuccessfully(): void } /** - * @test * @throws NoSuchCacheException */ + #[Test] public function cacheEntryIsRemovedSuccessfully(): void { $entryIdentifier = 'test_entry.html'; $data = '

Cached Content

'; $cacheManager = GeneralUtility::makeInstance(CacheManager::class); - assert($cacheManager instanceof CacheManager); $cache = $cacheManager->getCache('aus_ssi_include_cache'); $cache->set($entryIdentifier, $data); self::assertTrue($cache->has($entryIdentifier)); @@ -155,16 +152,15 @@ public function cacheEntryIsRemovedSuccessfully(): void } /** - * @test * @throws NoSuchCacheException */ + #[Test] public function flushRemovesAllCacheEntries(): void { $data1 = '

Content 1

'; $data2 = '

Content 2

'; $cacheManager = GeneralUtility::makeInstance(CacheManager::class); - assert($cacheManager instanceof CacheManager); $cache = $cacheManager->getCache('aus_ssi_include_cache'); $cache->set('entry1.html', $data1); @@ -184,16 +180,15 @@ public function flushRemovesAllCacheEntries(): void } /** - * @test * @throws NoSuchCacheException */ + #[Test] public function flushByTagRemovesOnlyMatchingEntries(): void { $data1 = '

Content 1

'; $data2 = '

Content 2

'; $cacheManager = GeneralUtility::makeInstance(CacheManager::class); - assert($cacheManager instanceof CacheManager); $cache = $cacheManager->getCache('aus_ssi_include_cache'); $cache->set('entry1.html', $data1, ['tag1']); @@ -214,9 +209,9 @@ public function flushByTagRemovesOnlyMatchingEntries(): void } /** - * @test * @throws NoSuchCacheException */ + #[Test] public function garbageCollectionRemovesOrphanedFiles(): void { $orphanedFile = $this->ssiIncludeDir . 'orphaned.html'; @@ -226,7 +221,6 @@ public function garbageCollectionRemovesOrphanedFiles(): void self::assertFileExists($orphanedFile); $cacheManager = GeneralUtility::makeInstance(CacheManager::class); - assert($cacheManager instanceof CacheManager); $cache = $cacheManager->getCache('aus_ssi_include_cache'); $cache->collectGarbage(); @@ -235,16 +229,16 @@ public function garbageCollectionRemovesOrphanedFiles(): void } /** - * @test * @throws NoSuchCacheException */ + #[Test] public function garbageCollectionRemovesOutdatedFiles(): void { $cacheManager = GeneralUtility::makeInstance(CacheManager::class); - assert($cacheManager instanceof CacheManager); $cache = $cacheManager->getCache('aus_ssi_include_cache'); $cache->set('outdated.html', '

Outdated Content

', [], 1); + assert(is_int($GLOBALS['EXEC_TIME'])); $GLOBALS['EXEC_TIME'] += 2; $cache->collectGarbage(); $GLOBALS['EXEC_TIME'] -= 2; @@ -255,13 +249,10 @@ public function garbageCollectionRemovesOutdatedFiles(): void self::assertFileDoesNotExist($this->ssiIncludeDir . 'outdated.html'); } - /** - * @test - */ + #[Test] public function cacheFlushEventRemovesAllFiles(): void { $cacheManager = GeneralUtility::makeInstance(CacheManager::class); - assert($cacheManager instanceof CacheManager); $cache = $cacheManager->getCache('aus_ssi_include_cache'); $cache->set('cacheFlushEventRemovesAllFiles1.html', 'test', ['tag1']); self::assertTrue($cache->has('cacheFlushEventRemovesAllFiles1.html')); @@ -281,20 +272,18 @@ public function cacheFlushEventRemovesAllFiles(): void } /** - * @test * @throws NoSuchCacheException */ + #[Test] public function noCacheFileCreatedWhenBackendUserIsLoggedIn(): void { - #$cacheManager = GeneralUtility::makeInstance(CacheManager::class); - #assert($cacheManager instanceof CacheManager); - #$cacheManager->flushCaches(); - // Import a page tree with a test page $this->importCSVDataSet(__DIR__ . '/../Fixtures/pages.csv'); // Set extension configuration + // @phpstan-ignore offsetAccess.nonOffsetAccessible, offsetAccess.nonOffsetAccessible, offsetAccess.nonOffsetAccessible $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ssi_include']['disabled'] = '0'; + // @phpstan-ignore offsetAccess.nonOffsetAccessible, offsetAccess.nonOffsetAccessible, offsetAccess.nonOffsetAccessible $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ssi_include']['method'] = 'ssi'; // Set up TypoScript template for the test page @@ -341,16 +330,18 @@ public function noCacheFileCreatedWhenBackendUserIsLoggedIn(): void } /** - * @test * @throws NoSuchCacheException */ + #[Test] public function cacheFileCreatedWhenNoBackendUserLoggedIn(): void { // Import a page tree with a test page $this->importCSVDataSet(__DIR__ . '/../Fixtures/pages.csv'); // Set extension configuration + // @phpstan-ignore offsetAccess.nonOffsetAccessible, offsetAccess.nonOffsetAccessible, offsetAccess.nonOffsetAccessible $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ssi_include']['disabled'] = '0'; + // @phpstan-ignore offsetAccess.nonOffsetAccessible, offsetAccess.nonOffsetAccessible, offsetAccess.nonOffsetAccessible $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['ssi_include']['method'] = 'ssi'; // Set up TypoScript template for the test page @@ -404,9 +395,9 @@ public function cacheFileCreatedWhenNoBackendUserLoggedIn(): void } /** - * @test * @throws NoSuchCacheException */ + #[Test] public function dataHandlerClearCacheRemovesCacheEntry(): void { $entryIdentifier = 'datahandler_test_entry.html'; @@ -414,7 +405,6 @@ public function dataHandlerClearCacheRemovesCacheEntry(): void // Store cache entry first $cacheManager = GeneralUtility::makeInstance(CacheManager::class); - assert($cacheManager instanceof CacheManager); $cache = $cacheManager->getCache('aus_ssi_include_cache'); assert($cache->getBackend() instanceof SsiIncludeCacheBackend); $cache->set($entryIdentifier, $data); diff --git a/Tests/Classes/SsiIncludeCacheFrontendTest.php b/Tests/Classes/SsiIncludeCacheFrontendTest.php index eabf9a4..30cab08 100644 --- a/Tests/Classes/SsiIncludeCacheFrontendTest.php +++ b/Tests/Classes/SsiIncludeCacheFrontendTest.php @@ -5,15 +5,14 @@ namespace AUS\SsiInclude\Tests; use AUS\SsiInclude\Cache\Frontend\SsiIncludeCacheFrontend; +use PHPUnit\Framework\Attributes\Test; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; class SsiIncludeCacheFrontendTest extends UnitTestCase { protected bool $resetSingletonInstances = true; - /** - * @test - */ + #[Test] public function validFilenamesPass(): void { $validFilenames = [ @@ -29,9 +28,7 @@ public function validFilenamesPass(): void } } - /** - * @test - */ + #[Test] public function invalidFilenamesFail(): void { $invalidFilenames = [ diff --git a/composer.json b/composer.json index 23ab43f..576f580 100644 --- a/composer.json +++ b/composer.json @@ -8,21 +8,26 @@ "name": "Matthias Vogel", "email": "m.vogel@andersundsehr.com", "homepage": "https://andersundsehr.com" + }, + { + "name": "Stefan Lamm", + "email": "s.lamm@andersundsehr.com", + "homepage": "https://andersundsehr.com" } ], "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", - "typo3/cms-core": "^11.5.0 || ^12.4.0 || ^13.4.0", - "typo3/cms-fluid": "^11.5.0 || ^12.4.0 || ^13.4.0", - "typo3/cms-frontend": "^11.5.0 || ^12.4.0 || ^13.4.0", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "typo3/cms-core": "^12.4.0 || ^13.4.0", + "typo3/cms-fluid": "^12.4.0 || ^13.4.0", + "typo3/cms-frontend": "^12.4.0 || ^13.4.0", "webimpress/safe-writer": "^2.2.0" }, "require-dev": { "composer/composer": "^2.5.5", "pluswerk/grumphp-config": "*", - "saschaegerer/phpstan-typo3": "*", - "ssch/typo3-rector": "^2.5.0", - "typo3/testing-framework": "^7.1.1 || ^8.2.7 || ^9.2.0" + "saschaegerer/phpstan-typo3": "^2.0.0 || ^3.0.1", + "ssch/typo3-rector": "^2.15.2 || ^3.14.1", + "typo3/testing-framework": "^8.3.1 || ^9.5.0" }, "replace": { "typo3-ter/ssi-include": "self.version" @@ -39,6 +44,7 @@ }, "config": { "allow-plugins": { + "a9f/fractor-extension-installer": true, "ergebnis/composer-normalize": true, "phpro/grumphp": true, "phpstan/extension-installer": true, @@ -55,7 +61,7 @@ } }, "scripts": { - "test": "@php ./vendor/bin/phpunit" + "test": "XDEBUG_MODE=coverage php ./vendor/bin/phpunit" }, "ter-require": { "webimpress/safe-writer": "^2.2.0" diff --git a/ext_emconf.php b/ext_emconf.php index 2adecee..5466d56 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -14,7 +14,7 @@ 'version' => InstalledVersions::getPrettyVersion('andersundsehr/ssi-include'), 'constraints' => [ 'depends' => [ - 'typo3' => '10.4.0-11.99.99', + 'typo3' => '12.4.0-13.99.99', ], 'conflicts' => [ ], diff --git a/ext_localconf.php b/ext_localconf.php index 9c31c6a..9054748 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -1,5 +1,7 @@ SsiIncludeCacheFrontend::class, 'backend' => SsiIncludeCacheBackend::class, 'groups' => ['pages'], -], $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['aus_ssi_include_cache'] ?? []); +], $existingCacheConfig); if (VersionNumberUtility::convertVersionNumberToInteger(VersionNumberUtility::getNumericTypo3Version()) < 12000000) { + // @phpstan-ignore offsetAccess.nonOffsetAccessible, offsetAccess.nonOffsetAccessible, offsetAccess.nonOffsetAccessible, offsetAccess.nonOffsetAccessible $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['usePageCache'][] = IsCacheableUtility::class; } diff --git a/fractor.php b/fractor.php new file mode 100644 index 0000000..00d33d1 --- /dev/null +++ b/fractor.php @@ -0,0 +1,18 @@ +withPaths(array_filter(explode("\n", (string)shell_exec("git ls-files | xargs ls -d 2>/dev/null")))) + ->withSets([ + ...FractorSettings::sets(true), + ]) + ->withRules([ + ...FractorSettings::rules(), + ]) + ->withOptions([ + ...FractorSettings::options(), + ]); diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 1fce4bc..164e3d1 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -15,46 +15,6 @@ parameters: count: 4 path: Classes/Proxy/Proxy.php - - - message: "#^Method AUS\\\\SsiInclude\\\\Proxy\\\\Proxy\\:\\:__call\\(\\) has parameter \\$arguments with no type specified\\.$#" - count: 1 - path: Classes/Proxy/Proxy.php - - - - message: "#^Method AUS\\\\SsiInclude\\\\Proxy\\\\Proxy\\:\\:__call\\(\\) has parameter \\$name with no type specified\\.$#" - count: 1 - path: Classes/Proxy/Proxy.php - - - - message: "#^Method AUS\\\\SsiInclude\\\\Proxy\\\\Proxy\\:\\:__get\\(\\) has parameter \\$name with no type specified\\.$#" - count: 1 - path: Classes/Proxy/Proxy.php - - - - message: "#^Method AUS\\\\SsiInclude\\\\Proxy\\\\Proxy\\:\\:__invoke\\(\\) has parameter \\$arguments with no type specified\\.$#" - count: 1 - path: Classes/Proxy/Proxy.php - - - - message: "#^Method AUS\\\\SsiInclude\\\\Proxy\\\\Proxy\\:\\:__isset\\(\\) has parameter \\$name with no type specified\\.$#" - count: 1 - path: Classes/Proxy/Proxy.php - - - - message: "#^Method AUS\\\\SsiInclude\\\\Proxy\\\\Proxy\\:\\:__set\\(\\) has parameter \\$name with no type specified\\.$#" - count: 1 - path: Classes/Proxy/Proxy.php - - - - message: "#^Method AUS\\\\SsiInclude\\\\Proxy\\\\Proxy\\:\\:__set\\(\\) has parameter \\$value with no type specified\\.$#" - count: 1 - path: Classes/Proxy/Proxy.php - - - - message: "#^Method AUS\\\\SsiInclude\\\\Proxy\\\\Proxy\\:\\:__unset\\(\\) has parameter \\$name with no type specified\\.$#" - count: 1 - path: Classes/Proxy/Proxy.php - - message: "#^Parameter \\#1 \\$array of function current expects array\\|object, mixed given\\.$#" count: 1 @@ -75,11 +35,6 @@ parameters: count: 1 path: Classes/Proxy/Proxy.php - - - message: "#^Parameter \\#1 \\$callback of function call_user_func expects callable\\(\\)\\: mixed, array\\{mixed, mixed\\} given\\.$#" - count: 1 - path: Classes/Proxy/Proxy.php - - message: "#^Parameter \\#1 \\$callback of function call_user_func expects callable\\(\\)\\: mixed, mixed given\\.$#" count: 1 diff --git a/phpunit.xml b/phpunit.xml index fae19c6..271c916 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -12,4 +12,16 @@ Tests + + + Classes + + + + + + + + + From 8f95a12eb9290b9eb050a4e3c2ac809a3bcbb9f0 Mon Sep 17 00:00:00 2001 From: Lamm Date: Thu, 30 Apr 2026 12:18:43 +0200 Subject: [PATCH 3/3] Bugfix: Add gpg to pipeline --- .github/workflows/tasks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tasks.yml b/.github/workflows/tasks.yml index 122c4a8..7797e3c 100644 --- a/.github/workflows/tasks.yml +++ b/.github/workflows/tasks.yml @@ -15,7 +15,7 @@ jobs: image: ghcr.io/typo3/core-testing-php${{ matrix.php }}:latest steps: - name: Install dependencies - run: apk add --no-cache nodejs + run: apk add --no-cache nodejs gpg - uses: actions/checkout@v4 - uses: actions/cache@v4 with: