From db84062c855c3691f080ffd3a31eea2fdad21c7d Mon Sep 17 00:00:00 2001 From: MateuszKolankowski Date: Fri, 27 Feb 2026 08:21:47 +0100 Subject: [PATCH 01/12] Add "doctrine/persistence" dependency to composer.json --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index daebc88726..4b8a23186a 100644 --- a/composer.json +++ b/composer.json @@ -45,6 +45,7 @@ "doctrine/dbal": "^2.13.0", "doctrine/orm": "^2.7", "doctrine/doctrine-bundle": "^2.0", + "doctrine/persistence": "^3.0", "liip/imagine-bundle": "^2.3", "oneup/flysystem-bundle": "^4.4.2", "league/flysystem-memory": "^2.0.6", From 314fb23dee297f7b4027128ceae2ae91c8d717d9 Mon Sep 17 00:00:00 2001 From: MateuszKolankowski Date: Fri, 27 Feb 2026 08:26:17 +0100 Subject: [PATCH 02/12] Update type hints in SiteAccessAwareEntityManager methods --- .../Doctrine/SiteAccessAwareEntityManager.php | 30 ++++--------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php b/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php index 03f1ecdaac..88a2d51a8c 100644 --- a/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php +++ b/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php @@ -229,18 +229,12 @@ public function find($className, $id): ?object return $this->getWrapped()->find($className, $id); } - /** - * @param object $object - */ - public function persist($object): void + public function persist(object $object): void { $this->getWrapped()->persist($object); } - /** - * @param object $object - */ - public function remove($object): void + public function remove(object $object): void { $this->getWrapped()->remove($object); } @@ -250,18 +244,12 @@ public function clear(): void $this->getWrapped()->clear(); } - /** - * @param object $object - */ - public function detach($object): void + public function detach(object $object): void { $this->getWrapped()->detach($object); } - /** - * @param object $object - */ - public function refresh($object, ?int $lockMode = null): void + public function refresh(object $object, ?int $lockMode = null): void { $this->getWrapped()->refresh($object, $lockMode); } @@ -300,10 +288,7 @@ public function getMetadataFactory(): ClassMetadataFactory return $this->getWrapped()->getMetadataFactory(); } - /** - * @param object $obj - */ - public function initializeObject($obj): void + public function initializeObject(object $obj): void { $this->getWrapped()->initializeObject($obj); } @@ -316,10 +301,7 @@ public function isUninitializedObject($value): bool return $this->getWrapped()->isUninitializedObject($value); } - /** - * @param object $object - */ - public function contains($object): bool + public function contains(object $object): bool { return $this->getWrapped()->contains($object); } From a848507c06056903ba79c2af2a602f7c97a17a77 Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Fri, 27 Feb 2026 15:42:15 +0100 Subject: [PATCH 03/12] [Composer] Relaxed doctrine/persistence requirement --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4b8a23186a..03d626ef5c 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "doctrine/dbal": "^2.13.0", "doctrine/orm": "^2.7", "doctrine/doctrine-bundle": "^2.0", - "doctrine/persistence": "^3.0", + "doctrine/persistence": "^2.0 || ^3.0", "liip/imagine-bundle": "^2.3", "oneup/flysystem-bundle": "^4.4.2", "league/flysystem-memory": "^2.0.6", From 84e08da12f13f6c255f435cd5897ca5d244a036b Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Fri, 27 Feb 2026 15:44:02 +0100 Subject: [PATCH 04/12] [GHA][Backend CI] Created a matrix of doctrine/persistence versions Enabled running Backend CI GHA on different versions of doctrine/persistence: v2 and v3 --- .github/workflows/ci.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 98ab313e7a..2a126a8ad7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -40,6 +40,9 @@ jobs: - '7.4' - '8.0' - '8.1' + doctrine-persistence: + - 'doctrine/persistence:^2.0' + - 'doctrine/persistence:^3.0' steps: - uses: actions/checkout@v5 @@ -50,6 +53,7 @@ jobs: gh-client-secret: ${{ secrets.AUTOMATION_CLIENT_SECRET }} satis-network-key: ${{ secrets.SATIS_NETWORK_KEY }} satis-network-token: ${{ secrets.SATIS_NETWORK_TOKEN }} + composer-options: "--with ${{ matrix.doctrine-persistence }}" - name: Setup problem matchers for PHPUnit run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" @@ -90,6 +94,9 @@ jobs: - '7.4' - '8.0' - '8.1' + doctrine-persistence: + - 'doctrine/persistence:^2.0' + - 'doctrine/persistence:^3.0' image: - 'postgres:14' - 'postgres:18' @@ -103,6 +110,7 @@ jobs: gh-client-secret: ${{ secrets.AUTOMATION_CLIENT_SECRET }} satis-network-key: ${{ secrets.SATIS_NETWORK_KEY }} satis-network-token: ${{ secrets.SATIS_NETWORK_TOKEN }} + composer-options: "--with ${{ matrix.doctrine-persistence }}" - name: Setup problem matchers for PHPUnit run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" @@ -143,6 +151,9 @@ jobs: - '7.4' - '8.0' - '8.1' + doctrine-persistence: + - 'doctrine/persistence:^2.0' + - 'doctrine/persistence:^3.0' image: - 'mysql:8.0' - 'mysql:8.4' @@ -156,6 +167,7 @@ jobs: gh-client-secret: ${{ secrets.AUTOMATION_CLIENT_SECRET }} satis-network-key: ${{ secrets.SATIS_NETWORK_KEY }} satis-network-token: ${{ secrets.SATIS_NETWORK_TOKEN }} + composer-options: "--with ${{ matrix.doctrine-persistence }}" - name: Setup problem matchers for PHPUnit run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" From 618b2521feed2abed0a825ee6ca457ffd97f3caa Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Fri, 27 Feb 2026 15:47:35 +0100 Subject: [PATCH 05/12] Revert "Update type hints in SiteAccessAwareEntityManager methods" This reverts commit 314fb23dee297f7b4027128ceae2ae91c8d717d9. --- .../Doctrine/SiteAccessAwareEntityManager.php | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php b/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php index 88a2d51a8c..03f1ecdaac 100644 --- a/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php +++ b/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php @@ -229,12 +229,18 @@ public function find($className, $id): ?object return $this->getWrapped()->find($className, $id); } - public function persist(object $object): void + /** + * @param object $object + */ + public function persist($object): void { $this->getWrapped()->persist($object); } - public function remove(object $object): void + /** + * @param object $object + */ + public function remove($object): void { $this->getWrapped()->remove($object); } @@ -244,12 +250,18 @@ public function clear(): void $this->getWrapped()->clear(); } - public function detach(object $object): void + /** + * @param object $object + */ + public function detach($object): void { $this->getWrapped()->detach($object); } - public function refresh(object $object, ?int $lockMode = null): void + /** + * @param object $object + */ + public function refresh($object, ?int $lockMode = null): void { $this->getWrapped()->refresh($object, $lockMode); } @@ -288,7 +300,10 @@ public function getMetadataFactory(): ClassMetadataFactory return $this->getWrapped()->getMetadataFactory(); } - public function initializeObject(object $obj): void + /** + * @param object $obj + */ + public function initializeObject($obj): void { $this->getWrapped()->initializeObject($obj); } @@ -301,7 +316,10 @@ public function isUninitializedObject($value): bool return $this->getWrapped()->isUninitializedObject($value); } - public function contains(object $object): bool + /** + * @param object $object + */ + public function contains($object): bool { return $this->getWrapped()->contains($object); } From e10dd624a0390bef03d5c20dbbb3d0bea126838a Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Fri, 27 Feb 2026 17:00:03 +0100 Subject: [PATCH 06/12] Provided cross-compatibility between doctrine/persistence v2 and v3 * Provided cross-compatibility between doctrine/persistence v2 and v3 for SiteAccessAwareEntityManager --- .../Doctrine/SiteAccessAwareEntityManager.php | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php b/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php index 03f1ecdaac..e5578924f7 100644 --- a/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php +++ b/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php @@ -31,6 +31,8 @@ /** * @internal + * + * SiteAccessAwareEntityManager is a cross-compatible class supporting doctrine/persistence v2 and v3. */ final class SiteAccessAwareEntityManager implements EntityManagerInterface, ConfigScopeChangeSubscriber, ResetInterface { @@ -237,15 +239,15 @@ public function persist($object): void $this->getWrapped()->persist($object); } - /** - * @param object $object - */ public function remove($object): void { $this->getWrapped()->remove($object); } - public function clear(): void + /** + * @param string|null $objectName + */ + public function clear($objectName = null): void { $this->getWrapped()->clear(); } @@ -258,9 +260,6 @@ public function detach($object): void $this->getWrapped()->detach($object); } - /** - * @param object $object - */ public function refresh($object, ?int $lockMode = null): void { $this->getWrapped()->refresh($object, $lockMode); @@ -271,25 +270,11 @@ public function flush(): void $this->getWrapped()->flush(); } - /** - * @template T of object - * - * @param class-string $className - * - * @return EntityRepository - */ public function getRepository($className): EntityRepository { return $this->getWrapped()->getRepository($className); } - /** - * @template T of object - * - * @param class-string $className - * - * @return ClassMetadata - */ public function getClassMetadata($className): ClassMetadata { return $this->getWrapped()->getClassMetadata($className); @@ -313,7 +298,12 @@ public function initializeObject($obj): void */ public function isUninitializedObject($value): bool { - return $this->getWrapped()->isUninitializedObject($value); + $entityManager = $this->getWrapped(); + + // workaround for doctrine/persistence v2 and v3 cross-compatibility + return method_exists($entityManager, 'isUninitializedObject') + ? $entityManager->isUninitializedObject($value) + : false; } /** @@ -323,4 +313,19 @@ public function contains($object): bool { return $this->getWrapped()->contains($object); } + + /** + * @param object $object + * + * @return object|null + */ + public function merge($object) + { + $entityManager = $this->getWrapped(); + + // workaround for doctrine/persistence v2 and v3 cross-compatibility + return method_exists($entityManager, 'merge') + ? $entityManager->merge($object) + : null; + } } From b04c7e921f40ec98608d6e39b418e92774361e8e Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Fri, 27 Feb 2026 18:05:10 +0100 Subject: [PATCH 07/12] [PHPStan] Implemented loading different baselines depending on a package version Co-authored-by: OpenAI Codex --- composer.json | 1 + phpstan-baseline.neon.php | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/composer.json b/composer.json index 03d626ef5c..a355ab0750 100644 --- a/composer.json +++ b/composer.json @@ -63,6 +63,7 @@ }, "require-dev": { "behat/behat": "^3.6.1", + "composer-runtime-api": "^2.0", "jenner/simple_fork": "^1.2", "friends-of-behat/mink-extension": "^2.4", "ibexa/ci-scripts": "^0.2@dev", diff --git a/phpstan-baseline.neon.php b/phpstan-baseline.neon.php index eaab20f250..a720b235ae 100644 --- a/phpstan-baseline.neon.php +++ b/phpstan-baseline.neon.php @@ -6,6 +6,9 @@ */ declare(strict_types=1); +use Composer\InstalledVersions; +use Composer\Semver\VersionParser; + $includes = []; if (PHP_VERSION_ID < 80000) { $includes[] = __DIR__ . '/phpstan-baseline-7.4.neon'; @@ -27,6 +30,13 @@ $includes[] = __DIR__ . '/phpstan-baseline-lte-8.2.neon'; } +$versionParser = new VersionParser(); +if (InstalledVersions::satisfies($versionParser, 'doctrine/persistence', '2.*')) { + $includes[] = __DIR__ . '/phpstan-baseline-doctrine-persistence-v2.neon'; +} elseif (InstalledVersions::satisfies($versionParser, 'doctrine/persistence', '3.*')) { + $includes[] = __DIR__ . '/phpstan-baseline-doctrine-persistence-v3.neon'; +} + $config = []; $config['includes'] = $includes; From 4e6413d7965fa6f65f51cf48e80a78acd5756de5 Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Mon, 2 Mar 2026 13:38:51 +0100 Subject: [PATCH 08/12] Aligned `ObjectManager::clear` method call with doctrine/persistence v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Paweł Niedzielski --- src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php b/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php index e5578924f7..102bcd10d9 100644 --- a/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php +++ b/src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php @@ -249,7 +249,7 @@ public function remove($object): void */ public function clear($objectName = null): void { - $this->getWrapped()->clear(); + $this->getWrapped()->clear($objectName); } /** From 3c048cc1c5c24e0e232321ecfee8866f125e9fde Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Fri, 27 Feb 2026 18:26:01 +0100 Subject: [PATCH 09/12] [PHPStan] Created baselines per different doctrine/persistence versions --- phpstan-baseline-doctrine-persistence-v2.neon | 7 +++++++ phpstan-baseline-doctrine-persistence-v3.neon | 13 +++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 phpstan-baseline-doctrine-persistence-v2.neon create mode 100644 phpstan-baseline-doctrine-persistence-v3.neon diff --git a/phpstan-baseline-doctrine-persistence-v2.neon b/phpstan-baseline-doctrine-persistence-v2.neon new file mode 100644 index 0000000000..998fa138e4 --- /dev/null +++ b/phpstan-baseline-doctrine-persistence-v2.neon @@ -0,0 +1,7 @@ +parameters: + ignoreErrors: + - + message: '#^Call to function method_exists\(\) with Doctrine\\ORM\\EntityManagerInterface and ''merge'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php diff --git a/phpstan-baseline-doctrine-persistence-v3.neon b/phpstan-baseline-doctrine-persistence-v3.neon new file mode 100644 index 0000000000..35aaa35c0d --- /dev/null +++ b/phpstan-baseline-doctrine-persistence-v3.neon @@ -0,0 +1,13 @@ +parameters: + ignoreErrors: + - + message: '#^Call to function method_exists\(\) with Doctrine\\ORM\\EntityManagerInterface and ''isUninitializedObje…'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php + + - + message: '#^Method Doctrine\\Persistence\\ObjectManager\:\:clear\(\) invoked with 1 parameter, 0 required\.$#' + identifier: arguments.count + count: 1 + path: src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php From 52ba6cb22afd7f3c9c9b4128bcccfe62cdfeb4f8 Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Mon, 2 Mar 2026 13:42:29 +0100 Subject: [PATCH 10/12] [GHA][Backend CI] Dropped doctrine persistence matrix for SQLite tests Temporarily replaced PHP 8.0-8.1 with PHP 8.2, to be permanently replaced with PHP 8.3 and 8.4. --- .github/workflows/ci.yaml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2a126a8ad7..db278cde44 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -38,11 +38,7 @@ jobs: matrix: php: - '7.4' - - '8.0' - - '8.1' - doctrine-persistence: - - 'doctrine/persistence:^2.0' - - 'doctrine/persistence:^3.0' + - '8.2' steps: - uses: actions/checkout@v5 @@ -53,7 +49,6 @@ jobs: gh-client-secret: ${{ secrets.AUTOMATION_CLIENT_SECRET }} satis-network-key: ${{ secrets.SATIS_NETWORK_KEY }} satis-network-token: ${{ secrets.SATIS_NETWORK_TOKEN }} - composer-options: "--with ${{ matrix.doctrine-persistence }}" - name: Setup problem matchers for PHPUnit run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" From 3136c28674093087d4b2c307e8299937bb11d00f Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Mon, 2 Mar 2026 13:47:26 +0100 Subject: [PATCH 11/12] [GHA][Backend CI] Dropped testing on PHP 8 versions past EOL --- .github/workflows/ci.yaml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index db278cde44..1c790d752e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -87,8 +87,6 @@ jobs: matrix: php: - '7.4' - - '8.0' - - '8.1' doctrine-persistence: - 'doctrine/persistence:^2.0' - 'doctrine/persistence:^3.0' @@ -144,8 +142,6 @@ jobs: matrix: php: - '7.4' - - '8.0' - - '8.1' doctrine-persistence: - 'doctrine/persistence:^2.0' - 'doctrine/persistence:^3.0' @@ -201,8 +197,7 @@ jobs: matrix: php: - '7.4' - - '8.0' - - '8.1' + - '8.2' steps: - uses: actions/checkout@v5 with: From 6f0b0762279f1036d3d14fb2aef33c4865978cc4 Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Mon, 2 Mar 2026 14:52:19 +0100 Subject: [PATCH 12/12] [GHA][Backend CI] Restored testing on PHP 8.1 for Unit & SQLite integration --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1c790d752e..c45551bbbd 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -38,7 +38,7 @@ jobs: matrix: php: - '7.4' - - '8.2' + - '8.1' steps: - uses: actions/checkout@v5