22
33namespace PHPStan \Rules \Doctrine \ORM ;
44
5+ use Doctrine \ORM \Configuration ;
56use Iterator ;
67use PHPStan \Rules \Rule ;
78use PHPStan \Testing \RuleTestCase ;
89use PHPStan \Type \Doctrine \ObjectMetadataResolver ;
10+ use function method_exists ;
11+ use const PHP_VERSION_ID ;
912
1013/**
1114 * @extends RuleTestCase<EntityNotFinalRule>
@@ -34,7 +37,7 @@ public function testRule(string $file, array $expectedErrors): void
3437 }
3538
3639 /**
37- * @dataProvider ruleProvider
40+ * @dataProvider ruleWithoutObjectManagerLoaderProvider
3841 * @param list<array{0: string, 1: int, 2?: string}> $expectedErrors
3942 */
4043 public function testRuleWithoutObjectManagerLoader (string $ file , array $ expectedErrors ): void
@@ -43,19 +46,86 @@ public function testRuleWithoutObjectManagerLoader(string $file, array $expected
4346 $ this ->analyse ([$ file ], $ expectedErrors );
4447 }
4548
49+ /**
50+ * @dataProvider ruleWithNativeLazyObjectsProvider
51+ * @param list<array{0: string, 1: int, 2?: string}> $expectedErrors
52+ */
53+ public function testRuleWithNativeLazyObjects (string $ file , array $ expectedErrors ): void
54+ {
55+ // @phpstan-ignore function.impossibleType, function.alreadyNarrowedType
56+ if (PHP_VERSION_ID < 80400 || !method_exists (Configuration::class, 'enableNativeLazyObjects ' )) {
57+ self ::markTestSkipped ('Test requires PHP 8.4+ and Doctrine ORM 3.4+. ' );
58+ }
59+
60+ $ this ->objectManagerLoader = __DIR__ . '/entity-manager-lazy-ghost-objects.php ' ;
61+ $ this ->analyse ([$ file ], $ expectedErrors );
62+ }
63+
4664 /**
4765 * @return Iterator<mixed[]>
4866 */
4967 public function ruleProvider (): Iterator
5068 {
69+ $ finalEntityErrors = self ::isNativeLazyObjectsDefault ()
70+ ? []
71+ : [
72+ [
73+ 'Entity class PHPStan\Rules\Doctrine\ORM\FinalEntity is final which can cause problems with proxies. ' ,
74+ 10 ,
75+ ],
76+ ];
77+
5178 yield 'final entity ' => [
5279 __DIR__ . '/data/FinalEntity.php ' ,
53- [
80+ $ finalEntityErrors ,
81+ ];
82+
83+ yield 'final annotated entity ' => [
84+ __DIR__ . '/data/FinalAnnotatedEntity.php ' ,
85+ [],
86+ ];
87+
88+ yield 'final non-entity ' => [
89+ __DIR__ . '/data/FinalNonEntity.php ' ,
90+ [],
91+ ];
92+
93+ yield 'correct entity ' => [
94+ __DIR__ . '/data/MyEntity.php ' ,
95+ [],
96+ ];
97+
98+ yield 'final embeddable ' => [
99+ __DIR__ . '/data/FinalEmbeddable.php ' ,
100+ [],
101+ ];
102+
103+ yield 'non final embeddable ' => [
104+ __DIR__ . '/data/MyEmbeddable.php ' ,
105+ [],
106+ ];
107+ }
108+
109+ /**
110+ * @return Iterator<mixed[]>
111+ */
112+ public function ruleWithoutObjectManagerLoaderProvider (): Iterator
113+ {
114+ $ nativeLazyObjectsFallback = PHP_VERSION_ID >= 80400
115+ && method_exists (Configuration::class, 'enableNativeLazyObjects ' ); // @phpstan-ignore function.impossibleType, function.alreadyNarrowedType
116+
117+ $ finalEntityErrors = $ nativeLazyObjectsFallback
118+ ? []
119+ : [
54120 [
55121 'Entity class PHPStan\Rules\Doctrine\ORM\FinalEntity is final which can cause problems with proxies. ' ,
56122 10 ,
57123 ],
58- ],
124+ ];
125+
126+ yield 'final entity ' => [
127+ __DIR__ . '/data/FinalEntity.php ' ,
128+ $ finalEntityErrors ,
59129 ];
60130
61131 yield 'final annotated entity ' => [
@@ -84,4 +154,50 @@ public function ruleProvider(): Iterator
84154 ];
85155 }
86156
157+ /**
158+ * @return Iterator<mixed[]>
159+ */
160+ public function ruleWithNativeLazyObjectsProvider (): Iterator
161+ {
162+ yield 'final entity with native lazy objects ' => [
163+ __DIR__ . '/data/FinalEntity.php ' ,
164+ [],
165+ ];
166+
167+ yield 'final annotated entity with native lazy objects ' => [
168+ __DIR__ . '/data/FinalAnnotatedEntity.php ' ,
169+ [],
170+ ];
171+
172+ yield 'final non-entity with native lazy objects ' => [
173+ __DIR__ . '/data/FinalNonEntity.php ' ,
174+ [],
175+ ];
176+
177+ yield 'correct entity with native lazy objects ' => [
178+ __DIR__ . '/data/MyEntity.php ' ,
179+ [],
180+ ];
181+
182+ yield 'final embeddable with native lazy objects ' => [
183+ __DIR__ . '/data/FinalEmbeddable.php ' ,
184+ [],
185+ ];
186+
187+ yield 'non final embeddable with native lazy objects ' => [
188+ __DIR__ . '/data/MyEmbeddable.php ' ,
189+ [],
190+ ];
191+ }
192+
193+ private static function isNativeLazyObjectsDefault (): bool
194+ {
195+ // @phpstan-ignore function.impossibleType, function.alreadyNarrowedType
196+ if (!method_exists (Configuration::class, 'isNativeLazyObjectsEnabled ' )) {
197+ return false ;
198+ }
199+
200+ return (new Configuration ())->isNativeLazyObjectsEnabled ();
201+ }
202+
87203}
0 commit comments