diff --git a/.code-quality/phpstan-baseline.neon b/.code-quality/phpstan-baseline.neon index e8005e0d4..c6a8535a8 100644 --- a/.code-quality/phpstan-baseline.neon +++ b/.code-quality/phpstan-baseline.neon @@ -8,14 +8,6 @@ parameters: message: "#^Comparison operation \"\\<\" between int\\<1, max\\> and 1 is always false\\.$#" count: 1 path: ../Classes/System/Configuration/TypoScriptConfiguration.php - - - message: "#^Call to an undefined static method TYPO3\\\\CMS\\\\Core\\\\Utility\\\\GeneralUtility\\:\\:sysLog\\(\\)\\.$#" - count: 1 - path: ../Classes/System/Log/Logger.php - - - message: "#^Relative file path \"tslib/class\\.tslib_fe\\.php\" is not allowed, use absolute one with __DIR__$#" - count: 4 - path: ../Classes/Backend/Utility/HookUtility.php - message: "#^Use value object over return of values$#" count: 2 @@ -28,26 +20,10 @@ parameters: message: "#^Anonymous variable in a `\\$GLOBALS\\['TYPO3_REQUEST'\\]\\-\\>\\.\\.\\.\\(\\)` method call can lead to false dead methods\\. Make sure the variable type is known$#" count: 1 path: ../Classes/System/Configuration/TypoScriptConfiguration.php - - - message: "#^Anonymous variables in a \"\\$GLOBALS\\['TSFE'\\]\\-\\>\\.\\.\\.\" property fetch can lead to false dead property\\. Make sure the variable type is known$#" - count: 1 - path: ../Classes/System/Configuration/TypoScriptConfiguration.php - - - message: "#^Anonymous variables in a \"\\$GLOBALS\\['TSFE'\\]\\-\\>tmpl\\-\\>\\.\\.\\.\" property fetch can lead to false dead property\\. Make sure the variable type is known$#" - count: 1 - path: ../Classes/System/Configuration/TypoScriptConfiguration.php - - - message: "#^Anonymous variable in a `\\$GLOBALS\\['TSFE'\\]\\-\\>\\.\\.\\.\\(\\)` method call can lead to false dead methods\\. Make sure the variable type is known$#" - count: 2 - path: ../Classes/Typo3/Hook/ContentPostProcAll.php - message: "#^Anonymous variable in a `\\$this\\[\\$found\\]\\-\\>\\.\\.\\.\\(\\)` method call can lead to false dead methods\\. Make sure the variable type is known$#" count: 3 path: ../Classes/Domain/Model/Asset/Collection.php - - - message: "#^On passing a constant, the method should have an enum type\\. See https\\://phpstan\\.org/writing\\-php\\-code/phpdoc\\-types\\#literals\\-and\\-constants$#" - count: 1 - path: ../Classes/Api/Url.php - message: "#^Unable to resolve the template type T in call to method static method TYPO3\\\\CMS\\\\Core\\\\Utility\\\\GeneralUtility\\:\\:makeInstance\\(\\)$#" count: 1 diff --git a/.code-quality/phpstan.neon b/.code-quality/phpstan.neon index 22d8534ca..264032be9 100644 --- a/.code-quality/phpstan.neon +++ b/.code-quality/phpstan.neon @@ -8,9 +8,10 @@ parameters: paths: - "../Classes/" + ignoreErrors: + - identifier: missingType.iterableValue + - identifier: missingType.generics inferPrivatePropertyTypeFromConstructor: true - checkMissingIterableValueType: false - checkGenericClassInNonGenericObjectType: false services: - diff --git a/Classes/Backend/Utility/HookUtility.php b/Classes/Backend/Utility/HookUtility.php deleted file mode 100644 index 66d98f1fd..000000000 --- a/Classes/Backend/Utility/HookUtility.php +++ /dev/null @@ -1,54 +0,0 @@ - - * - * All rights reserved - * - * This script is part of the TYPO3 project. The TYPO3 project is - * free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * The GNU General Public License can be found at - * http://www.gnu.org/copyleft/gpl.html. - * - * This script is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This copyright notice MUST APPEAR in all copies of the script! - ***************************************************************/ - -class HookUtility -{ - /** - * Register hooks - */ - public static function registerHooks(): void - { - $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['asdis']); - switch ($extConf['hook']) { - case 'contentPostProc-all': - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-all'][] = ContentPostProcAll::class . '->process'; - break; - case 'contentPostProc-output': - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output'][] = ContentPostProcAll::class . '->process'; - break; - case 'contentPostProc-all_and_output': - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-all'][] = ContentPostProcAll::class . '->processCache'; - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output'][] = ContentPostProcAll::class . '->processNoCache'; - break; - } - - unset($extConf); - } -} diff --git a/Classes/Bootstrap/Typo3Configurator.php b/Classes/Bootstrap/Typo3Configurator.php new file mode 100644 index 000000000..2083ac36d --- /dev/null +++ b/Classes/Bootstrap/Typo3Configurator.php @@ -0,0 +1,27 @@ +')) { + /** + * We must force templateParsing - otherwise the TypoScript (which configures this + * extension) is not available in the frontend, so we can't get the TypoScript here: + * @see \Aoe\Asdis\System\Configuration\TypoScriptConfiguration::getTypoScriptConfigurationArray + */ + $context = GeneralUtility::makeInstance(Context::class); + $context->setAspect('typoscript', GeneralUtility::makeInstance(TypoScriptAspect::class, true)); + } + } +} diff --git a/Classes/Content/Scraper/Html/AbstractHtmlScraper.php b/Classes/Content/Scraper/Html/AbstractHtmlScraper.php index 2bbde5a74..3e0a7bd2e 100644 --- a/Classes/Content/Scraper/Html/AbstractHtmlScraper.php +++ b/Classes/Content/Scraper/Html/AbstractHtmlScraper.php @@ -21,18 +21,6 @@ public function __construct(XmlTagAttribute $xmlTagAttributeExtractor, Factory $ $this->assetFactory = $assetFactory; } - /* - public function injectXmlTagAttributeExtractor(XmlTagAttribute $xmlTagAttributeExtractor): void - { - $this->xmlTagAttributeExtractor = $xmlTagAttributeExtractor; - } - - public function injectAssetFactory(Factory $assetFactory): void - { - $this->assetFactory = $assetFactory; - } - */ - protected function getAssets(string $tagName, string $attributeName, string $content, array $requiredOtherAttributes = []): ?Collection { $attributes = $this->xmlTagAttributeExtractor->getAttributeFromTag( diff --git a/Classes/Content/Scraper/Html/Image.php b/Classes/Content/Scraper/Html/Image.php index 35d637ee2..c1dee39da 100644 --- a/Classes/Content/Scraper/Html/Image.php +++ b/Classes/Content/Scraper/Html/Image.php @@ -17,6 +17,15 @@ public function scrape(string $content): ?Collection ->merge($this->getAssets('image', 'href', $content)) ->merge($this->getAssets('link', 'href', $content, [ 'type' => 'image/gif', + ])) + ->merge($this->getAssets('link', 'href', $content, [ + 'type' => 'image/webp', + ])) + ->merge($this->getAssets('link', 'href', $content, [ + 'type' => 'image/png', + ])) + ->merge($this->getAssets('link', 'href', $content, [ + 'type' => 'image/jpeg', ])); } } diff --git a/Classes/Middleware/ContentPostProcAll.php b/Classes/Middleware/ContentPostProcAll.php index 0f0abe5db..43633b416 100644 --- a/Classes/Middleware/ContentPostProcAll.php +++ b/Classes/Middleware/ContentPostProcAll.php @@ -45,7 +45,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $status = $response->getStatusCode(); try { - $this->setPageObject($GLOBALS['TSFE']); + $this->setPageObject($this->getTsfe()); $this->scrapeAndReplace(); $header['Content-Length'] = strlen($this->page->getPageObject()->content); @@ -58,6 +58,13 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface return $response; } + protected function getTsfe(): TypoScriptFrontendController + { + /** @var ServerRequestInterface $typo3Request */ + $typo3Request = $GLOBALS['TYPO3_REQUEST']; + return $typo3Request->getAttribute('frontend.controller'); + } + protected function scrapeAssets(): void { $this->page->scrapeAssets(); diff --git a/Classes/System/Configuration/Provider.php b/Classes/System/Configuration/Provider.php index daf48ff76..1189d7215 100644 --- a/Classes/System/Configuration/Provider.php +++ b/Classes/System/Configuration/Provider.php @@ -16,13 +16,6 @@ public function __construct(TypoScriptConfiguration $typoScriptConfiguration) $this->typoScriptConfiguration = $typoScriptConfiguration; } - /* - public function injectTypoScriptConfiguration(TypoScriptConfiguration $typoScriptConfiguration): void - { - $this->typoScriptConfiguration = $typoScriptConfiguration; - } - */ - /** * Tells if the assets on the current page should be replaced. */ diff --git a/Classes/System/Configuration/TypoScriptConfiguration.php b/Classes/System/Configuration/TypoScriptConfiguration.php index 8d08d0d39..12a619cd2 100644 --- a/Classes/System/Configuration/TypoScriptConfiguration.php +++ b/Classes/System/Configuration/TypoScriptConfiguration.php @@ -5,9 +5,11 @@ use Aoe\Asdis\System\Configuration\Exception\InvalidTypoScriptSetting; use Aoe\Asdis\System\Configuration\Exception\SiteNotFoundException; use Aoe\Asdis\System\Configuration\Exception\TypoScriptSettingNotExists; +use Psr\Http\Message\ServerRequestInterface; use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Core\Site\Entity\Site; use TYPO3\CMS\Core\Site\SiteFinder; +use TYPO3\CMS\Core\TypoScript\FrontendTypoScript; use TYPO3\CMS\Core\TypoScript\TemplateService; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\RootlineUtility; @@ -69,10 +71,25 @@ public function getSetting($key, $validateType = '', $hasSubkeys = false) */ protected function getTypoScriptConfigurationArray() { - if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9.5.0', '<')) { - return $GLOBALS['TSFE']->tmpl->setup['config.']['tx_asdis.']; + if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '12.4.0', '>')) { + if (isset($GLOBALS['TYPO3_REQUEST']) && + $GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface && + $GLOBALS['TYPO3_REQUEST']->getAttribute('frontend.typoscript') instanceof FrontendTypoScript) { + /** + * We can get the TypoScript in the frontend, because we force templateParsing (without + * forcing of templateParsing, we can't get the complete TypoScript in frontend) here: + * @see \Aoe\Asdis\Bootstrap\Typo3Configurator::forceTemplateParsingInFrontend + */ + $fullTypoScript = $GLOBALS['TYPO3_REQUEST']->getAttribute('frontend.typoscript')->getSetupArray(); + return $fullTypoScript['config.']['tx_asdis.']; + } + + return []; } + /** + * This code is for TYPO3v11 - we can remove it, when we don't support TYPO3v11 anymore! + */ $site = $this->getCurrentSite(); /** @var RootlineUtility $rootlineUtility */ diff --git a/Classes/System/Log/Logger.php b/Classes/System/Log/Logger.php index 181d452da..975a0d790 100644 --- a/Classes/System/Log/Logger.php +++ b/Classes/System/Log/Logger.php @@ -7,7 +7,6 @@ use TYPO3\CMS\Core\Log\LogManager; use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Core\Utility\VersionNumberUtility; /** * System logger. @@ -18,26 +17,10 @@ class Logger implements SingletonInterface public function logException(string $context, Exception $e): void { - if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9.5.0', '<')) { - $this->syslog( - 'Exception occured ' . PHP_EOL . - ' Code: ' . $e->getCode() . PHP_EOL . - ' Message: "' . $e->getMessage() . '"' . PHP_EOL . - ' Trace:' . PHP_EOL . $e->getTraceAsString(), - 4 - ); - return; - } - $this->logger = GeneralUtility::makeInstance(LogManager::class)->getLogger(self::class); $this->logger->error( $context . ': ' . $e->getMessage(), $e->getTrace() ); } - - private function syslog(string $message, int $severity): void - { - GeneralUtility::sysLog($message, 'asdis', $severity); - } } diff --git a/Classes/Typo3/Hook/AbstractHook.php b/Classes/Typo3/Hook/AbstractHook.php deleted file mode 100644 index b4ab27714..000000000 --- a/Classes/Typo3/Hook/AbstractHook.php +++ /dev/null @@ -1,66 +0,0 @@ -configurationProvider = GeneralUtility::makeInstance(Provider::class); - $this->logger = GeneralUtility::makeInstance(Logger::class); - } - - protected function getConfigurationProvider(): Provider - { - return $this->configurationProvider; - } - - protected function getLogger(): Logger - { - return $this->logger; - } - - protected function scrapeAssets(): void - { - $this->page->scrapeAssets(); - } - - protected function replaceAssets(): void - { - $this->page->replaceAssets(); - } - - /** - * Scrapes and replaces the assets of the current page. - */ - protected function scrapeAndReplace(): void - { - $this->scrapeAssets(); - $this->replaceAssets(); - } - - protected function setPageObject(TypoScriptFrontendController $pObj): void - { - /** @var Page $page */ - $page = GeneralUtility::makeInstance(Page::class); - $page->setAssets(GeneralUtility::makeInstance(Collection::class)); - $page->setPageObject($pObj); - $this->page = $page; - } -} diff --git a/Classes/Typo3/Hook/ContentPostProcAll.php b/Classes/Typo3/Hook/ContentPostProcAll.php deleted file mode 100644 index ea456a51d..000000000 --- a/Classes/Typo3/Hook/ContentPostProcAll.php +++ /dev/null @@ -1,58 +0,0 @@ -getConfigurationProvider()->isDefaultHookHandlingDisabled()) { - return; - } - - if ($pObj === null) { - if (isset($params['pObj']) && ($params['pObj'] instanceof TypoScriptFrontendController)) { - $pObj = $params['pObj']; - } else { - $pObj = $GLOBALS['TSFE']; - } - } - - try { - $this->setPageObject($pObj); - $this->scrapeAndReplace(); - } catch (Exception $exception) { - $this->getLogger() - ->logException(__METHOD__, $exception); - } - } - - /** - * Call main process hook function only if there are no INTincScripts to include. - * This function is called as contentPostProc-all hook. - */ - public function processCache(array &$params, TypoScriptFrontendController $pObj = null): void - { - if ($GLOBALS['TSFE']->isINTincScript()) { - return; - } - - $this->process($params, $pObj); - } - - /** - * Call main process hook function only if there are INTincScripts to include. - * This function is called as contentPostProc-output hook. - */ - public function processNoCache(array &$params, TypoScriptFrontendController $pObj = null): void - { - if (!$GLOBALS['TSFE']->isINTincScript()) { - return; - } - - $this->process($params, $pObj); - } -} diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index 4546f71d8..677c5fd15 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -57,3 +57,11 @@ services: Aoe\Asdis\Content\Scraper\Html\Srcset: public: true + + # EventListeners + Aoe\Asdis\Bootstrap\Typo3Configurator: + tags: + - name: event.listener + identifier: 'asdis/typo3-configurator' + method: 'forceTemplateParsingInFrontend' + event: TYPO3\CMS\Core\Core\Event\BootCompletedEvent \ No newline at end of file diff --git a/Documentation/Images/AdministratorManual/AsdisConfig1.png b/Documentation/Images/AdministratorManual/AsdisConfig1.png deleted file mode 100644 index ce28dc45f..000000000 Binary files a/Documentation/Images/AdministratorManual/AsdisConfig1.png and /dev/null differ diff --git a/Documentation/Pages/AdministratorManual.rst b/Documentation/Pages/AdministratorManual.rst index aff613cfd..7092d150c 100644 --- a/Documentation/Pages/AdministratorManual.rst +++ b/Documentation/Pages/AdministratorManual.rst @@ -6,25 +6,6 @@ .. include:: ../Includes.txt -.. _admin-manual: - -Administrator Manual -==================== - -The first thing you have to decide, when installing asdis, is the exact moment you want to replace the URLs to your CDN. - -Your options are: - -- Before Storing in cache (contentPostProc-all) (recommended) - -- Before outputting the content to the browser (contentPostProc-output) - -- Non INTincScripts before storing in cache (contentPostProc-all) + INTincScripts before outputting the content to the browser (contentPostProc-output) - -The description in your backend explains your options very well: - -.. image:: /Images/AdministratorManual/AsdisConfig1.png - ---------- Activation ---------- diff --git a/Tests/Content/Scraper/Html/ImageTest.php b/Tests/Content/Scraper/Html/ImageTest.php index 04265a2e2..641e0ca17 100644 --- a/Tests/Content/Scraper/Html/ImageTest.php +++ b/Tests/Content/Scraper/Html/ImageTest.php @@ -17,14 +17,14 @@ public function testScrape(): void $assetFactory = $this->getMockBuilder(Factory::class)->getMock(); $assetFactory - ->expects($this->exactly(3)) + ->expects($this->exactly(6)) ->method('createAssetsFromPaths') ->with(['uploads/tx_templavoila/example.gif']) ->willReturn(new Collection()); $attributeExtractor = $this->getMockBuilder(XmlTagAttribute::class)->getMock(); $attributeExtractor - ->expects($this->exactly(3)) + ->expects($this->exactly(6)) ->method('getAttributeFromTag') ->willReturn([ 'paths' => ['uploads/tx_templavoila/example.gif'], diff --git a/composer.json b/composer.json index 701db7ba9..e39f1c932 100644 --- a/composer.json +++ b/composer.json @@ -67,7 +67,7 @@ "TYPO3_PATH_ROOT=.Build/Web .Build/bin/phpunit --colors -c .Build/vendor/typo3/testing-framework/Resources/Core/Build/UnitTests.xml Tests" ], "code-style": [ - "[ -e ./.Build/bin/rector ] || composer install", + "[ -e ./.Build/bin/rector ] || composer update", "./.Build/bin/ecs check --config .code-quality/ecs.php", "./.Build/bin/rector process --dry-run --config .code-quality/rector.php" ], @@ -78,7 +78,7 @@ "./.Build/bin/phpstan analyse -c .code-quality/phpstan.neon --memory-limit=1G --generate-baseline" ], "code-compatibility": [ - "[ -e ./.Build/vendor/symplify/easy-coding-standard/vendor/squizlabs/php_codesniffer/bin/phpcs ] || composer install", + "[ -e ./.Build/vendor/symplify/easy-coding-standard/vendor/squizlabs/php_codesniffer/bin/phpcs ] || composer update", "[ -d ./reports/php_checkstyle ] || mkdir -p reports/php_checkstyle/", "./.code-quality/configure-checkstyle.sh", "./.Build/vendor/symplify/easy-coding-standard/vendor/squizlabs/php_codesniffer/bin/phpcs -d memory_limit=1G --standard=PHPCompatibility --colors --ignore=*/.Build/* -p . --runtime-set testVersion 8.0", diff --git a/ext_conf_template.txt b/ext_conf_template.txt deleted file mode 100644 index 68e66975a..000000000 --- a/ext_conf_template.txt +++ /dev/null @@ -1,2 +0,0 @@ -# cat=basic; type=options[Before Storing in cache (contentPostProc-all)=contentPostProc-all,Before outputting the content to the browser (contentPostProc-output)=contentPostProc-output,Non INTincScripts before storing in cache (contentPostProc-all) + INTincScripts before outputting the content to the browser (contentPostProc-output)=contentPostProc-all_and_output]; label=Which Hook should be used: The "contentPostProc-output" hook is called before the page will be outputted to the browser. The result of replacing the assets will not be cached. But therefore you can replace much more assets than before storing the content within the cache. That is because of the fact, that some other extensions changing the output within this hook too and adds some additional assets to the output. The "contentPostProc-all" is used before the content is is stored within the cache. Be careful with using the "contentPostProc-output" hook since this is much more expensive for the site performance. Another option is to use a combination of both hooks. Here the "contentPostProc-all" hook is used for pages without INTincScripts. However, pages with INTincScripts scripts still contain unreplaced markers so their actual content can not be processed at that time. So for pages with INTincScripts scripts the "contentPostProc-output" hook is used. -hook=contentPostProc-all diff --git a/ext_emconf.php b/ext_emconf.php index 8d4005960..021e246c1 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -19,10 +19,10 @@ 'clearCacheOnLoad' => 0, 'lockType' => '', 'author_company' => 'AOE GmbH', - 'version' => '11.0.17', + 'version' => '11.1.0', 'constraints' => [ 'depends' => [ - 'typo3' => '8.7.30-11.5.99', + 'typo3' => '11.5.0-12.9.99', ], 'conflicts' => [], 'suggests' => [], diff --git a/ext_localconf.php b/ext_localconf.php index 62146e548..66fb2e712 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -1,7 +1,6 @@