对 BSON 数据建模
类型映射
大多数从MongoDB读取数据的方法都支持 typeMap
选项,该选项允许控制BSON如何转换为PHP。 此外, MongoDB\Client
、 MongoDB\Database
和MongoDB\Collection
类接受typeMap
选项,该选项可用于指定默认类型映射以应用任何支持方法和选定的类(例如 MongoDB\Client::selectDatabase()
)。
默认情况下, MongoDB\Client
、 MongoDB\Database
和MongoDB\Collection
类使用以下类型映射:
[ 'array' => 'MongoDB\Model\BSONArray', 'document' => 'MongoDB\Model\BSONDocument', 'root' => 'MongoDB\Model\BSONDocument', ]
上面的类型映射将 BSON 文档和数组分别转换为MongoDB\Model\BSONDocument
和MongoDB\Model\BSONArray
对象。 root
和document
键分别用于区分顶级 BSON 文档和嵌入式文档。
类型映射可以指定实现 MongoDB\BSON\Unserializable 的任何类"array"
"stdClass
以及 、 " 和"object"
("stdClass
" 和"object"
是彼此的别名)。
可持久化类
扩展的 持久性规范 概述了类如何实现其 MongoDB\ BSON\Persistable 接口被序列化为 BSON 或从BSON反序列化。Persistable 接口类似于 PHP 的 Serializable 接口。
该扩展会自动处理实现 Persistable 的类的序列化和反序列化 接口,无需使用typeMap
选项。这是通过将PHP类的名称编码在BSON文档中的特殊属性中来完成的。
注意
从 BSON 反序列化 PHP 变量时, Persistable 的编码类名 对象将覆盖类型映射中指定的任何类,但不会覆盖"array"
和"stdClass"
或"object"
。持久性规范 对此进行了讨论 但值得重复的是。
考虑以下类定义:
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']; } }
以下示例构造一个Person
对象,将其插入数据库,然后将其作为相同类型的对象读回:
$collection = (new MongoDB\Client)->test->persons; $result = $collection->insertOne(new Person('Bob')); $person = $collection->findOne(['_id' => $result->getInsertedId()]); var_dump($person);
而输出将类似如下所示:
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) } }
同一个文档在 MongoDB Shell 中可能显示为:
{ "_id" : ObjectId("56fad2c36118fd2e9820cfc1"), "__pclass" : BinData(128,"UGVyc29u"), "name" : "Bob", "createdAt" : ISODate("2016-03-29T19:08:51.218Z") }
注意
MongoDB\ BSON\Persistable 只能用于根文档和嵌入式BSON文档。它不能用于BSON数组。
使用枚举
支持枚举 可以与 BSON 一起使用,并将序列化为其大小写值(即整数或string )。 纯枚举 ,没有支持的案例,无法直接序列化。这类似于 json_encode() 处理枚举的方式。
通过 BSON 来回支持的枚举需要特殊处理。 在以下示例中,包含枚举的类中的bsonUnserialize()
方法负责将值转换回枚举大小写:
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']); } }
禁止枚举实现 MongoDB\BSON\Unserializable 和 MongoDB\BSON\Persistable ,因为枚举没有状态,也不能像普通对象一样实例化。但是,纯枚举和支持枚举可以实现 MongoDB\BSON\Serializable ,它可用于克服默认行为,即支持的枚举会序列化为其案例值,而纯枚举无法序列化。