PHP 8.4.0 RC2 available for testing

Deserialization from BSON

Avertissement

Les documents BSON peuvent techniquement contenir des clés dupliquées car les documents sont stockés en tant qu'une liste de paire clé-valeur ; cependant, les applications devrait s'abstenir de générer des documents avec des clés dupliquées car le comportement du serveur et du pilote peut être indéfinie. Puisque les objets et tableaux PHP ne peuvent pas avoir de clés dupliquées, les données pourraient aussi être perdu lors du décodage d'un document BSON avec des clés dupliquées.

L'extension mongodb désérialise les documents BSON et les tableaux BSON en tant que tableaux PHP. Tant que les tableaux PHP sont pratiques à utiliser, ce comportement était problématique car différents types BSON pouvaient être désérialisés en la même valeur PHP (par exemple {"0": "foo"} et ["foo"]) et rendait impossible d'inférer le type BSON original. Par défaut, l'extension mongodb adresse cette préoccupation en s'assurant que les tableaux BSON et les documents BSON sont convertis en tableaux et objets PHP, respectivement.

Pour les types composés, il existe trois types de données :

root

réfère à un document BSON de niveau supérieur seulement

document

réfère à des documents BSON imbriqués seulement

array

réfère à un tableau BSON

A part les trois types collectifs, il est aussi possible de configurer des champs spécifiques dans votre document pour mapper les types de données mentionnés ci-dessous. Par exemple, le type de carte suivant vous permet de mapper chaque document intégré dans un tableau "addresses" à une classe Address et chaque champ "city" dans ces documents d'adresse intégrés à une classe City:

[
    'fieldPaths' => [
        'addresses.$' => 'MyProject\Address',
        'addresses.$.city' => 'MyProject\City',
    ],
]

Chacun de ces trois types de données, ainsi que les mappages spécifiques aux champs, peuvent être mappés contre différents types PHP. Les valeurs de mappage possibles sont:

non défini ou NULL (par défaut)

  • Un tableau BSON sera désérialisé en un tableau PHP.

  • Un document BSON (racine ou imbriqué) sans propriété __pclass [1] devient un objet stdClass, avec chaque clé de document BSON définie comme une propriété de stdClass publique.

  • Un document BSON (racine ou imbriqué) avec une propriété __pclass devient un objet PHP de la classe nommée par la propriété __pclass.

    Si la classe nommée implémente l'interface MongoDB\BSON\Persistable, alors les propriétés du document BSON, y compris la propriété __pclass, sont envoyées sous forme de tableau associatif à la fonction MongoDB\BSON\Unserializable::bsonUnserialize() pour initialiser les propriétés de l'objet.

    Si la classe nommée n'existe pas ou n'implémente pas l'interface MongoDB\BSON\Persistable, stdClass sera utilisé et chaque clé de document BSON (y compris __pclass) sera définie comme une propriété publique de stdClass.

    La fonctionnalité __pclass repose sur le fait que la propriété soit partie d'un document MongoDB récupéré. Si vous utilisez une » projection lors de la recherche de documents, vous devez inclure le champ __pclass dans la projection pour que cette fonctionnalité fonctionne.

"array"

Transforme un tableau BSON en un tableau PHP. Il n'y aura pas de traitement spécial d'une propriété __pclass [1] mais elle peut être définie comme un élément dans le tableau retourné si elle était présente dans le document BSON.

"object" ou "stdClass"

Transforme un tableau BSON ou un document BSON en un objet stdClass. Il n'y aura pas de traitement spécial d'une propriété __pclass [1] mais elle peut être définie comme une propriété publique dans l'objet retourné si elle était présente dans le document BSON.

"bson"

Transforme un tableau BSON en un MongoDB\BSON\PackedArray et un document BSON en un MongoDB\BSON\Document, indépendamment du fait que le document BSON ait une propriété __pclass [1].

Note: La valeur bson n'est disponible que pour les trois types racines, et non dans les mappages spécifiques aux champs.

toues les autres chaînes de caractères

Définit le nom de la classe à laquelle le document BSON doit être désérialisé. Pour les documents BSON qui incluent des propriétés __pclass, cette classe prendra la priorité.

Si la classe nommée n'existe pas ou n'implémente pas l'interface MongoDB\BSON\Unserializable, une exception MongoDB\Driver\Exception\InvalidArgumentException est lancée.

Si l'objet BSON a une propriété __pclass et que cette classe existe et implémente MongoDB\BSON\Persistable, elle prendra le pas sur la classe fournie dans la carte de type.

Les propriétés du document BSON, y compris la propriété __pclass, seront envoyées sous forme de tableau associatif à la fonction MongoDB\BSON\Unserializable::bsonUnserialize() pour initialiser les propriétés de l'objet.

TypeMaps

Les TypeMaps peuvent être définis via la méthode MongoDB\Driver\Cursor::setTypeMap() sur un objet MongoDB\Driver\Cursor, ou l'argument $typeMap de MongoDB\BSON\toPHP(), MongoDB\BSON\Document::toPHP(), et MongoDB\BSON\PackedArray::toPHP(). Chacune des trois classes (racine, document, et array) peut être définie individuellement, en plus des types spécifiques aux champs.

Si la valeur dans le TypeMap est NULL, cela signifie la même chose que la valeur par défaut pour cet élément.

Exemples

Ces exemples utilisent les classes suivantes:

MyClass

qui n'implémente aucune interface

YourClass

qui implémente MongoDB\BSON\Unserializable

OurClass

qui implémente MongoDB\BSON\Persistable

TheirClass

qui étends OurClass

La méthode MongoDB\BSON\Unserializable::bsonUnserialize() de YourClass, OurClass, TheirClass itère sur le tableau et définit les propriétés sans modifications. Elle ajoute aussi la propriété $unserialized à true:

<?php

function bsonUnserialize( array $map )
{
foreach (
$map as $k => $value )
{
$this->$k = $value;
}
$this->unserialized = true;
}

/* typemap: [] (all defaults) */
{ "foo": "yes", "bar" : false }
  -> stdClass { $foo => 'yes', $bar => false }

{ "foo": "no", "array" : [ 5, 6 ] }
  -> stdClass { $foo => 'no', $array => [ 5, 6 ] }

{ "foo": "no", "obj" : { "embedded" : 3.14 } }
  -> stdClass { $foo => 'no', $obj => stdClass { $embedded => 3.14 } }

{ "foo": "yes", "__pclass": "MyClass" }
  -> stdClass { $foo => 'yes', $__pclass => 'MyClass' }

{ "foo": "yes", "__pclass": { "$type" : "80", "$binary" : "MyClass" } }
  -> stdClass { $foo => 'yes', $__pclass => Binary(0x80, 'MyClass') }

{ "foo": "yes", "__pclass": { "$type" : "80", "$binary" : "YourClass") }
  -> stdClass { $foo => 'yes', $__pclass => Binary(0x80, 'YourClass') }

{ "foo": "yes", "__pclass": { "$type" : "80", "$binary" : "OurClass") }
  -> OurClass { $foo => 'yes', $__pclass => Binary(0x80, 'OurClass'), $unserialized => true }

{ "foo": "yes", "__pclass": { "$type" : "44", "$binary" : "YourClass") }
  -> stdClass { $foo => 'yes', $__pclass => Binary(0x44, 'YourClass') }

/* typemap: [ "root" => "MissingClass" ] */
{ "foo": "yes" }
  -> MongoDB\Driver\Exception\InvalidArgumentException("MissingClass does not exist")

/* typemap: [ "root" => "MyClass" ] */
{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "MyClass" } }
  -> MongoDB\Driver\Exception\InvalidArgumentException("MyClass does not implement Unserializable interface")

/* typemap: [ "root" => "MongoDB\BSON\Unserializable" ] */
{ "foo": "yes" }
  -> MongoDB\Driver\Exception\InvalidArgumentException("Unserializable is not a concrete class")

/* typemap: [ "root" => "YourClass" ] */
{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "MongoDB\BSON\Unserializable" } }
  -> YourClass { $foo => "yes", $__pclass => Binary(0x80, "MongoDB\BSON\Unserializable"), $unserialized => true }

/* typemap: [ "root" => "YourClass" ] */
{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "MyClass" } }
  -> YourClass { $foo => "yes", $__pclass => Binary(0x80, "MyClass"), $unserialized => true }

/* typemap: [ "root" => "YourClass" ] */
{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "OurClass" } }
  -> OurClass { $foo => "yes", $__pclass => Binary(0x80, "OurClass"), $unserialized => true }

/* typemap: [ "root" => "YourClass" ] */
{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "TheirClass" } }
  -> TheirClass { $foo => "yes", $__pclass => Binary(0x80, "TheirClass"), $unserialized => true }

/* typemap: [ "root" => "OurClass" ] */
{ foo: "yes", "__pclass" : { "$type": "80", "$binary": "TheirClass" } }
  -> TheirClass { $foo => "yes", $__pclass => Binary(0x80, "TheirClass"), $unserialized => true }

/* typemap: [ 'root' => 'YourClass' ] */
{ foo: "yes", "__pclass" : { "$type": "80", "$binary": "YourClass" } }
  -> YourClass { $foo => 'yes', $__pclass => Binary(0x80, 'YourClass'), $unserialized => true }

/* typemap: [ 'root' => 'array', 'document' => 'array' ] */
{ "foo": "yes", "bar" : false }
  -> [ "foo" => "yes", "bar" => false ]

{ "foo": "no", "array" : [ 5, 6 ] }
  -> [ "foo" => "no", "array" => [ 5, 6 ] ]

{ "foo": "no", "obj" : { "embedded" : 3.14 } }
  -> [ "foo" => "no", "obj" => [ "embedded => 3.14 ] ]

{ "foo": "yes", "__pclass": "MyClass" }
  -> [ "foo" => "yes", "__pclass" => "MyClass" ]

{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "MyClass" } }
  -> [ "foo" => "yes", "__pclass" => Binary(0x80, "MyClass") ]

{ "foo": "yes", "__pclass" : { "$type": "80", "$binary": "OurClass" } }
  -> [ "foo" => "yes", "__pclass" => Binary(0x80, "OurClass") ]

/* typemap: [ 'root' => 'object', 'document' => 'object' ] */
{ "foo": "yes", "__pclass": { "$type": "80", "$binary": "MyClass" } }
  -> stdClass { $foo => "yes", "__pclass" => Binary(0x80, "MyClass") }

add a note

User Contributed Notes 3 notes

up
2
Miguel
6 years ago
Make sure you include the field "__pclass" to the projection if you want the ODM to automatically call the bsonUnserialize of the class.

If you don't get that field in the query, the ODM will never know which class to call, so you'll have to specify it with the "typemap" variable.
up
2
hello at stefandjokic dot com
4 years ago
Minor correction to my previous comment:

Use 'fieldPaths' for specifying type of nested property.

Eg.

'typeMap' => [
'array' => 'array',
'fieldPaths' => [
'notifications.email.to' => 'array',
'notifications.data.params' => 'array',
],
],
up
0
hello at stefandjokic dot com
4 years ago
You can also specify the type map for nested document item, e.g.

<?php
.
.
.
// everything else is by default an object
'typeMap' => [
'customer.phones' => 'array',
],
To Top