From 3feda71938c936e3d267119ee84446d1803d9172 Mon Sep 17 00:00:00 2001 From: Leo Feyer Date: Fri, 4 Dec 2020 14:54:39 +0100 Subject: [PATCH] Add compatibility with PHP 8 (see #2535) Description ----------- See #2263 and #2291 ### TODO * [x] Fix the tests. * [x] Wait if https://github.com/sebastianbergmann/php-code-coverage/pull/837 gets merged and then use PHPUnit 8.5 for all PHP versions. * [ ] Click through the back end and front end and fix all warnings. Commits ------- 8ad61492 Add PHP 8.0 to the CI chain 7b8729e5 Fix the unit and functional tests 47c14dbb Use 127.0.0.1 instead of localhost in the functional tests 938836c0 Always set the ACCEPT_LANGUAGE header in the functional tests a4199ec2 Use PHPUnit 8.5 for all PHP versions 7ffbd267 Adjust the error level in PHP 8 4ce6b27b Merge branch '4.9' into fix/php8 --- .github/workflows/ci.yml | 76 +++++++++++++------ calendar-bundle/composer.json | 4 +- comments-bundle/composer.json | 2 +- composer.json | 4 +- core-bundle/composer.json | 4 +- .../src/DependencyInjection/Configuration.php | 17 ++++- .../contao/library/Contao/DcaExtractor.php | 8 +- .../contao/library/Contao/GdImage.php | 10 ++- .../contao/library/Contao/InsertTags.php | 6 ++ .../contao/library/Contao/Widget.php | 2 +- .../tests/Contao/Database/ResultTest.php | 7 +- core-bundle/tests/Contao/GdImageTest.php | 21 +++-- core-bundle/tests/Functional/RoutingTest.php | 3 + faq-bundle/composer.json | 4 +- installation-bundle/composer.json | 4 +- listing-bundle/composer.json | 2 +- manager-bundle/composer.json | 4 +- news-bundle/composer.json | 4 +- newsletter-bundle/composer.json | 2 +- 19 files changed, 129 insertions(+), 55 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9b60838e8b5..f8e759a624c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,16 +19,16 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 7.3 + php-version: 7.4 extensions: dom, fileinfo, filter, gd, hash, intl, json, mbstring, pcre, pdo, zlib - tools: prestissimo, flex + tools: flex coverage: pcov - name: Checkout uses: actions/checkout@v1 - name: Install the dependencies - run: composer install --no-interaction --no-suggest + run: composer install --no-interaction - name: Generate the coverage report run: php -d pcov.enabled=1 vendor/bin/phpunit --testsuite=coverage --coverage-clover=clover.xml --colors=always @@ -47,16 +47,16 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 7.3 + php-version: 7.4 extensions: dom, fileinfo, filter, gd, hash, intl, json, mbstring, pcre, pdo, zlib - tools: prestissimo, flex + tools: flex coverage: none - name: Checkout uses: actions/checkout@v1 - name: Install the dependencies - run: composer install --no-interaction --no-suggest + run: composer install --no-interaction - name: Check the coding style run: | @@ -87,7 +87,39 @@ jobs: with: php-version: ${{ matrix.php }} extensions: dom, fileinfo, filter, gd, hash, intl, json, mbstring, pcre, pdo_mysql, zlib - tools: prestissimo, flex + tools: flex + coverage: none + + - name: Initialize the database + run: | + sudo /etc/init.d/mysql start + mysql -uroot -proot -e "CREATE database contao_test" + + - name: Checkout + uses: actions/checkout@v1 + + - name: Install the dependencies + run: composer install --no-interaction + + - name: Run the unit tests + run: vendor/bin/phpunit --colors=always + + - name: Run the functional tests + run: vendor/bin/phpunit --testsuite=functional --colors=always + env: + DATABASE_URL: mysql://root:root@127.0.0.1:3306/contao_test + + php8: + name: PHP 8.0 + runs-on: ubuntu-latest + if: github.event_name != 'push' + steps: + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.0 + extensions: dom, fileinfo, filter, gd, hash, intl, json, mbstring, pcre, pdo_mysql, zlib + tools: flex coverage: none - name: Initialize the database @@ -99,7 +131,7 @@ jobs: uses: actions/checkout@v1 - name: Install the dependencies - run: composer install --no-interaction --no-suggest + run: composer install --ignore-platform-reqs --no-interaction - name: Run the unit tests run: vendor/bin/phpunit --colors=always @@ -107,7 +139,7 @@ jobs: - name: Run the functional tests run: vendor/bin/phpunit --testsuite=functional --colors=always env: - DATABASE_URL: mysql://root:root@localhost:3306/contao_test + DATABASE_URL: mysql://root:root@127.0.0.1:3306/contao_test prefer-lowest: name: Prefer Lowest @@ -119,7 +151,7 @@ jobs: with: php-version: 7.3 extensions: dom, fileinfo, filter, gd, hash, intl, json, mbstring, pcre, pdo_mysql, zlib - tools: prestissimo, flex + tools: flex coverage: none - name: Initialize the database @@ -131,7 +163,7 @@ jobs: uses: actions/checkout@v1 - name: Install the dependencies - run: composer update --prefer-lowest --prefer-stable --no-interaction --no-suggest + run: composer update --prefer-lowest --prefer-stable --no-interaction - name: Run the unit tests run: vendor/bin/phpunit --colors=always @@ -139,7 +171,7 @@ jobs: - name: Run the functional tests run: vendor/bin/phpunit --testsuite=functional --colors=always env: - DATABASE_URL: mysql://root:root@localhost:3306/contao_test + DATABASE_URL: mysql://root:root@127.0.0.1:3306/contao_test bundles: name: Bundles @@ -149,9 +181,9 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 7.3 + php-version: 7.4 extensions: dom, fileinfo, filter, gd, hash, intl, json, mbstring, pcre, pdo, zlib - tools: prestissimo, flex + tools: flex coverage: none - name: Checkout @@ -174,7 +206,7 @@ jobs: } file_put_contents(__DIR__."/composer.json", json_encode($data, JSON_UNESCAPED_SLASHES)); ' - COMPOSER_ROOT_VERSION=dev-${{ env.GITHUB_SHA }} composer install --no-interaction --no-suggest + COMPOSER_ROOT_VERSION=dev-${{ env.GITHUB_SHA }} composer install --no-interaction vendor/bin/phpunit --colors=always cd .. done @@ -187,10 +219,10 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 7.3 + php-version: 7.4 extensions: dom, fileinfo, filter, gd, hash, intl, json, mbstring, mysqli, pcre, pdo_mysql, zlib ini-values: memory_limit=1G - tools: prestissimo, flex + tools: flex coverage: none - name: Adjust the Git autocrlf setting @@ -200,7 +232,7 @@ jobs: uses: actions/checkout@v1 - name: Install the dependencies - run: composer install --no-interaction --no-suggest --no-progress + run: composer install --no-interaction --no-progress - name: Run the unit tests run: vendor/bin/phpunit.bat --colors=always @@ -213,9 +245,8 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 7.3 + php-version: 7.4 extensions: json, zlib - tools: prestissimo coverage: none - name: Checkout @@ -224,7 +255,7 @@ jobs: - name: Install the dependencies run: | composer global require contao/monorepo-tools:dev-master - composer install --no-interaction --no-suggest + composer install --no-interaction - name: Validate the composer.json files run: $HOME/.composer/vendor/bin/monorepo-tools composer-json --validate --ansi @@ -237,9 +268,8 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 7.3 + php-version: 7.4 extensions: json, zlib - tools: prestissimo coverage: none - name: Checkout diff --git a/calendar-bundle/composer.json b/calendar-bundle/composer.json index 74d28d268bb..3a035d52697 100644 --- a/calendar-bundle/composer.json +++ b/calendar-bundle/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.2", + "php": "^7.2 || ^8.0", "contao/core-bundle": "self.version", "friendsofsymfony/http-cache": "^2.4", "patchwork/utf8": "^1.2", @@ -32,7 +32,7 @@ "require-dev": { "contao/manager-plugin": "^2.3.1", "contao/test-case": "^4.0", - "phpunit/phpunit": "^8.4", + "phpunit/phpunit": "^8.5", "symfony/http-client": "4.4.*", "symfony/phpunit-bridge": "4.4.*" }, diff --git a/comments-bundle/composer.json b/comments-bundle/composer.json index 8f2d727f165..a554b97e7ed 100644 --- a/comments-bundle/composer.json +++ b/comments-bundle/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.2", + "php": "^7.2 || ^8.0", "contao/core-bundle": "self.version", "patchwork/utf8": "^1.2", "symfony/http-kernel": "4.4.*" diff --git a/composer.json b/composer.json index 20f15740321..13a31be6981 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.2", + "php": "^7.2 || ^8.0", "ext-dom": "*", "ext-gd": "*", "ext-hash": "*", @@ -148,7 +148,7 @@ "contao/test-case": "^4.0", "doctrine/event-manager": "^1.0", "monolog/monolog": "^1.24", - "phpunit/phpunit": "^8.4", + "phpunit/phpunit": "^8.5", "psr/event-dispatcher": "^1.0", "slam/phpstan-extensions": "^5.0", "symfony/browser-kit": "4.4.*", diff --git a/core-bundle/composer.json b/core-bundle/composer.json index 9c2443f1303..d8350f32d86 100644 --- a/core-bundle/composer.json +++ b/core-bundle/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.2", + "php": "^7.2 || ^8.0", "ext-dom": "*", "ext-gd": "*", "ext-hash": "*", @@ -120,7 +120,7 @@ "doctrine/event-manager": "^1.0", "lexik/maintenance-bundle": "^2.1.5", "monolog/monolog": "^1.24", - "phpunit/phpunit": "^8.4", + "phpunit/phpunit": "^8.5", "psr/event-dispatcher": "^1.0", "symfony/browser-kit": "4.4.*", "symfony/http-client": "4.4.*", diff --git a/core-bundle/src/DependencyInjection/Configuration.php b/core-bundle/src/DependencyInjection/Configuration.php index 32c37dad210..b5b432eead4 100644 --- a/core-bundle/src/DependencyInjection/Configuration.php +++ b/core-bundle/src/DependencyInjection/Configuration.php @@ -57,10 +57,10 @@ public function getConfigTreeBuilder(): TreeBuilder ->defaultValue('%kernel.secret%') ->end() ->integerNode('error_level') - ->info('The error reporting level set when the framework is initialized. Defaults to E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_USER_DEPRECATED.') + ->info('The error reporting level set when the framework is initialized.') ->min(-1) ->max(32767) - ->defaultValue(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_USER_DEPRECATED) + ->defaultValue($this->getErrorLevel()) ->end() ->variableNode('localconfig') ->info('Allows to set TL_CONFIG variables, overriding settings stored in localconfig.php. Changes in the Contao back end will not have any effect.') @@ -456,6 +456,19 @@ private function canonicalize(string $value): string return rtrim(implode('', $resolved), '\/'); } + private function getErrorLevel(): int + { + if (PHP_MAJOR_VERSION < 8) { + return E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_USER_DEPRECATED; + } + + // Disable E_WARNING in PHP 8, because a number of notices have been + // converted into warnings and now cause a lot of issues with undefined + // array keys and undefined properties. + // @see https://www.php.net/manual/de/migration80.incompatible.php + return E_ALL & ~E_WARNING & ~E_NOTICE & ~E_DEPRECATED & ~E_USER_DEPRECATED; + } + /** * @return array */ diff --git a/core-bundle/src/Resources/contao/library/Contao/DcaExtractor.php b/core-bundle/src/Resources/contao/library/Contao/DcaExtractor.php index 0391db08499..37ba47d068b 100644 --- a/core-bundle/src/Resources/contao/library/Contao/DcaExtractor.php +++ b/core-bundle/src/Resources/contao/library/Contao/DcaExtractor.php @@ -406,7 +406,13 @@ protected function createExtract() // Check whether there is a relation (see #6524) if (isset($config['relation'])) { - $table = substr($config['foreignKey'], 0, strrpos($config['foreignKey'], '.')); + $table = null; + + if (isset($config['foreignKey'])) + { + $table = substr($config['foreignKey'], 0, strrpos($config['foreignKey'], '.')); + } + $arrRelations[$field] = array_merge(array('table'=>$table, 'field'=>'id'), $config['relation']); // Store the field delimiter if the related IDs are stored in CSV format (see #257) diff --git a/core-bundle/src/Resources/contao/library/Contao/GdImage.php b/core-bundle/src/Resources/contao/library/Contao/GdImage.php index b76f1d6f5c9..1dcef830c5d 100644 --- a/core-bundle/src/Resources/contao/library/Contao/GdImage.php +++ b/core-bundle/src/Resources/contao/library/Contao/GdImage.php @@ -129,7 +129,7 @@ public function getResource() /** * Set the GD resource handle * - * @param resource $gdResource The GD resource handle + * @param \GdImage|resource $gdResource The GD resource handle * * @return static * @@ -137,7 +137,7 @@ public function getResource() */ public function setResource($gdResource) { - if (!\is_resource($gdResource) || get_resource_type($gdResource) !== 'gd') + if (!$gdResource instanceof \GdImage && (!\is_resource($gdResource) || get_resource_type($gdResource) !== 'gd')) { throw new \InvalidArgumentException('$gdResource is not a valid GD resource'); } @@ -397,4 +397,8 @@ public function __destruct() } } -class_alias(GdImage::class, 'GdImage'); +// PHP 8.0 compatibility +if (!class_exists('GdImage')) +{ + class_alias(GdImage::class, 'GdImage'); +} diff --git a/core-bundle/src/Resources/contao/library/Contao/InsertTags.php b/core-bundle/src/Resources/contao/library/Contao/InsertTags.php index 6d88fdac5f8..4d4fef8b0a9 100644 --- a/core-bundle/src/Resources/contao/library/Contao/InsertTags.php +++ b/core-bundle/src/Resources/contao/library/Contao/InsertTags.php @@ -105,6 +105,12 @@ protected function doReplace($strBuffer, $blnCache) for ($_rit=0, $_cnt=\count($tags); $_rit<$_cnt; $_rit+=2) { $strBuffer .= $tags[$_rit]; + + if (!isset($tags[$_rit+1])) + { + continue; + } + $strTag = $tags[$_rit+1]; // Skip empty tags diff --git a/core-bundle/src/Resources/contao/library/Contao/Widget.php b/core-bundle/src/Resources/contao/library/Contao/Widget.php index e8e004f096c..bba17d529f9 100644 --- a/core-bundle/src/Resources/contao/library/Contao/Widget.php +++ b/core-bundle/src/Resources/contao/library/Contao/Widget.php @@ -780,7 +780,7 @@ protected function getPost($strKey) break; } - $varValue = $varValue[$part]; + $varValue = $varValue[$part] ?? null; } return $varValue; diff --git a/core-bundle/tests/Contao/Database/ResultTest.php b/core-bundle/tests/Contao/Database/ResultTest.php index e329c2b7b6a..19c13a54dbb 100644 --- a/core-bundle/tests/Contao/Database/ResultTest.php +++ b/core-bundle/tests/Contao/Database/ResultTest.php @@ -15,6 +15,7 @@ use Contao\CoreBundle\Tests\Fixtures\Database\DoctrineArrayStatement; use Contao\Database\Result; use PHPUnit\Framework\Error\Notice; +use PHPUnit\Framework\Error\Warning; use PHPUnit\Framework\TestCase; class ResultTest extends TestCase @@ -52,7 +53,7 @@ public function testEmptyResult(): void } } - $this->expectException(Notice::class); + $this->expectException(PHP_MAJOR_VERSION < 8 ? Notice::class : Warning::class); $resultStatement->fetchField(); } @@ -95,7 +96,7 @@ public function testSingleRow(): void $this->assertSame('value1', $result->fetchField(0)); } - $this->expectException(Notice::class); + $this->expectException(PHP_MAJOR_VERSION < 8 ? Notice::class : Warning::class); $result->fetchField(1); } @@ -143,7 +144,7 @@ public function testMultipleRows(): void $this->assertSame('value2', $result->fetchField(0)); } - $this->expectException(Notice::class); + $this->expectException(PHP_MAJOR_VERSION < 8 ? Notice::class : Warning::class); $result->fetchField(1); } diff --git a/core-bundle/tests/Contao/GdImageTest.php b/core-bundle/tests/Contao/GdImageTest.php index 441655f0b29..08042a39cfc 100644 --- a/core-bundle/tests/Contao/GdImageTest.php +++ b/core-bundle/tests/Contao/GdImageTest.php @@ -36,14 +36,14 @@ public function testCreatesImagesFromResources(): void $resource = imagecreate(1, 1); $image = new GdImage($resource); - $this->assertIsResource($image->getResource()); + $this->assertIsGdResource($image->getResource()); } public function testCreatesImagesFromDimensions(): void { $image = GdImage::fromDimensions(100, 100); - $this->assertIsResource($image->getResource()); + $this->assertIsGdResource($image->getResource()); $this->assertTrue(imageistruecolor($image->getResource())); $this->assertSame(100, imagesx($image->getResource())); $this->assertSame(100, imagesy($image->getResource())); @@ -75,7 +75,7 @@ public function testCreatesImagesFromFiles(string $type): void $image = GdImage::fromFile(new File('test.'.$type)); - $this->assertIsResource($image->getResource()); + $this->assertIsGdResource($image->getResource()); $this->assertSame(100, imagesx($image->getResource())); $this->assertSame(100, imagesy($image->getResource())); } @@ -180,7 +180,7 @@ public function testConvertsImagesToPaletteImages(): void $image = new GdImage($image); $image->convertToPaletteImage(); - $this->assertIsResource($image->getResource()); + $this->assertIsGdResource($image->getResource()); $this->assertFalse(imageistruecolor($image->getResource())); $this->assertSame( @@ -213,7 +213,7 @@ public function testConvertsTrueColorImagesToPaletteImages(): void $image = new GdImage($image); $image->convertToPaletteImage(); - $this->assertIsResource($image->getResource()); + $this->assertIsGdResource($image->getResource()); $this->assertFalse(imageistruecolor($image->getResource())); $this->assertSame(256, imagecolorstotal($image->getResource())); @@ -263,4 +263,15 @@ public function testRecognizesSemitransparentImages(): void imagefill($image->getResource(), 0, 0, imagecolorallocatealpha($image->getResource(), 0, 0, 0, 0)); $this->assertFalse($image->isSemitransparent()); } + + private function assertIsGdResource($resource): void + { + if (\is_object($resource)) { + // PHP >= 8.0 + $this->assertInstanceOf(\GdImage::class, $resource); + } else { + // PHP <= 7.4 + $this->assertIsResource($resource); + } + } } diff --git a/core-bundle/tests/Functional/RoutingTest.php b/core-bundle/tests/Functional/RoutingTest.php index 6bda6ac3e7f..4a71508eadd 100644 --- a/core-bundle/tests/Functional/RoutingTest.php +++ b/core-bundle/tests/Functional/RoutingTest.php @@ -58,6 +58,7 @@ public function testResolvesAliases(string $request, int $statusCode, string $pa $_SERVER['REQUEST_URI'] = $request; $_SERVER['HTTP_HOST'] = $host; + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'en'; $client = $this->createClient([], $_SERVER); System::setContainer($client->getContainer()); @@ -317,6 +318,7 @@ public function testResolvesAliasesWithLocale(string $request, int $statusCode, $_SERVER['REQUEST_URI'] = $request; $_SERVER['HTTP_HOST'] = $host; + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'en'; $client = $this->createClient(['environment' => 'locale'], $_SERVER); System::setContainer($client->getContainer()); @@ -565,6 +567,7 @@ public function testResolvesAliasesWithoutUrlSuffix(string $request, int $status $_SERVER['REQUEST_URI'] = $request; $_SERVER['HTTP_HOST'] = $host; + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'en'; $client = $this->createClient(['environment' => 'suffix'], $_SERVER); System::setContainer($client->getContainer()); diff --git a/faq-bundle/composer.json b/faq-bundle/composer.json index e464626a88d..8e414785691 100644 --- a/faq-bundle/composer.json +++ b/faq-bundle/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.2", + "php": "^7.2 || ^8.0", "contao/core-bundle": "self.version", "patchwork/utf8": "^1.2", "symfony/config": "4.4.*", @@ -30,7 +30,7 @@ "require-dev": { "contao/manager-plugin": "^2.3.1", "contao/test-case": "^4.0", - "phpunit/phpunit": "^8.4", + "phpunit/phpunit": "^8.5", "symfony/http-client": "4.4.*", "symfony/phpunit-bridge": "4.4.*" }, diff --git a/installation-bundle/composer.json b/installation-bundle/composer.json index a2996f33920..f1cf566e448 100644 --- a/installation-bundle/composer.json +++ b/installation-bundle/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.2", + "php": "^7.2 || ^8.0", "contao/core-bundle": "self.version", "doctrine/dbal": "^2.10", "patchwork/utf8": "^1.2", @@ -37,7 +37,7 @@ }, "require-dev": { "contao/manager-plugin": "^2.3.1", - "phpunit/phpunit": "^8.4", + "phpunit/phpunit": "^8.5", "symfony/http-client": "4.4.*", "symfony/phpunit-bridge": "4.4.*" }, diff --git a/listing-bundle/composer.json b/listing-bundle/composer.json index db82c52006d..d8a0ffeb696 100644 --- a/listing-bundle/composer.json +++ b/listing-bundle/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.2", + "php": "^7.2 || ^8.0", "contao/core-bundle": "self.version", "patchwork/utf8": "^1.2", "symfony/http-kernel": "4.4.*" diff --git a/manager-bundle/composer.json b/manager-bundle/composer.json index 39f87814076..42cc7a78c3b 100644 --- a/manager-bundle/composer.json +++ b/manager-bundle/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.2", + "php": "^7.2 || ^8.0", "ext-json": "*", "contao/core-bundle": "self.version", "contao/installation-bundle": "self.version", @@ -59,7 +59,7 @@ "require-dev": { "composer/composer": "^1.0", "contao/test-case": "^4.0", - "phpunit/phpunit": "^8.4", + "phpunit/phpunit": "^8.5", "symfony/phpunit-bridge": "4.4.*" }, "conflict": { diff --git a/news-bundle/composer.json b/news-bundle/composer.json index c03fff00111..3d13d6b430a 100644 --- a/news-bundle/composer.json +++ b/news-bundle/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.2", + "php": "^7.2 || ^8.0", "contao/core-bundle": "self.version", "friendsofsymfony/http-cache": "^2.4", "patchwork/utf8": "^1.2", @@ -32,7 +32,7 @@ "require-dev": { "contao/manager-plugin": "^2.3.1", "contao/test-case": "^4.0", - "phpunit/phpunit": "^8.4", + "phpunit/phpunit": "^8.5", "symfony/http-client": "4.4.*", "symfony/phpunit-bridge": "4.4.*" }, diff --git a/newsletter-bundle/composer.json b/newsletter-bundle/composer.json index 2b2f580494a..42de22cbf1b 100644 --- a/newsletter-bundle/composer.json +++ b/newsletter-bundle/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.2", + "php": "^7.2 || ^8.0", "contao/core-bundle": "self.version", "patchwork/utf8": "^1.2", "symfony/http-kernel": "4.4.*"