3232use TypeLang \Mapper \Mapping \Metadata \TypeMetadata ;
3333use TypeLang \Mapper \Mapping \Reader \ReaderInterface ;
3434use TypeLang \Mapper \Mapping \Reader \ReflectionReader ;
35+ use TypeLang \Mapper \Mapping \Reference \Reader \NativeReferencesReader ;
36+ use TypeLang \Mapper \Mapping \Reference \Reader \ReferencesReaderInterface ;
37+ use TypeLang \Mapper \Mapping \Reference \ReferencesResolver ;
3538use TypeLang \Mapper \Runtime \Parser \TypeParserInterface ;
3639use TypeLang \Mapper \Runtime \Repository \TypeRepositoryInterface ;
3740
@@ -40,13 +43,18 @@ final class MetadataReaderProvider implements ProviderInterface
4043 /**
4144 * @var array<class-string, ClassMetadata<object>>
4245 */
43- private array $ references = [];
46+ private array $ metadata = [];
47+
48+ private readonly ReferencesResolver $ references ;
4449
4550 public function __construct (
4651 private readonly ReaderInterface $ reader = new ReflectionReader (),
4752 private ?ExpressionLanguage $ expression = null ,
4853 private readonly ?ClockInterface $ clock = null ,
49- ) {}
54+ ReferencesReaderInterface $ references = new NativeReferencesReader (),
55+ ) {
56+ $ this ->references = new ReferencesResolver ($ references );
57+ }
5058
5159 private function now (): ?int
5260 {
@@ -61,7 +69,6 @@ private function now(): ?int
6169 * @param \ReflectionClass<TArg> $class
6270 *
6371 * @return ClassMetadata<TArg>
64- *
6572 * @throws \Throwable
6673 */
6774 public function getClassMetadata (
@@ -92,20 +99,22 @@ private function toProxyClassMetadata(
9299 TypeParserInterface $ parser ,
93100 ): ClassMetadata {
94101 /** @var ClassMetadata<TArg> */
95- return $ this ->references [$ class ->name ] ??=
102+ return $ this ->metadata [$ class ->name ] ??=
96103 (new \ReflectionClass (ClassMetadata::class))
97104 ->newLazyProxy (function () use ($ class , $ types , $ parser ): ClassMetadata {
98105 $ info = $ this ->reader ->read ($ class );
99106
100107 $ metadata = new ClassMetadata (
101108 name: $ info ->name ,
102109 properties: $ this ->toPropertiesMetadata (
110+ context: $ class ,
103111 parent: $ info ,
104112 properties: $ info ->properties ,
105113 types: $ types ,
106114 parser: $ parser ,
107115 ),
108116 discriminator: $ this ->toOptionalDiscriminator (
117+ context: $ class ,
109118 parent: $ info ,
110119 info: $ info ->discriminator ,
111120 types: $ types ,
@@ -116,7 +125,7 @@ private function toProxyClassMetadata(
116125 createdAt: $ this ->now (),
117126 );
118127
119- unset($ this ->references [$ class ->name ]);
128+ unset($ this ->metadata [$ class ->name ]);
120129
121130 return $ metadata ;
122131 });
@@ -135,14 +144,14 @@ private function toLazyInitializedClassMetadata(
135144 TypeRepositoryInterface $ types ,
136145 TypeParserInterface $ parser ,
137146 ): ClassMetadata {
138- if (isset ($ this ->references [$ class ->name ])) {
147+ if (isset ($ this ->metadata [$ class ->name ])) {
139148 /** @var ClassMetadata<TArg> */
140- return $ this ->references [$ class ->name ];
149+ return $ this ->metadata [$ class ->name ];
141150 }
142151
143152 $ info = $ this ->reader ->read ($ class );
144153
145- $ this ->references [$ class ->name ] = $ metadata = new ClassMetadata (
154+ $ this ->metadata [$ class ->name ] = $ metadata = new ClassMetadata (
146155 name: $ info ->name ,
147156 isNormalizeAsArray: $ info ->isNormalizeAsArray ,
148157 typeErrorMessage: $ info ->typeErrorMessage ,
@@ -151,6 +160,7 @@ private function toLazyInitializedClassMetadata(
151160
152161 /** @phpstan-ignore-next-line : Allow readonly writing */
153162 $ metadata ->properties = $ this ->toPropertiesMetadata (
163+ context: $ class ,
154164 parent: $ info ,
155165 properties: $ info ->properties ,
156166 types: $ types ,
@@ -159,26 +169,29 @@ private function toLazyInitializedClassMetadata(
159169
160170 /** @phpstan-ignore-next-line : Allow readonly writing */
161171 $ metadata ->discriminator = $ this ->toOptionalDiscriminator (
172+ context: $ class ,
162173 parent: $ info ,
163174 info: $ info ->discriminator ,
164175 types: $ types ,
165176 parser: $ parser ,
166177 );
167178
168- unset($ this ->references [$ class ->name ]);
179+ unset($ this ->metadata [$ class ->name ]);
169180
170181 /** @var ClassMetadata<TArg> */
171182 return $ metadata ;
172183 }
173184
174185 /**
186+ * @param \ReflectionClass<object> $context
175187 * @param ClassInfo<object> $parent
176188 * @param iterable<mixed, PropertyInfo> $properties
177189 *
178190 * @return array<non-empty-string, PropertyMetadata>
179191 * @throws \Throwable
180192 */
181193 private function toPropertiesMetadata (
194+ \ReflectionClass $ context ,
182195 ClassInfo $ parent ,
183196 iterable $ properties ,
184197 TypeRepositoryInterface $ types ,
@@ -187,31 +200,33 @@ private function toPropertiesMetadata(
187200 $ result = [];
188201
189202 foreach ($ properties as $ property ) {
190- $ result [$ property ->name ] = $ this ->toPropertyMetadata ($ parent , $ property , $ types , $ parser );
203+ $ result [$ property ->name ] = $ this ->toPropertyMetadata ($ context , $ parent , $ property , $ types , $ parser );
191204 }
192205
193206 return $ result ;
194207 }
195208
196209 /**
210+ * @param \ReflectionClass<object> $context
197211 * @param ClassInfo<object> $parent
198212 *
199213 * @throws \Throwable
200214 */
201215 private function toPropertyMetadata (
216+ \ReflectionClass $ context ,
202217 ClassInfo $ parent ,
203218 PropertyInfo $ property ,
204219 TypeRepositoryInterface $ types ,
205220 TypeParserInterface $ parser ,
206221 ): PropertyMetadata {
207222 try {
208- $ read = $ this ->toTypeMetadata ($ property ->read , $ types , $ parser );
223+ $ read = $ this ->toTypeMetadata ($ context , $ property ->read , $ types , $ parser );
209224 } catch (TypeNotFoundException $ e ) {
210225 throw $ this ->toPropertyTypeException ($ e , $ parent , $ property , $ property ->read );
211226 }
212227
213228 try {
214- $ write = $ this ->toTypeMetadata ($ property ->write , $ types , $ parser );
229+ $ write = $ this ->toTypeMetadata ($ context , $ property ->write , $ types , $ parser );
215230 } catch (TypeNotFoundException $ e ) {
216231 throw $ this ->toPropertyTypeException ($ e , $ parent , $ property , $ property ->write );
217232 }
@@ -309,11 +324,13 @@ private function toDefaultValueMetadata(DefaultValueInfo $info): DefaultValueMet
309324 }
310325
311326 /**
327+ * @param \ReflectionClass<object> $context
312328 * @param ClassInfo<object> $parent
313329 *
314330 * @throws \Throwable
315331 */
316332 private function toOptionalDiscriminator (
333+ \ReflectionClass $ context ,
317334 ClassInfo $ parent ,
318335 ?DiscriminatorInfo $ info ,
319336 TypeRepositoryInterface $ types ,
@@ -323,15 +340,17 @@ private function toOptionalDiscriminator(
323340 return null ;
324341 }
325342
326- return $ this ->toDiscriminator ($ parent , $ info , $ types , $ parser );
343+ return $ this ->toDiscriminator ($ context , $ parent , $ info , $ types , $ parser );
327344 }
328345
329346 /**
347+ * @param \ReflectionClass<object> $context
330348 * @param ClassInfo<object> $parent
331349 *
332350 * @throws \Throwable
333351 */
334352 private function toDiscriminator (
353+ \ReflectionClass $ context ,
335354 ClassInfo $ parent ,
336355 DiscriminatorInfo $ info ,
337356 TypeRepositoryInterface $ types ,
@@ -341,37 +360,42 @@ private function toDiscriminator(
341360
342361 return new DiscriminatorMetadata (
343362 field: $ info ->field ,
344- map: $ this ->toDiscriminatorMap ($ info ->map , $ types , $ parser ),
345- default: $ this ->toOptionalTypeMetadata ($ info ->default , $ types , $ parser ),
363+ map: $ this ->toDiscriminatorMap ($ context , $ info ->map , $ types , $ parser ),
364+ default: $ this ->toOptionalTypeMetadata ($ context , $ info ->default , $ types , $ parser ),
346365 createdAt: $ this ->now (),
347366 );
348367 }
349368
350369 /**
370+ * @param \ReflectionClass<object> $context
351371 * @param non-empty-array<non-empty-string, TypeInfo> $map
352372 *
353373 * @return non-empty-array<non-empty-string, TypeMetadata>
354374 * @throws \Throwable
355375 */
356376 private function toDiscriminatorMap (
377+ \ReflectionClass $ context ,
357378 array $ map ,
358379 TypeRepositoryInterface $ types ,
359380 TypeParserInterface $ parser ,
360381 ): array {
361382 $ result = [];
362383
363384 foreach ($ map as $ value => $ type ) {
364- $ result [$ value ] = $ this ->toTypeMetadata ($ type , $ types , $ parser );
385+ $ result [$ value ] = $ this ->toTypeMetadata ($ context , $ type , $ types , $ parser );
365386 }
366387
367388 /** @var non-empty-array<non-empty-string, TypeMetadata> $result */
368389 return $ result ;
369390 }
370391
371392 /**
393+ * @param \ReflectionClass<object> $context
394+ *
372395 * @throws \Throwable
373396 */
374397 private function toOptionalTypeMetadata (
398+ \ReflectionClass $ context ,
375399 ?TypeInfo $ type ,
376400 TypeRepositoryInterface $ types ,
377401 TypeParserInterface $ parser ,
@@ -380,13 +404,16 @@ private function toOptionalTypeMetadata(
380404 return null ;
381405 }
382406
383- return $ this ->toTypeMetadata ($ type , $ types , $ parser );
407+ return $ this ->toTypeMetadata ($ context , $ type , $ types , $ parser );
384408 }
385409
386410 /**
411+ * @param \ReflectionClass<object> $context
412+ *
387413 * @throws \Throwable
388414 */
389415 private function toTypeMetadata (
416+ \ReflectionClass $ context ,
390417 TypeInfo $ info ,
391418 TypeRepositoryInterface $ types ,
392419 TypeParserInterface $ parser ,
@@ -400,6 +427,8 @@ private function toTypeMetadata(
400427 ))
401428 };
402429
430+ $ statement = $ this ->references ->resolve ($ statement , $ context );
431+
403432 $ type = $ types ->getTypeByStatement ($ statement );
404433
405434 return new TypeMetadata (
0 commit comments