From 8f5f36ab5456875decab5b3092586ac07a0ebaeb Mon Sep 17 00:00:00 2001 From: jmsche Date: Thu, 18 Dec 2025 13:10:18 +0100 Subject: [PATCH] Fix some PHP, Doctrine & Symfony deprecations --- .github/workflows/continuous-integration.yaml | 9 +- CHANGELOG-5.x.md | 5 ++ composer.json | 6 +- phpstan-baseline.neon | 82 +++++++++++-------- phpunit.xml.dist | 3 +- src/Listener/FileSubscriber.php | 1 - .../Constraints/RecaptchaValidator.php | 2 +- src/Validator/Constraints/Slug.php | 9 +- templates/Feed/index.atom.twig | 2 +- tests/LeaptCoreTestingKernel.php | 5 ++ tests/Listener/FileSubscriberTest.php | 6 +- tests/Paginator/DoctrineORMPaginatorTest.php | 6 +- .../PasswordStrengthValidatorTest.php | 27 +++--- 13 files changed, 98 insertions(+), 65 deletions(-) diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index bb959ee7..f3af3683 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -23,15 +23,12 @@ jobs: - '8.5' symfony-version: - '6.4.*' - - '7.3.*' - - '7.4.*@dev' + - '7.4.*' include: - php-version: '8.4' - symfony-version: '8.0.*@dev' - continue-on-error: true + symfony-version: '8.0.*' - php-version: '8.5' - symfony-version: '8.0.*@dev' - continue-on-error: true + symfony-version: '8.0.*' steps: - name: Checkout code diff --git a/CHANGELOG-5.x.md b/CHANGELOG-5.x.md index c3309b6c..7a0e0f22 100644 --- a/CHANGELOG-5.x.md +++ b/CHANGELOG-5.x.md @@ -1,3 +1,8 @@ +5.6.1 +----- + +* Fix deprecations + 5.6.0 ----- diff --git a/composer.json b/composer.json index b326dc6d..063c33f4 100644 --- a/composer.json +++ b/composer.json @@ -41,8 +41,8 @@ "twig/twig": "^3.0" }, "require-dev": { - "doctrine/data-fixtures": "^1.6", - "doctrine/persistence": "^3.2", + "doctrine/data-fixtures": "^1.6 || ^2.2", + "doctrine/persistence": "^3.2 || ^4.0", "easycorp/easyadmin-bundle": "^4.8.5", "endroid/qr-code": "^4.8 || ^5.0 || ^6.0", "fakerphp/faker": "^1.23", @@ -52,7 +52,7 @@ "phpstan/phpstan-deprecation-rules": "^2.0.3", "phpunit/phpunit": "^11.5.35", "symfony/browser-kit": "^6.4 || ^7.0 || ^8.0", - "symplify/easy-coding-standard": "^12.5.24" + "symplify/easy-coding-standard": "^13.0.0" }, "config": { "sort-packages": true diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 0e28a787..700656d9 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,157 +1,175 @@ parameters: ignoreErrors: - - message: '#^Property Leapt\\CoreBundle\\Datalist\\Datalist\:\:\$iterator \(Iterator\) does not accept Traversable\\.$#' + rawMessage: 'Property Leapt\CoreBundle\Datalist\Datalist::$initialized (bool) is never assigned true so the property type can be changed to false.' + identifier: property.tooWideBool + count: 1 + path: src/Datalist/Datalist.php + + - + rawMessage: 'Property Leapt\CoreBundle\Datalist\Datalist::$iterator (Iterator) does not accept Traversable.' identifier: assign.propertyType count: 1 path: src/Datalist/Datalist.php - - message: '#^Parameter \#1 \$value of function count expects array\|Countable, Iterator given\.$#' + rawMessage: 'Parameter #1 $value of function count expects array|Countable, Iterator given.' identifier: argument.type count: 1 path: src/Datalist/Datasource/AbstractDatasource.php - - message: '#^Method Leapt\\CoreBundle\\Datalist\\Field\\DatalistField\:\:getType\(\) should return Leapt\\CoreBundle\\Datalist\\Field\\Type\\FieldTypeInterface but returns Leapt\\CoreBundle\\Datalist\\TypeInterface\.$#' + rawMessage: 'Method Leapt\CoreBundle\Datalist\Field\DatalistField::getType() should return Leapt\CoreBundle\Datalist\Field\Type\FieldTypeInterface but returns Leapt\CoreBundle\Datalist\TypeInterface.' identifier: return.type count: 1 path: src/Datalist/Field/DatalistField.php - - message: '#^Method Leapt\\CoreBundle\\Datalist\\Filter\\DatalistFilter\:\:getType\(\) should return Leapt\\CoreBundle\\Datalist\\Filter\\Type\\FilterTypeInterface but returns Leapt\\CoreBundle\\Datalist\\TypeInterface\.$#' + rawMessage: 'Method Leapt\CoreBundle\Datalist\Filter\DatalistFilter::getType() should return Leapt\CoreBundle\Datalist\Filter\Type\FilterTypeInterface but returns Leapt\CoreBundle\Datalist\TypeInterface.' identifier: return.type count: 1 path: src/Datalist/Filter/DatalistFilter.php - - message: '#^Method Leapt\\CoreBundle\\Paginator\\DoctrineORMPaginator\:\:getIterator\(\) should return ArrayIterator but returns Traversable\<\(int\|string\), mixed\>\.$#' + rawMessage: 'Method Leapt\CoreBundle\Paginator\DoctrineORMPaginator::getIterator() should return ArrayIterator but returns Traversable<(int|string), mixed>.' identifier: return.type count: 1 path: src/Paginator/DoctrineORMPaginator.php - - message: '#^Call to method getParent\(\) of internal class Twig\\Template from outside its root namespace Twig\.$#' + rawMessage: 'Call to method getParent() of internal class Twig\Template from outside its root namespace Twig.' identifier: method.internalClass count: 1 path: src/Twig/Extension/DatalistExtension.php - - message: '#^Call to method hasBlock\(\) of internal class Twig\\Template from outside its root namespace Twig\.$#' + rawMessage: 'Call to method hasBlock() of internal class Twig\Template from outside its root namespace Twig.' identifier: method.internalClass count: 1 path: src/Twig/Extension/DatalistExtension.php - - message: '#^Call to method renderBlock\(\) of internal class Twig\\Template from outside its root namespace Twig\.$#' + rawMessage: 'Call to method renderBlock() of internal class Twig\Template from outside its root namespace Twig.' identifier: method.internalClass count: 1 path: src/Twig/Extension/DatalistExtension.php - - message: '#^Instanceof references internal class Twig\\Template\.$#' + rawMessage: Instanceof references internal class Twig\Template. identifier: instanceof.internalClass count: 1 path: src/Twig/Extension/DatalistExtension.php - - message: '#^Call to method getParent\(\) of internal class Twig\\Template from outside its root namespace Twig\.$#' + rawMessage: 'Call to method getParent() of internal class Twig\Template from outside its root namespace Twig.' identifier: method.internalClass count: 1 path: src/Twig/Extension/PaginatorExtension.php - - message: '#^Call to method hasBlock\(\) of internal class Twig\\Template from outside its root namespace Twig\.$#' + rawMessage: 'Call to method hasBlock() of internal class Twig\Template from outside its root namespace Twig.' identifier: method.internalClass count: 1 path: src/Twig/Extension/PaginatorExtension.php - - message: '#^Call to method renderBlock\(\) of internal class Twig\\Template from outside its root namespace Twig\.$#' + rawMessage: 'Call to method renderBlock() of internal class Twig\Template from outside its root namespace Twig.' identifier: method.internalClass count: 1 path: src/Twig/Extension/PaginatorExtension.php - - message: '#^Instanceof references internal class Twig\\Template\.$#' + rawMessage: Instanceof references internal class Twig\Template. identifier: instanceof.internalClass count: 1 path: src/Twig/Extension/PaginatorExtension.php - - message: '#^Call to function method_exists\(\) with ''Endroid\\\\QrCode\\\\Builder\\\\Builder'' and ''create'' will always evaluate to false\.$#' + rawMessage: 'Call to function method_exists() with ''Endroid\\QrCode\\Builder\\Builder'' and ''create'' will always evaluate to false.' identifier: function.impossibleType count: 1 path: src/Twig/Extension/QrCodeExtension.php - - message: ''' - #^Call to deprecated method getExpressionParser\(\) of class Twig\\Parser\: - since Twig 3\.21$# + rawMessage: ''' + Call to deprecated method getExpressionParser() of class Twig\Parser: + since Twig 3.21 ''' identifier: method.deprecated count: 3 path: src/Twig/TokenParser/DatalistThemeTokenParser.php - - message: '#^Call to function method_exists\(\) with Twig\\Parser and ''parseExpression'' will always evaluate to true\.$#' + rawMessage: 'Call to function method_exists() with Twig\Parser and ''parseExpression'' will always evaluate to true.' identifier: function.alreadyNarrowedType count: 3 path: src/Twig/TokenParser/DatalistThemeTokenParser.php - - message: ''' - #^Call to method parseExpression\(\) of deprecated class Twig\\ExpressionParser\: - since Twig 3\.21$# + rawMessage: ''' + Call to method parseExpression() of deprecated class Twig\ExpressionParser: + since Twig 3.21 ''' identifier: method.deprecatedClass count: 3 path: src/Twig/TokenParser/DatalistThemeTokenParser.php - - message: ''' - #^Call to deprecated method getExpressionParser\(\) of class Twig\\Parser\: - since Twig 3\.21$# + rawMessage: ''' + Call to deprecated method getExpressionParser() of class Twig\Parser: + since Twig 3.21 ''' identifier: method.deprecated count: 3 path: src/Twig/TokenParser/PaginatorThemeTokenParser.php - - message: '#^Call to function method_exists\(\) with Twig\\Parser and ''parseExpression'' will always evaluate to true\.$#' + rawMessage: 'Call to function method_exists() with Twig\Parser and ''parseExpression'' will always evaluate to true.' identifier: function.alreadyNarrowedType count: 3 path: src/Twig/TokenParser/PaginatorThemeTokenParser.php - - message: ''' - #^Call to method parseExpression\(\) of deprecated class Twig\\ExpressionParser\: - since Twig 3\.21$# + rawMessage: ''' + Call to method parseExpression() of deprecated class Twig\ExpressionParser: + since Twig 3.21 ''' identifier: method.deprecatedClass count: 3 path: src/Twig/TokenParser/PaginatorThemeTokenParser.php - - message: '#^Method Leapt\\CoreBundle\\Tests\\LeaptCoreTestingKernel\:\:configureContainer\(\) is unused\.$#' + rawMessage: 'Method Symfony\Component\Validator\Constraints\Regex::__construct() invoked with 8 parameters, 1-7 required.' + identifier: arguments.count + count: 1 + path: src/Validator/Constraints/Slug.php + + - + rawMessage: 'Method Leapt\CoreBundle\Tests\LeaptCoreTestingKernel::configureContainer() is unused.' + identifier: method.unused + count: 1 + path: tests/LeaptCoreTestingKernel.php + + - + rawMessage: 'Method Leapt\CoreBundle\Tests\LeaptCoreTestingKernel::configureRoutes() is unused.' identifier: method.unused count: 1 path: tests/LeaptCoreTestingKernel.php - - message: '#^Method Leapt\\CoreBundle\\Tests\\LeaptCoreTestingKernel\:\:configureRoutes\(\) is unused\.$#' + rawMessage: 'Method Leapt\CoreBundle\Tests\LeaptCoreTestingKernel::getConfigDir() is unused.' identifier: method.unused count: 1 path: tests/LeaptCoreTestingKernel.php - - message: '#^Property Leapt\\CoreBundle\\Tests\\Listener\\Fixtures\\Entity\\User\:\:\$id is never written, only read\.$#' + rawMessage: 'Property Leapt\CoreBundle\Tests\Listener\Fixtures\Entity\User::$id is never written, only read.' identifier: property.onlyRead count: 1 path: tests/Listener/Fixtures/Entity/User.php - - message: '#^Property Leapt\\CoreBundle\\Tests\\Paginator\\Entity\\Player\:\:\$id is never written, only read\.$#' + rawMessage: 'Property Leapt\CoreBundle\Tests\Paginator\Entity\Player::$id is never written, only read.' identifier: property.onlyRead count: 1 path: tests/Paginator/Entity/Player.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 42919f0d..f9bdbe62 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -3,8 +3,7 @@ diff --git a/src/Listener/FileSubscriber.php b/src/Listener/FileSubscriber.php index b1cf0127..8649b3fc 100644 --- a/src/Listener/FileSubscriber.php +++ b/src/Listener/FileSubscriber.php @@ -226,7 +226,6 @@ private function checkClassConfig($entity, EntityManagerInterface $entityManager } $attributes = $this->getAttributes($property); foreach ($attributes as $attribute) { - $property->setAccessible(true); $field = $property->getName(); if (null === $attribute->mappedBy) { diff --git a/src/Validator/Constraints/RecaptchaValidator.php b/src/Validator/Constraints/RecaptchaValidator.php index 552d845a..09c0e4af 100644 --- a/src/Validator/Constraints/RecaptchaValidator.php +++ b/src/Validator/Constraints/RecaptchaValidator.php @@ -36,7 +36,7 @@ public function validate(mixed $value, Constraint $constraint): void // define variable for recaptcha check answer $mainRequest = $this->requestStack->getMainRequest(); $remoteIp = $mainRequest->getClientIp(); - $answer = $mainRequest->get('g-recaptcha-response'); + $answer = $mainRequest->request->get('g-recaptcha-response'); // Verify user response with Google $response = $this->checkAnswer($this->privateKey, $remoteIp, $answer); diff --git a/src/Validator/Constraints/Slug.php b/src/Validator/Constraints/Slug.php index 436c9173..f188fb80 100644 --- a/src/Validator/Constraints/Slug.php +++ b/src/Validator/Constraints/Slug.php @@ -18,9 +18,14 @@ public function __construct( ?callable $normalizer = null, ?array $groups = null, mixed $payload = null, - array $options = [], + ?array $options = null, ) { - parent::__construct($pattern, $message, $htmlPattern, $match, $normalizer, $groups, $payload, $options); + if (null !== $options) { + trigger_deprecation('leapt/core-bundle', '5.6.1', 'Passing an array of options to configure the "%s" constraint is deprecated, use named arguments instead.', static::class); + parent::__construct($pattern, $message, $htmlPattern, $match, $normalizer, $groups, $payload, $options); + } else { + parent::__construct($pattern, $message, $htmlPattern, $match, $normalizer, $groups, $payload); + } } public function getRequiredOptions(): array diff --git a/templates/Feed/index.atom.twig b/templates/Feed/index.atom.twig index c13c40d6..ebaeef4a 100644 --- a/templates/Feed/index.atom.twig +++ b/templates/Feed/index.atom.twig @@ -2,7 +2,7 @@ {{ feed.title }} - + {{ feed.updatedAt|date(constant('DATE_ATOM')) }} {{ feed.id }} {% for item in items %} diff --git a/tests/LeaptCoreTestingKernel.php b/tests/LeaptCoreTestingKernel.php index 1e68ca02..8976189c 100644 --- a/tests/LeaptCoreTestingKernel.php +++ b/tests/LeaptCoreTestingKernel.php @@ -50,4 +50,9 @@ private function configureRoutes(RoutingConfigurator $routes): void ->prefix('/feed'); $routes->import(__DIR__ . '/../config/routing_sitemap.php'); } + + private function getConfigDir(): string + { + return __DIR__ . '/../var/config'; + } } diff --git a/tests/Listener/FileSubscriberTest.php b/tests/Listener/FileSubscriberTest.php index 1b266cc6..d9bd9b86 100644 --- a/tests/Listener/FileSubscriberTest.php +++ b/tests/Listener/FileSubscriberTest.php @@ -191,7 +191,11 @@ private function buildEntityManager(): EntityManagerInterface { $config = ORMSetup::createConfiguration(true, sys_get_temp_dir()); $config->setMetadataDriverImpl(new AttributeDriver([__DIR__ . '/Fixtures'])); - $config->setAutoGenerateProxyClasses(true); + if (\PHP_VERSION_ID < 80400) { + $config->setAutoGenerateProxyClasses(true); + } else { + $config->enableNativeLazyObjects(true); + } $params = [ 'driver' => 'pdo_sqlite', diff --git a/tests/Paginator/DoctrineORMPaginatorTest.php b/tests/Paginator/DoctrineORMPaginatorTest.php index af73a265..41034116 100644 --- a/tests/Paginator/DoctrineORMPaginatorTest.php +++ b/tests/Paginator/DoctrineORMPaginatorTest.php @@ -35,7 +35,11 @@ public static function setUpBeforeClass(): void $proxiesIdentifier = uniqid('Proxies', true); $config->setProxyDir(sys_get_temp_dir() . '/' . $proxiesIdentifier); $config->setProxyNamespace('MyProject\Proxies\\' . $proxiesIdentifier); - $config->setAutoGenerateProxyClasses(true); + if (\PHP_VERSION_ID < 80400) { + $config->setAutoGenerateProxyClasses(true); + } else { + $config->enableNativeLazyObjects(true); + } $em = new EntityManager(DriverManager::getConnection($dbParams), $config); diff --git a/tests/Validator/PasswordStrengthValidatorTest.php b/tests/Validator/PasswordStrengthValidatorTest.php index f9afaca0..bff456ad 100644 --- a/tests/Validator/PasswordStrengthValidatorTest.php +++ b/tests/Validator/PasswordStrengthValidatorTest.php @@ -28,7 +28,7 @@ public function testEmptyStringIsValid(): void #[DataProvider('getValidPasswords')] public function testValidPassword(string $password): void { - $this->validator->validate($password, new PasswordStrength(['score' => 50, 'min' => 5, 'max' => 255])); + $this->validator->validate($password, new PasswordStrength(min: 5, max: 255, score: 50)); $this->assertNoViolation(); } @@ -48,10 +48,7 @@ public static function getValidPasswords(): iterable #[DataProvider('getInvalidPasswords')] public function testInvalidPasswords(string $password): void { - $constraint = new PasswordStrength([ - 'scoreMessage' => 'scoreMessage', - 'score' => 50, - ]); + $constraint = new PasswordStrength(score: 50, scoreMessage: 'scoreMessage'); $this->validator->validate($password, $constraint); @@ -68,11 +65,11 @@ public static function getInvalidPasswords(): iterable public function testMinPasswords(): void { - $constraint = new PasswordStrength([ - 'minMessage' => 'minMessage', - 'score' => 50, - 'min' => 5, - ]); + $constraint = new PasswordStrength( + min: 5, + minMessage: 'minMessage', + score: 50, + ); $this->validator->validate('abc', $constraint); $this->buildViolation('minMessage') @@ -82,11 +79,11 @@ public function testMinPasswords(): void public function testMaxPasswords(): void { - $constraint = new PasswordStrength([ - 'maxMessage' => 'maxMessage', - 'score' => 50, - 'max' => 5, - ]); + $constraint = new PasswordStrength( + max: 5, + maxMessage: 'maxMessage', + score: 50, + ); $this->validator->validate('abcdefgh', $constraint); $this->buildViolation('maxMessage')