Modeling BSON Data
On this page
Type Maps
Most methods that read data from MongoDB support a typeMap
option, which
allows control over how BSON is converted to PHP. Additionally,
the MongoDB\Client
, MongoDB\Database
, and
MongoDB\Collection
classes accept a typeMap
option, which can
be used to specify a default type map to apply to any supporting methods and
selected classes (e.g. MongoDB\Client::selectDatabase()
).
The MongoDB\Client
, MongoDB\Database
, and
MongoDB\Collection
classes use the following type map by
default:
[ 'array' => 'MongoDB\Model\BSONArray', 'document' => 'MongoDB\Model\BSONDocument', 'root' => 'MongoDB\Model\BSONDocument', ]
The type map above will convert BSON documents and arrays to
MongoDB\Model\BSONDocument
and
MongoDB\Model\BSONArray
objects, respectively. The root
and
document
keys are used to distinguish the top-level BSON document from
embedded documents, respectively.
A type map may specify any class that implements
MongoDB\BSON\Unserializable as well as
"array"
, "stdClass
", and "object"
("stdClass
" and "object"
are aliases of one another).
Persistable Classes
The extension's persistence specification outlines how classes implementing its MongoDB\BSON\Persistable interface are serialized to and deserialized from BSON. The Persistable interface is analogous to PHP's Serializable interface.
The extension automatically handles serialization and deserialization for
classes implementing the Persistable interface
without requiring the use of the typeMap
option. This is done by encoding
the name of the PHP class in a special property within the BSON document.
Note
When deserializing a PHP variable from BSON, the encoded class name of a
Persistable object will override any class
specified in the type map, but it will not override "array"
and
"stdClass"
or "object"
. This is discussed in the
persistence specification but it bears
repeating.
Consider the following class definition:
class Person implements MongoDB\BSON\Persistable { private MongoDB\BSON\ObjectId $id; private string $name; private MongoDB\BSON\UTCDateTime $createdAt; public function __construct(string $name) { $this->id = new MongoDB\BSON\ObjectId; $this->name = $name; $this->createdAt = new MongoDB\BSON\UTCDateTime; } function bsonSerialize() { return [ '_id' => $this->id, 'name' => $this->name, 'createdAt' => $this->createdAt, ]; } function bsonUnserialize(array $data) { $this->id = $data['_id']; $this->name = $data['name']; $this->createdAt = $data['createdAt']; } }
The following example constructs a Person
object, inserts it into the
database, and reads it back as an object of the same type:
$collection = (new MongoDB\Client)->test->persons; $result = $collection->insertOne(new Person('Bob')); $person = $collection->findOne(['_id' => $result->getInsertedId()]); var_dump($person);
The output would then resemble:
object(Person)#18 (3) { ["id":"Person":private]=> object(MongoDB\BSON\ObjectId)#15 (1) { ["oid"]=> string(24) "56fad2c36118fd2e9820cfc1" } ["name":"Person":private]=> string(3) "Bob" ["createdAt":"Person":private]=> object(MongoDB\BSON\UTCDateTime)#17 (1) { ["milliseconds"]=> int(1459278531218) } }
The same document in the MongoDB shell might display as:
{ "_id" : ObjectId("56fad2c36118fd2e9820cfc1"), "__pclass" : BinData(128,"UGVyc29u"), "name" : "Bob", "createdAt" : ISODate("2016-03-29T19:08:51.218Z") }
Note
MongoDB\BSON\Persistable may only be used for root and embedded BSON documents. It may not be used for BSON arrays.
Working with Enums
Backed enums can be used with BSON and will serialize as their case value (i.e. integer or string). Pure enums, which have no backed cases, cannot be directly serialized. This is similar to how enums are handled by json_encode().
Round-tripping a backed enum through BSON requires special handling. In the
following example, the bsonUnserialize()
method in the class containing the
enum is responsible for converting the value back to an enum case:
enum Role: int { case USER = 1; case ADMIN = 2; } class User implements MongoDB\BSON\Persistable { public function __construct( private string $username, private Role $role, private MongoDB\BSON\ObjectId $_id = new MongoDB\BSON\ObjectId(), ) {} public function bsonSerialize(): array { return [ '_id' => $this->_id, 'username' => $this->username, 'role' => $this->role, ]; } public function bsonUnserialize(array $data): void { $this->_id = $data['_id']; $this->username = $data['username']; $this->role = Role::from($data['role']); } }
Enums are prohibited from implementing MongoDB\BSON\Unserializable and MongoDB\BSON\Persistable, since enum cases have no state and cannot be instantiated like ordinary objects. Pure and backed enums can, however, implement MongoDB\BSON\Serializable, which can be used to overcome the default behavior whereby backed enums are serialized as their case value and pure enums cannot be serialized.