mongodb-php-persistence-php-deserialization-4

  • Persisting Data
  • Deserialization from BSON

  • Deserialization from BSON
  • Deserialization from BSON

    Deserialization from BSON

    The legacy mongo extension deserialized both BSON documents and
    arrays as PHP arrays. While PHP arrays are convenient to work with,
    this behavior was problematic because different BSON types could
    deserialize to the same PHP value (e.g. {“0”: “foo”} and
    [“foo”]) and make it impossible to infer the original BSON
    type. By default, the current driver addresses this concern by
    ensuring that BSON arrays and documents are converted to PHP arrays
    and objects, respectively.

    For compound types, there are three data types:

    root

    refers to the top-level BSON document only

    document

    refers to embedded BSON documents only

    array

    refers to a BSON array

    Besides the three collective types, it is also
    possible to configure specific fields in your document to map to
    the data types mentioned below. As an example, the following type
    map allows you to map each embedded document within an
    “addresses” array to an Address class and
    each “city” field within those embedded address documents
    to a City class:

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

    Each of those three data types, as well as the
    field specific mappings, can be mapped against different PHP types.
    The possible mapping values are:

    not set or NULL (default)

    • A BSON array will be deserialized as a PHP
      array.

    • A BSON document (root or embedded) without a
      __pclass property [1] becomes a PHP stdClass object, with each BSON document key
      set as a public stdClass
      property.

    • A BSON document (root or embedded) with a
      __pclass property [1] becomes a PHP object of
      the class name as defined by the __pclass property.

      If the named class implements the MongoDB\BSON\Persistable
      interface, then the properties of the BSON document, including the
      __pclass property, are sent as an
      associative array to the MongoDB\BSON\Unserializable::bsonUnserialize()
      function to initialise the object’s properties.

      If the named class does not exist or does not
      implement the MongoDB\BSON\Persistable interface,
      stdClass will be used and each
      BSON document key (including __pclass) will be set as a public stdClass property.

      The __pclass
      functionality relies on the property being part of a retrieved
      MongoDB document. If you use a projection when querying for documents, you need
      to include the __pclass field in the
      projection for this functionality to work.

    “array”

    Turns a BSON array or BSON document into a PHP
    array. There will be no special treatment of a __pclass property [1], but it may be set as an
    element in the returned array if it was present in the BSON
    document.

    “object” or “stdClass”

    Turns a BSON array or BSON document into a
    stdClass object. There will be
    no special treatment of a __pclass
    property [1], but it
    may be set as a public property in the returned object if it was
    present in the BSON document.

    any other string

    Defines the class name that the BSON array or BSON
    object should be deserialized as. For BSON objects that include
    __pclass properties, that class will
    take priority.

    If the named class does not exist, is not concrete
    (i.e. it is abstract or an interface), or does not implement
    MongoDB\BSON\Unserializable then an
    MongoDB\Driver\Exception\InvalidArgumentException
    exception is thrown.

    If the BSON object has a __pclass property and that class exists and
    implements MongoDB\BSON\Persistable it will
    supersede the class provided in the type map.

    The properties of the BSON document, including the __pclass property if it exists, will be sent as
    an associative array to the MongoDB\BSON\Unserializable::bsonUnserialize()
    function to initialise the object’s properties.

    TypeMaps

    TypeMaps can be set through the MongoDB\Driver\Cursor::setTypeMap() method
    on a MongoDB\Driver\Cursor object, or the
    $typeMap argument of MongoDB\BSON\toPHP(). Each of the three
    classes (root, document, and array) can
    be individually set, in addition to the field specific types.

    If the value in the map is NULL, it means the same as the default value for that item.

    Examples

    These examples use the following classes:

    MyClass

    which does not implement
    any interface

    YourClass

    which implements MongoDB\BSON\Unserializable

    OurClass

    which implements MongoDB\BSON\Persistable

    TheirClass

    which extends OurClass

    The MongoDB\BSON\Unserializable::bsonUnserialize()
    method of YourClass, OurClass, TheirClass iterate over the array
    and set the properties without modifications. It also sets the $unserialized property to
    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") }