diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..4283b9a
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,64 @@
+name: CI
+
+on: [push, pull_request]
+
+jobs:
+ testsuite:
+
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ TYPO3: [ '11' , '12', '13']
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Set up PHP Version
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 8.1
+ tools: composer:v2
+
+ - name: Start MySQL
+ run: sudo /etc/init.d/mysql start
+
+ - name: Validate composer.json and composer.lock
+ run: composer validate
+
+ - name: Cache dependencies
+ uses: actions/cache@v1
+ with:
+ path: ~/.composer/cache
+ key: dependencies-composer-${{ hashFiles('composer.json') }}
+
+ - name: Install composer dependencies TYPO3 13
+ if: matrix.TYPO3 == '13'
+ run: |
+ composer install --no-progress --no-interaction
+
+ - name: Install composer dependencies TYPO3 12
+ if: matrix.TYPO3 == '12'
+ run: |
+ composer require typo3/cms-core:^12.4 --no-progress --no-interaction --dev -W
+ - name: Install composer dependencies TYPO3 11
+ if: matrix.TYPO3 == '11'
+ run: |
+ composer require typo3/cms-core:^11.5 --no-progress --no-interaction --dev -W
+ - name: Phpstan 12/13
+ if: matrix.TYPO3 != '11'
+ run: .Build/bin/phpstan analyze -c Build/phpstan.neon
+ - name: Phpstan 11
+ if: matrix.TYPO3 == '11'
+ run: .Build/bin/phpstan analyze -c Build/phpstan11.neon
+ - name: Phpcsfix
+ run: .Build/bin/php-cs-fixer fix --config=Build/php-cs-fixer.php --dry-run --stop-on-violation --using-cache=no
+ - name: Unit Tests
+ run: .Build/bin/phpunit -c Build/phpunit/UnitTests.xml Tests/Unit
+ - name: Functional Tests
+ run: |
+ export typo3DatabaseName="typo3";
+ export typo3DatabaseHost="127.0.0.1";
+ export typo3DatabaseUsername="root";
+ export typo3DatabasePassword="root";
+ .Build/bin/phpunit -c Build/phpunit/FunctionalTests.xml Tests/Functional
diff --git a/.gitignore b/.gitignore
index a1ee133..ebbd882 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-/build/
/composer.lock
-/.php_cs.cache
-/public/
\ No newline at end of file
+/Build/phpunit/.phpunit.*
+/public/
+/.Build/
diff --git a/Build/php-cs-fixer.php b/Build/php-cs-fixer.php
new file mode 100644
index 0000000..6ee0307
--- /dev/null
+++ b/Build/php-cs-fixer.php
@@ -0,0 +1,5 @@
+getFinder()->exclude(['var'])->in(__DIR__ . '/..');
+return $config;
diff --git a/Build/phpstan.neon b/Build/phpstan.neon
new file mode 100644
index 0000000..457f990
--- /dev/null
+++ b/Build/phpstan.neon
@@ -0,0 +1,6 @@
+includes:
+ - ../.Build/vendor/saschaegerer/phpstan-typo3/extension.neon
+parameters:
+ level: 5
+ paths:
+ - %currentWorkingDirectory%/Classes
\ No newline at end of file
diff --git a/Build/phpstan11.neon b/Build/phpstan11.neon
new file mode 100644
index 0000000..649a756
--- /dev/null
+++ b/Build/phpstan11.neon
@@ -0,0 +1,8 @@
+includes:
+ - ../.Build/vendor/saschaegerer/phpstan-typo3/extension.neon
+parameters:
+ level: 5
+ paths:
+ - %currentWorkingDirectory%/Classes
+ excludePaths:
+ - %currentWorkingDirectory%/Classes/Listener/AfterCacheableContentIsGenerated.php
diff --git a/Build/phpunit/FunctionalTests.xml b/Build/phpunit/FunctionalTests.xml
new file mode 100644
index 0000000..3c32aa4
--- /dev/null
+++ b/Build/phpunit/FunctionalTests.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ ../../Tests/Functional/
+
+
+
+
+
+
+
diff --git a/Build/phpunit/FunctionalTestsBootstrap.php b/Build/phpunit/FunctionalTestsBootstrap.php
new file mode 100644
index 0000000..443197d
--- /dev/null
+++ b/Build/phpunit/FunctionalTestsBootstrap.php
@@ -0,0 +1,20 @@
+defineOriginalRootPath();
+ $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/tests');
+ $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/transient');
+});
diff --git a/Build/phpunit/UnitTests.xml b/Build/phpunit/UnitTests.xml
new file mode 100644
index 0000000..380f48d
--- /dev/null
+++ b/Build/phpunit/UnitTests.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ ../../Tests/Unit/
+
+
+
+
+
+
+
diff --git a/Build/phpunit/UnitTestsBootstrap.php b/Build/phpunit/UnitTestsBootstrap.php
new file mode 100644
index 0000000..b12ccf0
--- /dev/null
+++ b/Build/phpunit/UnitTestsBootstrap.php
@@ -0,0 +1,74 @@
+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;
+ \TYPO3\CMS\Core\Core\SystemEnvironmentBuilder::run(0, $requestType);
+
+ $testbase->createDirectory(\TYPO3\CMS\Core\Core\Environment::getPublicPath() . '/typo3conf/ext');
+ $testbase->createDirectory(\TYPO3\CMS\Core\Core\Environment::getPublicPath() . '/typo3temp/assets');
+ $testbase->createDirectory(\TYPO3\CMS\Core\Core\Environment::getPublicPath() . '/typo3temp/var/tests');
+ $testbase->createDirectory(\TYPO3\CMS\Core\Core\Environment::getPublicPath() . '/typo3temp/var/transient');
+
+ // Retrieve an instance of class loader and inject to core bootstrap
+ $classLoader = require $testbase->getPackagesPath() . '/autoload.php';
+ \TYPO3\CMS\Core\Core\Bootstrap::initializeClassLoader($classLoader);
+
+ // Initialize default TYPO3_CONF_VARS
+ $configurationManager = new \TYPO3\CMS\Core\Configuration\ConfigurationManager();
+ $GLOBALS['TYPO3_CONF_VARS'] = $configurationManager->getDefaultConfiguration();
+
+ $cache = new \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend(
+ 'core',
+ 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
+ );
+ }
+ \TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance(\TYPO3\CMS\Core\Package\PackageManager::class, $packageManager);
+ \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::setPackageManager($packageManager);
+
+ $testbase->dumpClassLoadingInformation();
+
+ \TYPO3\CMS\Core\Utility\GeneralUtility::purgeInstances();
+});
diff --git a/Classes/AssetCollector.php b/Classes/AssetCollector.php
index 770730f..880d9df 100644
--- a/Classes/AssetCollector.php
+++ b/Classes/AssetCollector.php
@@ -1,6 +1,7 @@
removeUtf8Bom(file_get_contents($absoluteFile));
@@ -183,7 +185,7 @@ public function buildJavaScriptIncludes(): string
$attributeCode[] = htmlspecialchars($name);
}
}
- $webPath = (strpos($file['fileName'], 'EXT:') === 0)
+ $webPath = (str_starts_with($file['fileName'], 'EXT:'))
? PathUtility::getAbsoluteWebPath(GeneralUtility::getFileAbsFileName(($file['fileName'])))
: $file['fileName'];
$includes .= '';
diff --git a/Classes/Hooks/AssetRenderer.php b/Classes/Hooks/AssetRenderer.php
index 96b7d60..a98d87a 100644
--- a/Classes/Hooks/AssetRenderer.php
+++ b/Classes/Hooks/AssetRenderer.php
@@ -1,6 +1,7 @@
getBody();
$body->rewind();
$contents = $response->getBody()->getContents();
- if (strpos($contents, '