Este documento trata sobre los métodos de cómo las estructuras compuestas (documentos, arrays, objetos) se hacen persistentes a través de los controladores y de cómo son llevadas de vuelta a PHP.
Si un array es un array compacto, esto es, las claves empiezan en 0 y están en secuencia sin huecos: array BSON.
Si el array no es compacto, esto es, tiene claves asociativas (string), las claves no comienzan en 0, o cuando hay huecos: objeto BSON
Un documento del más alto nivel (raíz), siempre se serializa como un documento BSON.
Los siguientes arrays se serializan como arrays BSON:
[ 8, 5, 2, 3 ] => [ 8, 5, 2, 3 ] [ 0 => 4, 1 => 9 ] => [ 4, 9 ]
Estos se serializan como documentos BSON:
[ 0 => 1, 2 => 8, 3 => 12 ] => { "0" : 1, "2" : 8, "3" : 12 } [ "foo" => 42 ] => { "foo" : 42 } [ 1 => 9, 0 => 10 ] => { "1" : 9, "0" : 10 }
Observe que los cinco ejemplos son fragmentos de un documento completo que representan solamente un valor dentro de un documento.
Si un objeto es de la clase stdClass se serializa como un documento BSON.
Si un objeto es de una clase admitida que implementa MongoDB\BSON\Tipo, se utiliza la lógica de serialización BSON para un tipo específico. Las instancias de MongoDB\BSON\Tipo (excluyendo MongoDB\BSON\Serializable solo podrían ser serializadas como un valor de campo de documento. Intentar serializar tales objetos como un documento raíz lanzará una MongoDB\Driver\Exception\UnexpectedValueException
Si un objeto se de una clase desconocida que implementa la interfaz MongoDB\BSON\Tipo, lanza una MongoDB\Driver\Exception\UnexpectedValueException
Si un objeto es de cualquier otra clase que no implemente ninguna interfaz especial, se serializa como un documento BSON. Se mantienen solo las propiedades public y se ignoran las propiedades protected y private.
Si un objeto es de una clase que implementa la interfaz MongoDB\BSON\Serializable, se llama a MongoDB\BSON\Serializable::bsonSerialize() y se utiliza el array u objeto stdClass devuelto para serilizarlo como un documento BSON o array. El tipo BSON será determinado como sigue:
Los documentos raíz deben ser serializados como un documento BSON.
Los objetos MongoDB\BSON\Persistable deben ser serializados como un documento BSON.
Si MongoDB\BSON\Serializable::bsonSerialize() devuelve un array compacto, se serializa como un array BSON.
Si MongoDB\BSON\Serializable::bsonSerialize() devuelve un array no compacto o un objeto stdClass, se serializa como un documento BSON.
Si MongoDB\BSON\Serializable::bsonSerialize() no devuelve un array u objeto stdClass, se lanza una excepción de tipo MongoDB\Driver\Exception\UnexpectedValueException.
Si un objeto es de una clase que implementa la
interfaz MongoDB\BSON\Persistable (lo que implica que
MongoDB\BSON\Serializable obtiene las propiedades
de una forma similar a los párrafos anteriores, aunque
también añade una propiedad adicional
__pclass como un valor Binary, con subtipo
0x80
y datos soportando el nombre de la clase completamente cualificado
del objeto que se está serializando.
La propiedad __pclass se añade al array u objeto devuelto por MongoDB\BSON\Serializable::bsonSerialize(), lo que significa que se sobrescribirá cualquier clave/propiedad __pclass en el valor devuelto de MongoDB\BSON\Serializable::bsonSerialize(). Para evitar este funcionamiento y establecer un valor de __pclass propio, no se debe implementar MongoDB\BSON\Persistable y, en su lugar, se deería implementar MongoDB\BSON\Serializable directamente.
<?php
class stdClass {
public $foo = 42;
} // => { "foo" : 42 }
class MyClass {
public $foo = 42;
protected $prot = "wine";
private $fpr = "cheese";
} // => { "foo" : 42 }
class AnotherClass1 implements MongoDB\BSON\Serializable {
public $foo = 42;
protected $prot = "wine";
private $fpr = "cheese";
function bsonSerialize() {
return [ 'foo' => $this->foo, 'prot' => $this->prot ];
}
} // => { "foo" : 42, "prot" : "wine" }
class AnotherClass2 implements MongoDB\BSON\Serializable {
public $foo = 42;
function bsonSerialize() {
return $this;
}
} // => MongoDB\Driver\Exception\UnexpectedValueException("bsonSerialize() did not return an array or stdClass")
class AnotherClass3 implements MongoDB\BSON\Serializable {
private $elements = [ 'foo', 'bar' ];
function bsonSerialize() {
return $this->elements;
}
} // => { "0" : "foo", "1" : "bar" }
class ContainerClass implements MongoDB\BSON\Serializable {
public $things = AnotherClass4 implements MongoDB\BSON\Serializable {
private $elements = [ 0 => 'foo', 2 => 'bar' ];
function bsonSerialize() {
return $this->elements;
}
}
function bsonSerialize() {
return [ 'things' => $this->things ];
}
} // => { "things" : { "0" : "foo", "2" : "bar" } }
class ContainerClass implements MongoDB\BSON\Serializable {
public $things = AnotherClass5 implements MongoDB\BSON\Serializable {
private $elements = [ 0 => 'foo', 2 => 'bar' ];
function bsonSerialize() {
return array_values($this->elements);
}
}
function bsonSerialize() {
return [ 'things' => $this->things ];
}
} // => { "things" : [ "foo", "bar" ] }
class ContainerClass implements MongoDB\BSON\Serializable {
public $things = AnotherClass6 implements MongoDB\BSON\Serializable {
private $elements = [ 'foo', 'bar' ];
function bsonSerialize() {
return (object) $this->elements;
}
}
function bsonSerialize() {
return [ 'things' => $this->things ];
}
} // => { "things" : { "0" : "foo", "1" : "bar" } }
class UpperClass implements MongoDB\BSON\Persistable {
public $foo = 42;
protected $prot = "wine";
private $fpr = "cheese";
function bsonSerialize() {
return [ 'foo' => $this->foo, 'prot' => $this->prot ];
}
} // => { "foo" : 42, "prot" : "wine", "__pclass" : { "$type" : "80", "$binary" : "VXBwZXJDbGFzcw==" } }
BSON documents can technically contain duplicate keys because documents are stored as a list of key-value pairs; however, applications should refrain from generating documents with duplicate keys as server and driver behavior may be undefined. Since PHP objects and arrays cannot have duplicate keys, data could also be lost when decoding a BSON document with duplicate keys.
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.
Para tipos compuestos, existen tres tipos de datos:
se refiere al documento BSON de más alto nivel solamente
se refiere a docuemtnos BSON embebidos solamente
se refiere a un array BSON
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', ], ]
Cada uno de estos tres tipos de datos se pueden hacer corresponder con diferentes tipos de PHP. Los posibles valores de correspondencia son:
Un array BSON será deserializado como un array de PHP.
Un documento BSON (raíz o embebido) sin una propiedad __pclass [1] se convierte en un objeto stdClass de PHP, con cada clave de documento BSON establecida a propiedad stdClass pública.
Un documento BSON (raíz o embebido) con una propiedad __pclass [1] se convierte en un objeto de PHP del nombre de la clase definida por la propiedad __pclass.
Si la clase con nombre implementa la intefaz MongoDB\BSON\Persistable, las propiedades del documento BSON, incluyendo la propiedad __pclass, son enviadas como un array asociativo a la función bsonUnserialize() para inicializar la propiedades del objeto.
Si la clase con nombre no existe o no implementa la interfaz MongoDB\BSON\Persistable, se empleará stdClass y cada clave del documento BSON (incluyendo __pclass) será establecida a una propiedad stdClass pública.
"array"
Convierte un array BSON o documento BSON en un array de PHP. No habrá ningún tratamiento especial de una propiedad __pclass [1], aunque se podría establecer como un elemento del array devuelto si estaba presente el el documento BSON.
"object"
o "stdClass"
Convierte un array BSON o documento BSON a un objeto stdClass. No habrá ningún tratamiento especial de una propiedad __pclass [1], aunque se podría establecer como propiedad pública del objeto devuelto si estaba presente en el documento BSON.
Define el nombre de la clase a la que debe ser deserializado el array BSON u objeto BSON. Para objetos BSON que incluyan propiedades __pclass, esta clase tomará prioridad.
Si la clase citada no existe, no es concreta (esto es, es abstracta o es una interfaz), o no implementa MongoDB\BSON\Unserializable, se lanzará una excepción MongoDB\Driver\Exception\InvalidArgumentException.
Si el objeto BSON posee una propiedad __pclass y esa clase existe e implementa MongoDB\BSON\Persistable, sustituirá a la clase proporcionada en el mapa de tipo.
Las propiedades del documento BSON, incluyendo la propiedad __pclass si existiera, será enviada como un array asociativo a la función bsonUnserialize() para inicializar las propiedades del objeto.
TypeMaps se puede establecer a través del
método MongoDB\Driver\Cursor::setTypeMap() en un
objeto MongoDB\Driver\Cursor o del
argumento $typeMap
de
MongoDB\BSON\toPHP(). Cada una de las tres
clases (root, document and
array) se pueden establecer individualmente.
Si el valor del mapa es NULL, significa lo mismo que el valor predeterminado para ese elemento.
Estos ejemplos utilizan las siguientes clases:
la cual no implementa ninguna interfaz
que implementa MongoDB\BSON\Unserializable
que implementa MongoDB\BSON\Persistable
que extiende NuestraClase
El método MongoDB\BSON\Unserializable::bsonUnserialize()
de TuClase, NuestraClase, SuClase recorre el array y establece las propiedades
sin modificaciones. También establece la propiedad
$unserialized
a 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") }