From e37e0156880d3b5917a929ec190b0ed696f92cdd Mon Sep 17 00:00:00 2001 From: Andreas Fernandez Date: Mon, 3 Jul 2023 11:06:50 +0200 Subject: [PATCH] [!!!][TASK] Provide TYPO3 v12 compatibility The extension is declared compatible to TYPO3 v12. In the same run, support for TYPO3 v10 has been dropped. Also, the deprecated configuration `dataServiceProcessor` has been removed. --- .github/workflows/ci.yml | 37 ++-- .github/workflows/publish.yml | 4 +- .gitignore | 3 +- .php_cs-fixer.dist.php | 2 +- .phplint.yml | 1 + Build/tools/php-cs-fixer/composer.json | 5 + Build/tools/phplint/composer.json | 5 + .../AssetRenderer/UsercentricsLibrary.php} | 60 ++----- Classes/ViewHelpers/ScriptViewHelper.php | 73 +++++++- Configuration/Services.yaml | 5 + Configuration/TCA/Overrides/sys_template.php | 6 +- .../UsercentricsLibraryTest.php} | 165 ++++++++++-------- composer.json | 29 +-- ext_emconf.php | 4 +- ext_localconf.php | 5 +- 15 files changed, 242 insertions(+), 162 deletions(-) create mode 100644 Build/tools/php-cs-fixer/composer.json create mode 100644 Build/tools/phplint/composer.json rename Classes/{Hooks/PageRendererPreProcess.php => EventListener/AssetRenderer/UsercentricsLibrary.php} (65%) rename Tests/Unit/{PageRendererPreProcessTest.php => EventListener/AssetRenderer/UsercentricsLibraryTest.php} (59%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1bf2a9..d1cec5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,41 +9,44 @@ jobs: strategy: fail-fast: false matrix: - typo3: [^10.4, dev-master] - php: ['7.4'] + typo3: [^11.5, ^12.4] + php: ['8.1', '8.2'] include: - - typo3: ^10.4 + - typo3: ^11.5 php: '7.4' - - typo3: ^10.4 - php: '7.3' - - typo3: ^10.4 - php: '7.2' - - typo3: dev-master + - typo3: ^11.5 php: '8.0' - - typo3: dev-master - php: '7.4' + - typo3: ^11.5 + php: '8.1' + - typo3: ^11.5 + php: '8.2' + - typo3: ^12.4 + php: '8.1' + - typo3: ^12.4 + php: '8.2' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup PHP ${{ matrix.php }} uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - - name: Update Composer - run: | - sudo composer self-update - composer --version - - name: Validate composer.json and composer.lock run: composer validate - name: Install dependencies run: | - composer require typo3/cms-core:${{ matrix.typo3 }} --no-progress + composer require typo3/cms-core:${{ matrix.typo3 }} --no-progress --ansi git checkout composer.json + - name: Install dev tools + run: | + for tool in `ls -1 Build/tools`; do + composer install --working-dir="Build/tools/$tool" --no-progress --ansi + done + - name: CGL run: composer t3g:cgl diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ee1556f..173f552 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,7 +10,7 @@ jobs: publish: name: Publish new version to TER if: startsWith(github.ref, 'refs/tags/') - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 env: TYPO3_EXTENSION_KEY: ${{ secrets.TYPO3_EXTENSION_KEY }} TYPO3_API_TOKEN: ${{ secrets.TYPO3_API_TOKEN }} @@ -40,7 +40,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.0 extensions: intl, mbstring, json, zip, curl - name: Install tailor diff --git a/.gitignore b/.gitignore index 887a789..756e019 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ var/ config/ # CGL Fixer -.php_cs.cache +.php-cs-fixer.cache +.phplint.cache diff --git a/.php_cs-fixer.dist.php b/.php_cs-fixer.dist.php index f4a28be..25f5242 100644 --- a/.php_cs-fixer.dist.php +++ b/.php_cs-fixer.dist.php @@ -40,7 +40,7 @@ ], ], 'no_leading_import_slash' => true, - 'no_trailing_comma_in_singleline_array' => true, + 'no_trailing_comma_in_singleline' => true, 'no_singleline_whitespace_before_semicolons' => true, 'no_unused_imports' => true, 'concat_space' => ['spacing' => 'one'], diff --git a/.phplint.yml b/.phplint.yml index cc3c4fe..90d6367 100644 --- a/.phplint.yml +++ b/.phplint.yml @@ -5,3 +5,4 @@ extensions: - php exclude: - .build + - Build diff --git a/Build/tools/php-cs-fixer/composer.json b/Build/tools/php-cs-fixer/composer.json new file mode 100644 index 0000000..2f173c4 --- /dev/null +++ b/Build/tools/php-cs-fixer/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "friendsofphp/php-cs-fixer": "^3.20" + } +} diff --git a/Build/tools/phplint/composer.json b/Build/tools/phplint/composer.json new file mode 100644 index 0000000..19da403 --- /dev/null +++ b/Build/tools/phplint/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "overtrue/phplint": "^3.3 || ^4.5" + } +} diff --git a/Classes/Hooks/PageRendererPreProcess.php b/Classes/EventListener/AssetRenderer/UsercentricsLibrary.php similarity index 65% rename from Classes/Hooks/PageRendererPreProcess.php rename to Classes/EventListener/AssetRenderer/UsercentricsLibrary.php index 8d78fd9..dee41d2 100644 --- a/Classes/Hooks/PageRendererPreProcess.php +++ b/Classes/EventListener/AssetRenderer/UsercentricsLibrary.php @@ -1,5 +1,5 @@ assetCollector = $assetCollector ?? GeneralUtility::makeInstance(AssetCollector::class); - } + if ($event->isInline()) { + return; + } - public function addLibrary(): void - { $config = $this->getTypoScriptConfiguration(); if ($config === null) { return; @@ -38,12 +29,12 @@ public function addLibrary(): void if (!$this->isValidId($config)) { throw new \InvalidArgumentException('Usercentrics ID not configured, please set plugin.tx_usercentrics.settingsId in your TypoScript configuration', 1583774571); } - $this->addUsercentricsScript($config); - $this->addConfiguredJsFiles($config['jsFiles.'] ?? []); - $this->addConfiguredInlineJavaScript($config['jsInline.'] ?? []); + $this->addUsercentricsScript($event, $config); + $this->addConfiguredJsFiles($event, $config['jsFiles.'] ?? []); + $this->addConfiguredInlineJavaScript($event, $config['jsInline.'] ?? []); } - protected function addConfiguredInlineJavaScript(array $jsInline): void + protected function addConfiguredInlineJavaScript(BeforeJavaScriptsRenderingEvent $event, array $jsInline): void { foreach ($jsInline as $inline) { $code = $inline['value'] ?? ''; @@ -54,11 +45,11 @@ protected function addConfiguredInlineJavaScript(array $jsInline): void $identifier = StringUtility::getUniqueId($dataProcessingService . '-'); $attributes = $this->getAttributesForUsercentrics($inline['attributes.'] ?? [], $dataProcessingService); $options = $this->convertPriorityToBoolean($inline['options.'] ?? []); - $this->assetCollector->addInlineJavaScript($identifier, $code, $attributes, $options); + $event->getAssetCollector()->addInlineJavaScript($identifier, $code, $attributes, $options); } } - protected function addConfiguredJsFiles(array $jsFiles): void + protected function addConfiguredJsFiles(BeforeJavaScriptsRenderingEvent $event, array $jsFiles): void { foreach ($jsFiles as $jsFile) { if (!$this->isValidFile($jsFile)) { @@ -71,13 +62,13 @@ protected function addConfiguredJsFiles(array $jsFiles): void $identifier = StringUtility::getUniqueId($dataProcessingService . '-'); $attributes = $this->getAttributesForUsercentrics($jsFile['attributes.'] ?? [], $dataProcessingService); $options = $this->convertPriorityToBoolean($jsFile['options.'] ?? []); - $this->assetCollector->addJavaScript($identifier, $jsFile['file'], $attributes, $options); + $event->getAssetCollector()->addJavaScript($identifier, $jsFile['file'], $attributes, $options); } } - protected function addUsercentricsScript(array $config): void + protected function addUsercentricsScript(BeforeJavaScriptsRenderingEvent $event, array $config): void { - $this->assetCollector->addJavaScript('usercentrics', 'https://app.usercentrics.eu/latest/main.js', [ + $event->getAssetCollector()->addJavaScript('usercentrics', 'https://app.usercentrics.eu/latest/main.js', [ 'type' => 'application/javascript', 'id' => $config['settingsId'], 'language' => $config['language'], @@ -105,7 +96,6 @@ protected function getTypoScriptConfiguration(): ?array if (!isset($GLOBALS['TSFE']) || !($GLOBALS['TSFE'] instanceof TypoScriptFrontendController)) { return null; } - /** @var \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController $tsfe */ $tsfe = $GLOBALS['TSFE']; $ts = $tsfe->tmpl->setup; return $ts['plugin.']['tx_usercentrics.'] ?? null; @@ -123,27 +113,11 @@ protected function isValidId(array $config): bool protected function isValidIdentifier(array $jsFile): bool { - if (isset($jsFile['dataServiceProcessor'])) { - trigger_error( - 'The setting "dataServiceProcessor" has been marked as deprecated. Use dataProcessingService instead.', - E_USER_DEPRECATED - ); - return isset($jsFile['dataServiceProcessor']) && is_string($jsFile['dataServiceProcessor']); - } - return isset($jsFile['dataProcessingService']) && is_string($jsFile['dataProcessingService']); } protected function getDataProcessingService(array $configuration): string { - if (isset($configuration['dataServiceProcessor'])) { - trigger_error( - 'The setting "dataServiceProcessor" has been marked as deprecated. Use dataProcessingService instead.', - E_USER_DEPRECATED - ); - return $configuration['dataServiceProcessor']; - } - return $configuration['dataProcessingService']; } } diff --git a/Classes/ViewHelpers/ScriptViewHelper.php b/Classes/ViewHelpers/ScriptViewHelper.php index 377870d..562c958 100644 --- a/Classes/ViewHelpers/ScriptViewHelper.php +++ b/Classes/ViewHelpers/ScriptViewHelper.php @@ -10,7 +10,10 @@ namespace T3G\AgencyPack\Usercentrics\ViewHelpers; +use TYPO3\CMS\Core\Page\AssetCollector; use TYPO3\CMS\Core\Utility\StringUtility; +use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper; +use TYPO3Fluid\Fluid\Core\ViewHelper\TagBuilder; /** * Usercentrics Viewhelper @@ -25,12 +28,71 @@ * alert('hello world'); * */ -class ScriptViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\Asset\ScriptViewHelper +class ScriptViewHelper extends AbstractTagBasedViewHelper { + /** + * This VH does not produce direct output, thus does not need to be wrapped in an escaping node + * + * @var bool + */ + protected $escapeOutput = false; + + /** + * Rendered children string is passed as JavaScript code, + * there is no point in HTML encoding anything from that. + * + * @var bool + */ + protected $escapeChildren = false; + + protected AssetCollector $assetCollector; + + public function injectAssetCollector(AssetCollector $assetCollector): void + { + $this->assetCollector = $assetCollector; + } + + public function initialize(): void + { + // Add a tag builder, that does not html encode values, because rendering with encoding happens in AssetRenderer + $this->setTagBuilder( + new class() extends TagBuilder { + public function addAttribute($attributeName, $attributeValue, $escapeSpecialCharacters = false): void + { + parent::addAttribute($attributeName, $attributeValue, false); + } + } + ); + parent::initialize(); + } + public function initializeArguments(): void { parent::initializeArguments(); - $this->registerArgument('dataServiceProcessor', 'string', 'the data processing service name as configured in Usercentrics', true); + $this->registerUniversalTagAttributes(); + $this->registerTagAttribute('async', 'bool', 'Define that the script will be fetched in parallel to parsing and evaluation.', false); + $this->registerTagAttribute('crossorigin', 'string', 'Define how to handle crossorigin requests.', false); + $this->registerTagAttribute('defer', 'bool', 'Define that the script is meant to be executed after the document has been parsed.', false); + $this->registerTagAttribute('integrity', 'string', 'Define base64-encoded cryptographic hash of the resource that allows browsers to verify what they fetch.', false); + $this->registerTagAttribute('nomodule', 'bool', 'Define that the script should not be executed in browsers that support ES2015 modules.', false); + $this->registerTagAttribute('nonce', 'string', 'Define a cryptographic nonce (number used once) used to whitelist inline styles in a style-src Content-Security-Policy.', false); + $this->registerTagAttribute('referrerpolicy', 'string', 'Define which referrer is sent when fetching the resource.', false); + $this->registerTagAttribute('src', 'string', 'Define the URI of the external resource.', false); + $this->registerTagAttribute('type', 'string', 'Define the MIME type (usually \'text/javascript\').', false); + $this->registerArgument('useNonce', 'bool', 'Whether to use the global nonce value', false, false); + $this->registerArgument( + 'identifier', + 'string', + 'Use this identifier within templates to only inject your JS once, even though it is added multiple times.', + true + ); + $this->registerArgument( + 'priority', + 'boolean', + 'Define whether the JavaScript should be put in the tag above-the-fold or somewhere in the body part.', + false, + false + ); $this->registerArgument('dataProcessingService', 'string', 'the data processing service name as configured in Usercentrics', true); } @@ -59,13 +121,6 @@ public function render(): string protected function getDataProcessingService(): string { - if (isset($this->arguments['dataServiceProcessor'])) { - trigger_error( - 'The argument "dataServiceProcessor" of ' . self::class . ' has been marked as deprecated. Use dataProcessingService instead.', - E_USER_DEPRECATED - ); - return $this->arguments['dataServiceProcessor']; - } return $this->arguments['dataProcessingService']; } } diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index f3cde7c..d60e4ea 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -7,3 +7,8 @@ services: T3G\AgencyPack\Usercentrics\: resource: '../Classes/*' + T3G\AgencyPack\Usercentrics\EventListener\AssetRenderer\UsercentricsLibrary: + tags: + - name: event.listener + identifier: 'usercentrics/UsercentricsLibrary' + event: TYPO3\CMS\Core\Page\Event\BeforeJavaScriptsRenderingEvent diff --git a/Configuration/TCA/Overrides/sys_template.php b/Configuration/TCA/Overrides/sys_template.php index b23a956..68f90f4 100644 --- a/Configuration/TCA/Overrides/sys_template.php +++ b/Configuration/TCA/Overrides/sys_template.php @@ -7,11 +7,13 @@ * LICENSE file that was distributed with this source code. */ -if (!defined('TYPO3_MODE')) { +use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; + +if (!defined('TYPO3')) { die('Access denied.'); } call_user_func(static function () { // Add static template - \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('usercentrics', 'Configuration/TypoScript/Static/', 'Usercentrics Integration'); + ExtensionManagementUtility::addStaticFile('usercentrics', 'Configuration/TypoScript/Static/', 'Usercentrics Integration'); }); diff --git a/Tests/Unit/PageRendererPreProcessTest.php b/Tests/Unit/EventListener/AssetRenderer/UsercentricsLibraryTest.php similarity index 59% rename from Tests/Unit/PageRendererPreProcessTest.php rename to Tests/Unit/EventListener/AssetRenderer/UsercentricsLibraryTest.php index d66db26..0fb1c11 100644 --- a/Tests/Unit/PageRendererPreProcessTest.php +++ b/Tests/Unit/EventListener/AssetRenderer/UsercentricsLibraryTest.php @@ -8,50 +8,36 @@ * LICENSE file that was distributed with this source code. */ -namespace T3G\AgencyPack\Usercentrics\Tests\Unit; +namespace T3G\AgencyPack\Usercentrics\Tests\Unit\EventListener\AssetRenderer; -use Prophecy\Argument; -use T3G\AgencyPack\Usercentrics\Hooks\PageRendererPreProcess; +use T3G\AgencyPack\Usercentrics\EventListener\AssetRenderer\UsercentricsLibrary; use TYPO3\CMS\Core\Page\AssetCollector; +use TYPO3\CMS\Core\Page\Event\BeforeJavaScriptsRenderingEvent; use TYPO3\CMS\Core\TypoScript\TemplateService; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; -class PageRendererPreProcessTest extends UnitTestCase +class UsercentricsLibraryTest extends UnitTestCase { - protected $templateService; - protected $assetCollector; - - protected function setUp(): void - { - parent::setUp(); - $tsfeProphecy = $this->prophesize(TypoScriptFrontendController::class); - $this->templateService = $this->prophesize(TemplateService::class); - $tsfeProphecy->tmpl = $this->templateService->reveal(); - $GLOBALS['TSFE'] = $tsfeProphecy->reveal(); - $this->assetCollector = $this->prophesize(AssetCollector::class); - $this->assetCollector->addJavaScript(Argument::cetera())->willReturn($this->assetCollector->reveal()); - $this->assetCollector->addInlineJavaScript(Argument::cetera())->willReturn($this->assetCollector->reveal()); - } - /** * @test */ public function addLibraryThrowsExceptionIfUsercentricsIdIsNotSet(): void { - $this->templateService->setup = [ + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionCode(1583774571); + + $this->mockTypoScriptFrontend([ 'plugin.' => [ 'tx_usercentrics.' => [ ], ], - ]; + ]); - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionCode(1583774571); - - $pageRendererPreProcess = new PageRendererPreProcess($this->assetCollector->reveal()); - $pageRendererPreProcess->addLibrary(); + $assetCollector = new AssetCollector(); + $event = new BeforeJavaScriptsRenderingEvent($assetCollector, false, false); + (new UsercentricsLibrary())($event); } /** @@ -59,23 +45,29 @@ public function addLibraryThrowsExceptionIfUsercentricsIdIsNotSet(): void */ public function addLibraryAddsMainUsercentricsScript(): void { - $this->templateService->setup = [ + $this->mockTypoScriptFrontend([ 'plugin.' => [ 'tx_usercentrics.' => [ 'settingsId' => 'myUsercentricsId', 'language' => 'en', ], ], - ]; + ]); - $pageRendererPreProcess = new PageRendererPreProcess($this->assetCollector->reveal()); - $pageRendererPreProcess->addLibrary(); + $event = new BeforeJavaScriptsRenderingEvent(new AssetCollector(), false, false); + (new UsercentricsLibrary())($event); - $this->assetCollector->addJavaScript('usercentrics', 'https://app.usercentrics.eu/latest/main.js', [ - 'type' => 'application/javascript', - 'id' => 'myUsercentricsId', - 'language' => 'en', - ])->shouldHaveBeenCalled(); + $javaScripts = $event->getAssetCollector()->getJavaScripts(); + self::assertArrayHasKey('usercentrics', $javaScripts); + self::assertSame([ + 'source' => 'https://app.usercentrics.eu/latest/main.js', + 'attributes' => [ + 'type' => 'application/javascript', + 'id' => 'myUsercentricsId', + 'language' => 'en', + ], + 'options' => [], + ], $javaScripts['usercentrics']); } /** @@ -83,7 +75,9 @@ public function addLibraryAddsMainUsercentricsScript(): void */ public function addLibraryThrowsExceptionIfNoIdentifierGivenForFile(): void { - $this->templateService->setup = [ + $this->expectExceptionCode(1583774683); + + $this->mockTypoScriptFrontend([ 'plugin.' => [ 'tx_usercentrics.' => [ 'settingsId' => 'myUsercentricsId', @@ -95,12 +89,10 @@ public function addLibraryThrowsExceptionIfNoIdentifierGivenForFile(): void ], ], ], - ]; - - $this->expectExceptionCode(1583774683); + ]); - $pageRendererPreProcess = new PageRendererPreProcess($this->assetCollector->reveal()); - $pageRendererPreProcess->addLibrary(); + $event = new BeforeJavaScriptsRenderingEvent(new AssetCollector(), false, false); + (new UsercentricsLibrary())($event); } /** @@ -108,7 +100,9 @@ public function addLibraryThrowsExceptionIfNoIdentifierGivenForFile(): void */ public function addLibraryThrowsExceptionIfNoFileGiven(): void { - $this->templateService->setup = [ + $this->expectExceptionCode(1583774682); + + $this->mockTypoScriptFrontend([ 'plugin.' => [ 'tx_usercentrics.' => [ 'settingsId' => 'myUsercentricsId', @@ -119,12 +113,10 @@ public function addLibraryThrowsExceptionIfNoFileGiven(): void ], ], ], - ]; + ]); - $this->expectExceptionCode(1583774682); - - $pageRendererPreProcess = new PageRendererPreProcess($this->assetCollector->reveal()); - $pageRendererPreProcess->addLibrary(); + $event = new BeforeJavaScriptsRenderingEvent(new AssetCollector(), false, false); + (new UsercentricsLibrary())($event); } /** @@ -134,7 +126,7 @@ public function addLibraryAddsConfiguredFileWithAttributes(): void { $file = 'EXT:site/Resources/Public/JavaScript/test.js'; $identifier = 'myIdentifier'; - $this->templateService->setup = [ + $this->mockTypoScriptFrontend([ 'plugin.' => [ 'tx_usercentrics.' => [ 'settingsId' => 'myUsercentricsId', @@ -150,17 +142,26 @@ public function addLibraryAddsConfiguredFileWithAttributes(): void ], ], ], - ]; + ]); $expectedAttributes = [ 'custom' => 'attribute', 'type' => 'text/plain', 'data-usercentrics' => $identifier ]; - $pageRendererPreProcess = new PageRendererPreProcess($this->assetCollector->reveal()); - $pageRendererPreProcess->addLibrary(); - $this->assetCollector->addJavaScript($identifier, $file, $expectedAttributes); + $event = new BeforeJavaScriptsRenderingEvent(new AssetCollector(), false, false); + (new UsercentricsLibrary())($event); + + $javaScripts = $event->getAssetCollector()->getJavaScripts(); + $addedScript = current(array_filter($javaScripts, static function (string $usedIdentifier) use ($identifier) { + return str_starts_with($usedIdentifier, $identifier); + }, ARRAY_FILTER_USE_KEY)); + self::assertSame([ + 'source' => 'EXT:site/Resources/Public/JavaScript/test.js', + 'attributes' => $expectedAttributes, + 'options' => [], + ], $addedScript); } /** @@ -170,7 +171,7 @@ public function addLibraryAddsConfiguredFileWithAttributesAndOptions(): void { $file = 'EXT:site/Resources/Public/JavaScript/test.js'; $identifier = 'myIdentifier'; - $this->templateService->setup = [ + $this->mockTypoScriptFrontend([ 'plugin.' => [ 'tx_usercentrics.' => [ 'settingsId' => 'myUsercentricsId', @@ -189,7 +190,7 @@ public function addLibraryAddsConfiguredFileWithAttributesAndOptions(): void ], ], ], - ]; + ]); $expectedAttributes = [ 'custom' => 'attribute', @@ -199,10 +200,19 @@ public function addLibraryAddsConfiguredFileWithAttributesAndOptions(): void $expectedOptions = [ 'priority' => true ]; - $pageRendererPreProcess = new PageRendererPreProcess($this->assetCollector->reveal()); - $pageRendererPreProcess->addLibrary(); - $this->assetCollector->addJavaScript($identifier, $file, $expectedAttributes, $expectedOptions); + $event = new BeforeJavaScriptsRenderingEvent(new AssetCollector(), false, false); + (new UsercentricsLibrary())($event); + + $javaScripts = $event->getAssetCollector()->getJavaScripts(); + $addedScript = current(array_filter($javaScripts, static function (string $usedIdentifier) use ($identifier) { + return str_starts_with($usedIdentifier, $identifier); + }, ARRAY_FILTER_USE_KEY)); + self::assertSame([ + 'source' => $file, + 'attributes' => $expectedAttributes, + 'options' => $expectedOptions, + ], $addedScript); } /** @@ -210,7 +220,9 @@ public function addLibraryAddsConfiguredFileWithAttributesAndOptions(): void */ public function addLibraryThrowsExceptionIfNoIdentifierGivenForInlineJs(): void { - $this->templateService->setup = [ + $this->expectExceptionCode(1583774685); + + $this->mockTypoScriptFrontend([ 'plugin.' => [ 'tx_usercentrics.' => [ 'settingsId' => 'myUsercentricsId', @@ -222,12 +234,10 @@ public function addLibraryThrowsExceptionIfNoIdentifierGivenForInlineJs(): void ], ], ], - ]; - - $this->expectExceptionCode(1583774685); + ]); - $pageRendererPreProcess = new PageRendererPreProcess($this->assetCollector->reveal()); - $pageRendererPreProcess->addLibrary(); + $event = new BeforeJavaScriptsRenderingEvent(new AssetCollector(), false, false); + (new UsercentricsLibrary())($event); } /** @@ -237,7 +247,7 @@ public function addLibraryAddsInlineJsWithAttributesAndOptions(): void { $value = 'alert(123);'; $identifier = 'myIdentifier'; - $this->templateService->setup = [ + $this->mockTypoScriptFrontend([ 'plugin.' => [ 'tx_usercentrics.' => [ 'settingsId' => 'myUsercentricsId', @@ -256,7 +266,7 @@ public function addLibraryAddsInlineJsWithAttributesAndOptions(): void ], ], ], - ]; + ]); $expectedAttributes = [ 'custom' => 'attribute', @@ -266,9 +276,28 @@ public function addLibraryAddsInlineJsWithAttributesAndOptions(): void $expectedOptions = [ 'priority' => true ]; - $pageRendererPreProcess = new PageRendererPreProcess($this->assetCollector->reveal()); - $pageRendererPreProcess->addLibrary(); - $this->assetCollector->addInlineJavaScript($identifier, $value, $expectedAttributes, $expectedOptions); + $event = new BeforeJavaScriptsRenderingEvent(new AssetCollector(), false, false); + (new UsercentricsLibrary())($event); + + $javaScripts = $event->getAssetCollector()->getInlineJavaScripts(); + $addedScript = current(array_filter($javaScripts, static function (string $usedIdentifier) use ($identifier) { + return str_starts_with($usedIdentifier, $identifier); + }, ARRAY_FILTER_USE_KEY)); + self::assertSame([ + 'source' => $value, + 'attributes' => $expectedAttributes, + 'options' => $expectedOptions, + ], $addedScript); + } + + private function mockTypoScriptFrontend(array $setup = []): void + { + $templateService = $this->createMock(TemplateService::class); + $templateService->setup = $setup; + + $tsfe = $this->createMock(TypoScriptFrontendController::class); + $tsfe->tmpl = $templateService; + $GLOBALS['TSFE'] = $tsfe; } } diff --git a/composer.json b/composer.json index 224b9ca..a8dcbfe 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,11 @@ "bin-dir": ".build/bin", "discard-changes": true, "optimize-autoloader": true, - "vendor-dir": ".build/vendor" + "vendor-dir": ".build/vendor", + "allow-plugins": { + "typo3/class-alias-loader": true, + "typo3/cms-composer-installers": true + } }, "extra": { "typo3/cms": { @@ -41,12 +45,12 @@ "app-dir": ".build" }, "branch-alias": { - "dev-develop": "11.0.x-dev" + "dev-develop": "12.0.x-dev" } }, "scripts": { "t3g:test:php:lint": [ - "phplint" + "Build/tools/phplint/vendor/bin/phplint" ], "t3g:test:php:unit": [ "phpunit -c Build/UnitTests.xml" @@ -56,26 +60,25 @@ "@t3g:test:php:unit" ], "t3g:cgl": [ - "php-cs-fixer fix --config=.php_cs-fixer.dist.php -v --dry-run" + "Build/tools/php-cs-fixer/vendor/bin/php-cs-fixer fix --config=.php_cs-fixer.dist.php -v --dry-run" ], "t3g:cgl:fix": [ - "php-cs-fixer fix --config=.php_cs-fixer.dist.php" + "Build/tools/php-cs-fixer/vendor/bin/php-cs-fixer fix --config=.php_cs-fixer.dist.php" ], "post-autoload-dump": [ - "mkdir -p .build/web/typo3conf/ext/", - "[ -L .build/web/typo3conf/ext/usercentrics ] || ln -snvf ../../../../. .build/web/typo3conf/ext/usercentrics" + "[ -d .build/public/_assets ] || mkdir -p .build/public/typo3conf/ext/", + "[ -d .build/public/_assets ] || [ -L .build/public/typo3conf/ext/usercentrics ] || ln -snvf ../../../../. .build/public/typo3conf/ext/usercentrics", ] }, "require": { - "php": "^7.2 || ^8.0", + "php": "^7.4 || ^8.0", "ext-json": "*", - "typo3/cms-core": "^10.4 || 11.*.*@dev" + "typo3/cms-core": "^11.4 || 12.4" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^v2.19", "roave/security-advisories": "dev-latest", - "typo3/testing-framework": "^4.9 || ^5.0 || ^6.3", - "bk2k/extension-helper": "^1.0", - "overtrue/phplint": "^3.0" + "typo3/testing-framework": "^7.0 || ^8.0", + "bk2k/extension-helper": "^2.0", + "phpunit/phpunit": "^8.4 || ^9.0" } } diff --git a/ext_emconf.php b/ext_emconf.php index e3f25bb..6ba337e 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -15,10 +15,10 @@ 'clearCacheOnLoad' => 0, 'author' => 'TYPO3 GmbH', 'author_email' => 'info@typo3.com', - 'version' => '11.0.0', + 'version' => '12.0.0', 'constraints' => [ 'depends' => [ - 'typo3' => '11.0.0-11.4.99', + 'typo3' => '11.0.0-12.4.99', ], 'conflicts' => [], 'suggests' => [], diff --git a/ext_localconf.php b/ext_localconf.php index e754c65..be28b93 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -7,14 +7,11 @@ * LICENSE file that was distributed with this source code. */ -if (!defined('TYPO3_MODE')) { +if (!defined('TYPO3')) { die('Access denied.'); } call_user_func(static function () { - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'][\T3G\AgencyPack\Usercentrics\Hooks\PageRendererPreProcess::class] - = \T3G\AgencyPack\Usercentrics\Hooks\PageRendererPreProcess::class . '->addLibrary'; - // Register "usercentrics" as global fluid namespace $GLOBALS['TYPO3_CONF_VARS']['SYS']['fluid']['namespaces']['usercentrics'][] = 'T3G\\AgencyPack\\Usercentrics\\ViewHelpers'; });