Skip to content

Commit

Permalink
[!!!][TASK] Provide TYPO3 v12 compatibility (#35)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
andreaskienast committed Jul 10, 2023
1 parent 7a93335 commit 41c0984
Show file tree
Hide file tree
Showing 15 changed files with 242 additions and 163 deletions.
37 changes: 20 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ var/
config/

# CGL Fixer
.php_cs.cache
.php-cs-fixer.cache
.phplint.cache
2 changes: 1 addition & 1 deletion .php_cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
Expand Down
1 change: 1 addition & 0 deletions .phplint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ extensions:
- php
exclude:
- .build
- Build
5 changes: 5 additions & 0 deletions Build/tools/php-cs-fixer/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"require": {
"friendsofphp/php-cs-fixer": "^3.20"
}
}
5 changes: 5 additions & 0 deletions Build/tools/phplint/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"require": {
"overtrue/phplint": "^3.3 || ^4.5"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
declare(strict_types = 1);
declare(strict_types=1);

/*
* This file is part of the package t3g/usercentrics.
Expand All @@ -8,42 +8,33 @@
* LICENSE file that was distributed with this source code.
*/

namespace T3G\AgencyPack\Usercentrics\Hooks;
namespace T3G\AgencyPack\Usercentrics\EventListener\AssetRenderer;

use TYPO3\CMS\Core\Page\AssetCollector;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Page\Event\BeforeJavaScriptsRenderingEvent;
use TYPO3\CMS\Core\Utility\StringUtility;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;

class PageRendererPreProcess
final class UsercentricsLibrary
{

/**
* @var \TYPO3\CMS\Core\Page\AssetCollector
*/
private $assetCollector;

public function __construct(AssetCollector $assetCollector = null)
public function __invoke(BeforeJavaScriptsRenderingEvent $event): void
{
// hooks: no DI yet :(
$this->assetCollector = $assetCollector ?? GeneralUtility::makeInstance(AssetCollector::class);
}
if ($event->isInline()) {
return;
}

public function addLibrary(): void
{
$config = $this->getTypoScriptConfiguration();
if ($config === null) {
return;
}
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'] ?? '';
Expand All @@ -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)) {
Expand All @@ -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'],
Expand Down Expand Up @@ -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;
Expand All @@ -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'];
}
}
73 changes: 64 additions & 9 deletions Classes/ViewHelpers/ScriptViewHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -25,12 +28,71 @@
* alert('hello world');
* </usercentrics:script>
*/
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 <head> 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);
}

Expand Down Expand Up @@ -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'];
}
}
5 changes: 5 additions & 0 deletions Configuration/Services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 4 additions & 2 deletions Configuration/TCA/Overrides/sys_template.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});
Loading

0 comments on commit 41c0984

Please sign in to comment.