diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 9b8ab937b8..21f2ae7374 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -84,6 +84,10 @@ jobs: run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update" if: "${{ matrix.dbal-version != 'default' }}" + - name: "Downgrade VarExporter" + run: 'composer require --no-update "symfony/var-exporter:^6.4 || ^7.4"' + if: "${{ matrix.native_lazy == '0' }}" + - name: "Install dependencies with Composer" uses: "ramsey/composer-install@v3" with: diff --git a/composer.json b/composer.json index 004368503f..de6dcbdc6d 100644 --- a/composer.json +++ b/composer.json @@ -44,7 +44,7 @@ "doctrine/persistence": "^3.3.1 || ^4", "psr/cache": "^1 || ^2 || ^3", "symfony/console": "^5.4 || ^6.0 || ^7.0 || ^8.0", - "symfony/var-exporter": "^6.3.9 || ^7.0" + "symfony/var-exporter": "^6.3.9 || ^7.0 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^14.0", @@ -54,7 +54,7 @@ "phpstan/phpstan-deprecation-rules": "^2", "phpunit/phpunit": "^10.5.0 || ^11.5", "psr/log": "^1 || ^2 || ^3", - "symfony/cache": "^5.4 || ^6.2 || ^7.0" + "symfony/cache": "^5.4 || ^6.2 || ^7.0 || ^8.0" }, "suggest": { "ext-dom": "Provides support for XSD validation for XML mapping files", diff --git a/src/ORMInvalidArgumentException.php b/src/ORMInvalidArgumentException.php index acf1393619..144b93913f 100644 --- a/src/ORMInvalidArgumentException.php +++ b/src/ORMInvalidArgumentException.php @@ -160,6 +160,11 @@ public static function proxyDirectoryRequired(): self return new self('You must configure a proxy directory. See docs for details'); } + public static function lazyGhostUnavailable(): self + { + return new self('Symfony LazyGhost is not available. Please install the "symfony/var-exporter" package version 6.4 or 7 to use this feature or enable PHP 8.4 native lazy objects.'); + } + public static function proxyNamespaceRequired(): self { return new self('You must configure a proxy namespace'); diff --git a/src/Proxy/ProxyFactory.php b/src/Proxy/ProxyFactory.php index 4518dfc187..e1bb99d02f 100644 --- a/src/Proxy/ProxyFactory.php +++ b/src/Proxy/ProxyFactory.php @@ -37,6 +37,7 @@ use function is_int; use function is_writable; use function ltrim; +use function method_exists; use function mkdir; use function preg_match_all; use function random_bytes; @@ -161,6 +162,11 @@ public function __construct( ); } + // @phpstan-ignore function.impossibleType (This method has been removed in Symfony 8) + if (! method_exists(ProxyHelper::class, 'generateLazyGhost')) { + throw ORMInvalidArgumentException::lazyGhostUnavailable(); + } + if (! $proxyDir) { throw ORMInvalidArgumentException::proxyDirectoryRequired(); } @@ -464,7 +470,7 @@ private function generateProxyClass(ClassMetadata $class, string|null $fileName, private function generateUseLazyGhostTrait(ClassMetadata $class): string { - // @phpstan-ignore staticMethod.deprecated (Because we support Symfony < 7.3) + // @phpstan-ignore staticMethod.notFound (This method has been removed in Symfony 8) $code = ProxyHelper::generateLazyGhost($class->getReflectionClass()); $code = substr($code, 7 + (int) strpos($code, "\n{")); $code = substr($code, 0, (int) strpos($code, "\n}")); diff --git a/tests/Tests/ORM/Persisters/BinaryIdPersisterTest.php b/tests/Tests/ORM/Persisters/BinaryIdPersisterTest.php index fdeaeddb12..f1ab47277b 100644 --- a/tests/Tests/ORM/Persisters/BinaryIdPersisterTest.php +++ b/tests/Tests/ORM/Persisters/BinaryIdPersisterTest.php @@ -16,6 +16,8 @@ use Doctrine\Tests\Models\BinaryPrimaryKey\Category; use Doctrine\Tests\OrmTestCase; +use const PHP_VERSION_ID; + final class BinaryIdPersisterTest extends OrmTestCase { private EntityManager|null $entityManager = null; @@ -64,6 +66,7 @@ private function createEntityManager(): EntityManager } $config = ORMSetup::createAttributeMetadataConfiguration([__DIR__ . '/../../Models/BinaryPrimaryKey'], isDevMode: true); + $config->enableNativeLazyObjects(PHP_VERSION_ID >= 80400); if (! DbalType::hasType(BinaryIdType::NAME)) { DbalType::addType(BinaryIdType::NAME, BinaryIdType::class); diff --git a/tests/Tests/ORM/Proxy/ProxyFactoryTest.php b/tests/Tests/ORM/Proxy/ProxyFactoryTest.php index 4e826ebca9..2295fd274c 100644 --- a/tests/Tests/ORM/Proxy/ProxyFactoryTest.php +++ b/tests/Tests/ORM/Proxy/ProxyFactoryTest.php @@ -10,6 +10,7 @@ use Doctrine\Deprecations\PHPUnit\VerifyDeprecations; use Doctrine\ORM\EntityNotFoundException; use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\ORMInvalidArgumentException; use Doctrine\ORM\Persisters\Entity\BasicEntityPersister; use Doctrine\ORM\Proxy\ProxyFactory; use Doctrine\Persistence\Mapping\RuntimeReflectionService; @@ -22,10 +23,12 @@ use Doctrine\Tests\OrmTestCase; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\IgnoreDeprecations; +use PHPUnit\Framework\Attributes\RequiresMethod; use PHPUnit\Framework\Attributes\RequiresPhp; use ReflectionClass; use ReflectionProperty; use stdClass; +use Symfony\Component\VarExporter\ProxyHelper; use function assert; use function method_exists; @@ -247,6 +250,7 @@ public function testProxyFactoryAcceptsNullProxyArgsWhenNativeLazyObjectsAreEnab } #[RequiresPhp('8.4')] + #[RequiresMethod(ProxyHelper::class, 'generateLazyGhost')] #[IgnoreDeprecations] public function testProxyFactoryTriggersDeprecationWhenNativeLazyObjectsAreDisabled(): void { @@ -276,6 +280,25 @@ public function testProxyFactoryDoesNotTriggerDeprecationWhenNativeLazyObjectsAr ProxyFactory::AUTOGENERATE_ALWAYS, ); } + + public function testProxyFactoryThrowsIfLazyGhostsAreUnavailable(): void + { + if (method_exists(ProxyHelper::class, 'generateLazyGhost')) { + self::markTestSkipped('This test is not relevant when lazy ghosts are available'); + } + + $this->emMock->getConfiguration()->enableNativeLazyObjects(false); + + $this->expectException(ORMInvalidArgumentException::class); + $this->expectExceptionMessage('Symfony LazyGhost is not available. Please install the "symfony/var-exporter" package version 6.4 or 7 to use this feature or enable PHP 8.4 native lazy objects.'); + + new ProxyFactory( + $this->emMock, + sys_get_temp_dir(), + 'Proxies', + ProxyFactory::AUTOGENERATE_ALWAYS, + ); + } } abstract class AbstractClass