1414use Doctrine \ODM \MongoDB \Proxy \InternalProxy ;
1515use Doctrine \ODM \MongoDB \Types \Type ;
1616use Doctrine \ODM \MongoDB \UnitOfWork ;
17+ use MongoDB \BSON \Document ;
1718use ProxyManager \Proxy \GhostObjectInterface ;
1819
19- use function array_key_exists ;
2020use function chmod ;
2121use function class_exists ;
2222use function dirname ;
@@ -169,8 +169,11 @@ private function generateHydratorClass(ClassMetadata $class, string $hydratorCla
169169 <<<EOF
170170
171171 // AlsoLoad(" $ name")
172- if (! array_key_exists('%1 \$s', \$data) && array_key_exists(' $ name', \$data)) {
172+ if (! \$data->has('%1 \$s') && \$data->has(' $ name')) {
173+ // @todo extracting and repacking is not very efficient
174+ \$data = \$data->toPHP(['root' => 'array', 'document' => 'bson', 'array' => 'bson']);
173175 \$data['%1 \$s'] = \$data[' $ name'];
176+ \$data = Document::fromPHP( \$data);
174177 }
175178
176179EOF
@@ -203,8 +206,11 @@ private function generateHydratorClass(ClassMetadata $class, string $hydratorCla
203206 <<<EOF
204207
205208 // Field(type: " {$ mapping ['type ' ]}")
206- if (isset( \$data['%1 \$s']) || (! empty( \$this->class->fieldMappings['%2 \$s']['nullable']) && array_key_exists('%1 \$s', \$data))) {
207- \$value = \$data['%1 \$s'];
209+ if ( \$data->has('%1 \$s') || (! empty( \$this->class->fieldMappings['%2 \$s']['nullable']) && \$data->has('%1 \$s'))) {
210+ \$value = \$data->get('%1 \$s');
211+ if ( \$value instanceof PackedArray || \$value instanceof Document) {
212+ \$value = \$value->toPHP(DocumentManager::CLIENT_TYPEMAP);
213+ }
208214 if ( \$value !== null) {
209215 \$typeIdentifier = \$this->class->fieldMappings['%2 \$s']['type'];
210216 %3 \$s
@@ -226,11 +232,11 @@ private function generateHydratorClass(ClassMetadata $class, string $hydratorCla
226232 <<<'EOF'
227233
228234 // ReferenceOne
229- if (isset( $data[ '%1$s'] ) || (! empty($this->class->fieldMappings['%2$s']['nullable']) && array_key_exists ('%1$s', $data ))) {
230- $return = $data[ '%1$s'] ;
235+ if ($data->has( '%1$s') || (! empty($this->class->fieldMappings['%2$s']['nullable']) && $data->has ('%1$s'))) {
236+ $return = $data->get( '%1$s') ;
231237 if ($return !== null) {
232- if ($this->class->fieldMappings['%2$s']['storeAs'] !== ClassMetadata::REFERENCE_STORE_AS_ID && ! is_array( $return) ) {
233- throw HydratorException::associationTypeMismatch('%3$s', '%1$s', 'array', gettype ($return));
238+ if ($this->class->fieldMappings['%2$s']['storeAs'] !== ClassMetadata::REFERENCE_STORE_AS_ID && ! $return instanceof Document ) {
239+ throw HydratorException::associationTypeMismatch('%3$s', '%1$s', Document::class, get_debug_type ($return));
234240 }
235241
236242 $className = $this->dm->getClassNameForAssociation($this->class->fieldMappings['%2$s'], $return);
@@ -295,10 +301,10 @@ private function generateHydratorClass(ClassMetadata $class, string $hydratorCla
295301 <<<'EOF'
296302
297303 // ReferenceMany & EmbedMany
298- $mongoData = $data[ '%1$s'] ?? null;
304+ $mongoData = $data->has( '%1$s') ? $data->get('%1$s') : null;
299305
300- if ($mongoData !== null && ! is_array( $mongoData) ) {
301- throw HydratorException::associationTypeMismatch('%3$s', '%1$s', 'array', gettype ($mongoData));
306+ if ($mongoData !== null && ! $mongoData instanceof PackedArray && ! $mongoData instanceof Document ) {
307+ throw HydratorException::associationTypeMismatch('%3$s', '%1$s', Document::class . '|' . PackedArray::class, get_debug_type ($mongoData));
302308 }
303309
304310 $return = $this->dm->getConfiguration()->getPersistentCollectionFactory()->create($this->dm, $this->class->fieldMappings['%2$s']);
@@ -322,13 +328,13 @@ private function generateHydratorClass(ClassMetadata $class, string $hydratorCla
322328 <<<'EOF'
323329
324330 // EmbedOne
325- if (isset( $data[ '%1$s'] ) || (! empty($this->class->fieldMappings['%2$s']['nullable']) && array_key_exists ('%1$s', $data ))) {
326- $return = $data[ '%1$s'] ;
331+ if ($data->has( '%1$s') || (! empty($this->class->fieldMappings['%2$s']['nullable']) && $data->has ('%1$s'))) {
332+ $return = $data->get( '%1$s') ;
327333 if ($return !== null) {
328334 $embeddedDocument = $return;
329335
330- if (! is_array( $embeddedDocument) ) {
331- throw HydratorException::associationTypeMismatch('%3$s', '%1$s', 'array', gettype ($embeddedDocument));
336+ if (! $embeddedDocument instanceof Document ) {
337+ throw HydratorException::associationTypeMismatch('%3$s', '%1$s', Document::class, get_debug_type ($embeddedDocument));
332338 }
333339
334340 $className = $this->dm->getClassNameForAssociation($this->class->fieldMappings['%2$s'], $embeddedDocument);
@@ -370,9 +376,11 @@ private function generateHydratorClass(ClassMetadata $class, string $hydratorCla
370376use Doctrine\ODM\MongoDB\Hydrator\HydratorInterface;
371377use Doctrine\ODM\MongoDB\Query\Query;
372378use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
379+ use MongoDB\BSON\Document;
380+ use MongoDB\BSON\PackedArray;
373381
374382use function array_key_exists;
375- use function gettype ;
383+ use function get_debug_type ;
376384use function is_array;
377385
378386/**
@@ -382,10 +390,11 @@ class $hydratorClassName implements HydratorInterface
382390{
383391 public function __construct(private DocumentManager \$dm, private ClassMetadata \$class) {}
384392
385- public function hydrate(object \$document, array \$data, array \$hints = []): array
393+ public function hydrate(object \$document, Document \$data, array \$hints = []): array
386394 {
387395 \$hydratedData = [];
388- %s return \$hydratedData;
396+ %s
397+ return \$hydratedData;
389398 }
390399}
391400EOF
@@ -425,13 +434,14 @@ public function hydrate(object \$document, array \$data, array \$hints = []): ar
425434 *
426435 * @return array<string, mixed>
427436 */
428- public function hydrate (object $ document , array $ data , array $ hints = []): array
437+ public function hydrate (object $ document , Document $ data , array $ hints = []): array
429438 {
430439 $ metadata = $ this ->dm ->getClassMetadata ($ document ::class);
431440 // Invoke preLoad lifecycle events and listeners
432441 if (! empty ($ metadata ->lifecycleCallbacks [Events::preLoad])) {
433- $ args = [new PreLoadEventArgs ($ document , $ this ->dm , $ data )];
434- $ metadata ->invokeLifecycleCallbacks (Events::preLoad, $ document , $ args );
442+ $ preloadEventArgs = new PreLoadEventArgs ($ document , $ this ->dm , $ data );
443+ $ metadata ->invokeLifecycleCallbacks (Events::preLoad, $ document , [$ preloadEventArgs ]);
444+ $ data = $ preloadEventArgs ->getRawData ();
435445 }
436446
437447 $ this ->evm ->dispatchEvent (Events::preLoad, new PreLoadEventArgs ($ document , $ this ->dm , $ data ));
@@ -441,8 +451,8 @@ public function hydrate(object $document, array $data, array $hints = []): array
441451 foreach ($ metadata ->alsoLoadMethods as $ method => $ fieldNames ) {
442452 foreach ($ fieldNames as $ fieldName ) {
443453 // Invoke the method only once for the first field we find
444- if (array_key_exists ($ fieldName, $ data )) {
445- $ document ->$ method ($ data[ $ fieldName] );
454+ if ($ data -> has ($ fieldName )) {
455+ $ document ->$ method ($ data-> get ( $ fieldName) );
446456 continue 2 ;
447457 }
448458 }
0 commit comments