1616use Patchlevel \Hydrator \Metadata \ClassNotFound ;
1717use Patchlevel \Hydrator \Metadata \MetadataFactory ;
1818use Patchlevel \Hydrator \Normalizer \HydratorAwareNormalizer ;
19+ use ReflectionClass ;
1920use ReflectionParameter ;
2021use Symfony \Component \EventDispatcher \EventDispatcher ;
2122use Symfony \Component \EventDispatcher \EventDispatcherInterface ;
@@ -36,6 +37,7 @@ public function __construct(
3637 private readonly MetadataFactory $ metadataFactory = new AttributeMetadataFactory (),
3738 PayloadCryptographer |null $ cryptographer = null ,
3839 private EventDispatcherInterface |null $ eventDispatcher = null ,
40+ private readonly bool $ defaultLazy = false ,
3941 ) {
4042 if (!$ cryptographer ) {
4143 return ;
@@ -66,6 +68,31 @@ public function hydrate(string $class, array $data): object
6668 throw new ClassNotSupported ($ class , $ e );
6769 }
6870
71+ $ lazy = $ metadata ->lazy () === null
72+ ? $ this ->defaultLazy
73+ : $ metadata ->lazy ();
74+
75+ if (!$ lazy ) {
76+ return $ this ->doHydrate ($ metadata , $ data );
77+ }
78+
79+ return (new ReflectionClass ($ class ))->newLazyProxy (
80+ function () use ($ metadata , $ data ): object {
81+ return $ this ->doHydrate ($ metadata , $ data );
82+ },
83+ );
84+ }
85+
86+ /**
87+ * @param ClassMetadata<T> $metadata
88+ * @param array<string, mixed> $data
89+ *
90+ * @return T
91+ *
92+ * @template T of object
93+ */
94+ private function doHydrate (ClassMetadata $ metadata , array $ data ): object
95+ {
6996 if ($ this ->eventDispatcher ) {
7097 $ data = $ this ->eventDispatcher ->dispatch (new PreHydrate ($ data , $ metadata ))->data ;
7198 }
@@ -110,7 +137,7 @@ public function hydrate(string $class, array $data): object
110137 $ value = $ normalizer ->denormalize ($ value );
111138 } catch (Throwable $ e ) {
112139 throw new DenormalizationFailure (
113- $ class ,
140+ $ metadata -> className () ,
114141 $ propertyMetadata ->propertyName (),
115142 $ normalizer ::class,
116143 $ e ,
@@ -122,7 +149,7 @@ public function hydrate(string $class, array $data): object
122149 $ propertyMetadata ->setValue ($ object , $ value );
123150 } catch (TypeError $ e ) {
124151 throw new TypeMismatch (
125- $ class ,
152+ $ metadata -> className () ,
126153 $ propertyMetadata ->propertyName (),
127154 $ e ,
128155 );
@@ -234,6 +261,7 @@ private function promotedConstructorParametersWithDefaultValue(ClassMetadata $me
234261 public static function create (
235262 iterable $ guessers = [],
236263 EventDispatcherInterface |null $ eventDispatcher = null ,
264+ bool $ defaultLazy = false ,
237265 ): self {
238266 $ guesser = new BuiltInGuesser ();
239267
@@ -250,6 +278,7 @@ public static function create(
250278 ),
251279 null ,
252280 $ eventDispatcher ,
281+ $ defaultLazy ,
253282 );
254283 }
255284}
0 commit comments