From 4db76876ed9fcf0811aae536c8eaf8afdc84b794 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 15 Oct 2026 15:56:54 +0200 Subject: [PATCH] #164 - Use the PHP 8.3 to 8.5 functions through the Symfony polyfills, and configure Rector accordingly * Require symfony/polyfill-php83, symfony/polyfill-php84 and symfony/polyfill-php85 (^1.33). * Rector: withPhpVersion(PHP_82) (was PHP_85) and withPhpSets() without argument (PHP_POLYFILLS set), remove the redundant LevelSetList::UP_TO_PHP_82. No change applied by Rector. * array_last() instead of end() in CleverAgeUiProcessExtensionTest. * Test kernel: lazy ghost proxies with Doctrine ORM 2, now installed by the lowest dependencies job (the legacy proxies cannot unset the readonly properties of the entities). * CONTRIBUTING: new "PHP version" section. CHANGELOG. Co-Authored-By: Claude Opus 5.5 (1M context) --- CHANGELOG.md | 1 + CONTRIBUTING.md | 8 ++++++++ composer.json | 3 +++ rector.php | 6 ++---- tests/App/TestKernel.php | 6 ++++++ .../CleverAgeUiProcessExtensionTest.php | 2 +- 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 749e4d8..0748797 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Latest ------ ## Changes +* [#164](https://github.com/cleverage/ui-process-bundle/issues/164) Require `symfony/polyfill-php83`, `symfony/polyfill-php84` and `symfony/polyfill-php85`: the functions of PHP 8.3 to 8.5 (`json_validate()`, `array_find()`, `array_first()`...) can be used while supporting PHP 8.2 (see `CONTRIBUTING.md`). Rector is configured for PHP 8.2 (was 8.5, which allowed it to introduce PHP 8.3+ functions without polyfill) with the `PHP_POLYFILLS` set (`withPhpSets()` without argument), it does not change the code. `array_last()` replaces `end()` in a test. Tests: lazy ghost proxies with Doctrine ORM 2 (now installed by the lowest dependencies job), as configured by the Symfony recipe: the legacy proxies cannot unset the readonly properties of the entities. * [#158](https://github.com/cleverage/ui-process-bundle/issues/158) CI: test the lowest versions allowed by `composer.json` (`--prefer-lowest`, PHP 8.2). Require `symfony/scheduler` ^6.4.44 || ^7.4.17 || ^8.1.5: the `every` expressions validation (`EveryExpressionValidator`) relies on the `PeriodicalTrigger` rejecting the intervals that do not move the run date forward or resolve to zero seconds (older versions loop forever on e.g. "yesterday", and fail with a `TypeError` on an invalid expression). `ProcessExecutionDurationFilter`: the number of seconds is cast to an integer and inlined in the DQL instead of being bound as a parameter (#111): with DBAL 3, the SQLite platform puts the `SECOND` intervals inside a string literal, so the parameter was never bound ("column index out of range" error on SQLite with DBAL 3). * [#156](https://github.com/cleverage/ui-process-bundle/issues/156) `LogRecord::contextIsEmpty()` (deprecated since v3.1, use `hasContextInfo()`) triggers a deprecation at runtime with `trigger_deprecation()` (`symfony/deprecation-contracts`, now required). Add tests. * [#154](https://github.com/cleverage/ui-process-bundle/issues/154) Add a `.gitattributes`: the development files (`.docker/`, `.github/`, `tests/`, quality tools and PHPUnit configurations, `Makefile`) are no longer part of the archive installed by Composer (`dist`), remove the unused `package.json` (Webpack Encore leftover of the Symfony skeleton: no `webpack.config.js`, no `assets/`). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d06b733..e4466ff 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,6 +40,14 @@ make quality make tests ``` +## PHP version + +The bundle supports PHP 8.2 and later: do not use a syntax introduced by a later version (typed class constants, +property hooks, pipe operator...). The functions of PHP 8.3 to 8.5 (`json_validate()`, `array_find()`, `array_any()`, +`mb_trim()`, `array_first()`...) can be used: they are provided by the required `symfony/polyfill-php83`, +`symfony/polyfill-php84` and `symfony/polyfill-php85` packages on the older versions. Rector (`make quality`) is +configured accordingly. + ## Deprecations notices When a feature should be deprecated, or when you have a breaking change for a future version, please : diff --git a/composer.json b/composer.json index 2abd4aa..f9d2f91 100644 --- a/composer.json +++ b/composer.json @@ -67,6 +67,9 @@ "symfony/monolog-bundle": "^3.11 || ^4", "symfony/options-resolver": "^6.4 || ^7.4 || ^8", "symfony/password-hasher": "^6.4 || ^7.4 || ^8", + "symfony/polyfill-php83": "^1.33", + "symfony/polyfill-php84": "^1.33", + "symfony/polyfill-php85": "^1.33", "symfony/process": "^6.4 || ^7.4 || ^8", "symfony/routing": "^6.4 || ^7.4 || ^8", "symfony/scheduler": "^6.4.44 || ^7.4.17 || ^8.1.5", diff --git a/rector.php b/rector.php index 8c3ed55..3ca9cbf 100644 --- a/rector.php +++ b/rector.php @@ -4,23 +4,21 @@ use Rector\Config\RectorConfig; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedConstructorParamRector; -use Rector\Set\ValueObject\LevelSetList; use Rector\Symfony\Set\SymfonySetList; use Rector\ValueObject\PhpVersion; return RectorConfig::configure() - ->withPhpVersion(PhpVersion::PHP_85) + ->withPhpVersion(PhpVersion::PHP_82) ->withPaths([ __DIR__.'/src', __DIR__.'/tests', ]) - ->withPhpSets(php82: true) + ->withPhpSets() // here we can define, what prepared sets of rules will be applied ->withComposerBased(doctrine: true, phpunit: true, symfony: true) ->withPreparedSets(deadCode: true, codeQuality: true, doctrineCodeQuality: true, symfonyCodeQuality: true) ->withAttributesSets(symfony: true, doctrine: true) ->withSets([ - LevelSetList::UP_TO_PHP_82, SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION, ]) ->withSkip([ diff --git a/tests/App/TestKernel.php b/tests/App/TestKernel.php index 9658be3..6e5b14c 100644 --- a/tests/App/TestKernel.php +++ b/tests/App/TestKernel.php @@ -17,6 +17,7 @@ use CleverAge\UiProcessBundle\CleverAgeUiProcessBundle; use Doctrine\Bundle\DoctrineBundle\DoctrineBundle; use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle; +use Doctrine\ORM\Proxy\ProxyFactory; use EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle; use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; @@ -70,6 +71,11 @@ public function getLogDir(): string protected function configureContainer(\Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator $container): void { $container->import(__DIR__.'/config/packages.yaml'); + // Doctrine ORM 2 (lowest dependencies): lazy ghost proxies, as configured by the Symfony recipe, the legacy + // proxies cannot unset the readonly properties of the entities (ProcessExecution::$code...) + if (method_exists(ProxyFactory::class, 'resetUninitializedProxy')) { + $container->extension('doctrine', ['orm' => ['enable_lazy_ghost_objects' => true]]); + } } protected function configureRoutes(\Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator $routes): void diff --git a/tests/DependencyInjection/CleverAgeUiProcessExtensionTest.php b/tests/DependencyInjection/CleverAgeUiProcessExtensionTest.php index 7f27ee5..eb0d05c 100644 --- a/tests/DependencyInjection/CleverAgeUiProcessExtensionTest.php +++ b/tests/DependencyInjection/CleverAgeUiProcessExtensionTest.php @@ -136,7 +136,7 @@ public function testLoadWithCustomConfiguration(): void self::assertSame('Error', $databaseHandler->getArgument('$level')); self::assertTrue($databaseHandler->hasMethodCall('disable')); $calls = $databaseHandler->getMethodCalls(); - self::assertSame(['disable', []], end($calls)); + self::assertSame(['disable', []], array_last($calls)); $purgeLogsCommand = $container->getDefinition('cleverage_ui_process.command.purge_logs'); self::assertSame(30, $purgeLogsCommand->getArgument('$databaseMaxDays'));