diff --git a/docs/index.txt b/docs/index.txt index 77890982c..5cbf328a4 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -35,6 +35,8 @@ following pages should help you get started: - :doc:`/tutorial/gridfs` +- :doc:`/tutorial/modeling-bson-data` + - :doc:`/reference/bson` Code examples can be found in the ``examples`` directory in the source code. diff --git a/docs/reference/bson.txt b/docs/reference/bson.txt index 7ac5b6bc6..b9fbbaa2c 100644 --- a/docs/reference/bson.txt +++ b/docs/reference/bson.txt @@ -21,8 +21,8 @@ By default, the |php-library| returns BSON documents as :phpclass:`MongoDB\\Model\\BSONDocument` objects and BSON arrays as :phpclass:`MongoDB\\Model\\BSONArray` objects, respectively. -BSON Classes ------------- +Classes +------- .. phpclass:: MongoDB\\Model\\BSONArray @@ -49,213 +49,3 @@ BSON Classes class. During BSON and JSON serialization, instances of this class will serialize as a document type (:php:`object casting ` is used internally). - -.. _php-type-map: - -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 :phpclass:`MongoDB\\Client`, :phpclass:`MongoDB\\Database`, and -:phpclass:`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. :phpmethod:`MongoDB\\Client::selectDatabase()`). - -The :phpclass:`MongoDB\\Client`, :phpclass:`MongoDB\\Database`, and -:phpclass:`MongoDB\\Collection` classes use the following type map by -default: - -.. code-block:: php - - [ - 'array' => 'MongoDB\Model\BSONArray', - 'document' => 'MongoDB\Model\BSONDocument', - 'root' => 'MongoDB\Model\BSONDocument', - ] - -The type map above will convert BSON documents and arrays to -:phpclass:`MongoDB\\Model\\BSONDocument` and -:phpclass:`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 -:php:`MongoDB\\BSON\\Unserializable ` as well as -``"array"``, ``"stdClass``", and ``"object"`` (``"stdClass``" and ``"object"`` -are aliases of one another). - -.. seealso:: :php:`Deserialization from BSON ` in the PHP manual - -``Persistable`` Classes ------------------------ - -The driver's :php:`persistence specification ` outlines how -classes implementing its :php:`MongoDB\\BSON\\Persistable -` interface are serialized to and deserialized from -BSON. The :php:`Persistable ` interface is analogous -to PHP's :php:`Serializable interface `. - -The driver automatically handles serialization and deserialization for classes -implementing the :php:`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 - :php:`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 - :php:`persistence specification ` but it bears - repeating. - -Consider the following class definition: - -.. code-block:: php - - id = new MongoDB\BSON\ObjectId; - $this->name = (string) $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: - -.. code-block:: php - - test->persons; - - $result = $collection->insertOne(new Person('Bob')); - - $person = $collection->findOne(['_id' => $result->getInsertedId()]); - - var_dump($person); - -The output would then resemble: - -.. code-block:: none - - 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: - -.. code-block:: js - - { - "_id" : ObjectId("56fad2c36118fd2e9820cfc1"), - "__pclass" : BinData(128,"UGVyc29u"), - "name" : "Bob", - "createdAt" : ISODate("2016-03-29T19:08:51.218Z") - } - -.. note:: - - :php:`MongoDB\\BSON\\Persistable ` may only be used - for root and embedded BSON documents. It may not be used for BSON arrays. - -Emulating the Legacy Driver ---------------------------- - -The legacy ``mongo`` extension returned both BSON documents and arrays as PHP -arrays. While PHP arrays are convenient to work with, this behavior was -problematic: - -- Different BSON types could deserialize to the same PHP value (e.g. - ``{"0": "foo"}`` and ``["foo"]``), which made it impossible to infer the - original BSON type. - -- Numerically-indexed PHP arrays would be serialized as BSON documents if there - was a gap in their key sequence. Such gaps were easily caused by unsetting a - key to remove an element and forgetting to numerically reindex the array. - -The |php-library|'s :phpclass:`BSONDocument ` and -:phpclass:`BSONArray ` classes address these concerns -by preserving the BSON type information during serialization and -deserialization; however, some users may still prefer the legacy behavior. If -desired, you can use the ``typeMap`` option to have the library return -everything as a PHP array: - -.. code-block:: php - - [ - 'array' => 'array', - 'document' => 'array', - 'root' => 'array', - ], - ] - ); - - $document = $client->test->zips->findOne(['_id' => '94301']); - - var_dump($document); - -The above example would output something similar to: - -.. code-block:: php - - array(5) { - ["_id"]=> - string(5) "94301" - ["city"]=> - string(9) "PALO ALTO" - ["loc"]=> - array(2) { - [0]=> - float(-122.149685) - [1]=> - float(37.444324) - } - ["pop"]=> - int(15965) - ["state"]=> - string(2) "CA" - } diff --git a/docs/tutorial.txt b/docs/tutorial.txt index a749af2d1..91333fb45 100644 --- a/docs/tutorial.txt +++ b/docs/tutorial.txt @@ -17,4 +17,5 @@ Tutorials /tutorial/indexes /tutorial/tailable-cursor /tutorial/example-data + /tutorial/modeling-bson-data /tutorial/stable-api diff --git a/docs/tutorial/modeling-bson-data.txt b/docs/tutorial/modeling-bson-data.txt new file mode 100644 index 000000000..8d2e90064 --- /dev/null +++ b/docs/tutorial/modeling-bson-data.txt @@ -0,0 +1,158 @@ +================== +Modeling BSON Data +================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + + +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 :phpclass:`MongoDB\\Client`, :phpclass:`MongoDB\\Database`, and +:phpclass:`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. :phpmethod:`MongoDB\\Client::selectDatabase()`). + +The :phpclass:`MongoDB\\Client`, :phpclass:`MongoDB\\Database`, and +:phpclass:`MongoDB\\Collection` classes use the following type map by +default: + +.. code-block:: php + + [ + 'array' => 'MongoDB\Model\BSONArray', + 'document' => 'MongoDB\Model\BSONDocument', + 'root' => 'MongoDB\Model\BSONDocument', + ] + +The type map above will convert BSON documents and arrays to +:phpclass:`MongoDB\\Model\\BSONDocument` and +:phpclass:`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 +:php:`MongoDB\\BSON\\Unserializable ` as well as +``"array"``, ``"stdClass``", and ``"object"`` (``"stdClass``" and ``"object"`` +are aliases of one another). + +.. seealso:: :php:`Deserialization from BSON ` in the PHP manual + + +Persistable Classes +------------------- + +The driver's :php:`persistence specification ` outlines how +classes implementing its :php:`MongoDB\\BSON\\Persistable +` interface are serialized to and deserialized from +BSON. The :php:`Persistable ` interface is analogous +to PHP's :php:`Serializable interface `. + +The driver automatically handles serialization and deserialization for classes +implementing the :php:`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 + :php:`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 + :php:`persistence specification ` but it bears + repeating. + +Consider the following class definition: + +.. code-block:: php + + 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: + +.. code-block:: php + + test->persons; + + $result = $collection->insertOne(new Person('Bob')); + + $person = $collection->findOne(['_id' => $result->getInsertedId()]); + + var_dump($person); + +The output would then resemble: + +.. code-block:: none + + 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: + +.. code-block:: js + + { + "_id" : ObjectId("56fad2c36118fd2e9820cfc1"), + "__pclass" : BinData(128,"UGVyc29u"), + "name" : "Bob", + "createdAt" : ISODate("2016-03-29T19:08:51.218Z") + } + +.. note:: + + :php:`MongoDB\\BSON\\Persistable ` may only be used + for root and embedded BSON documents. It may not be used for BSON arrays. +.. _php-type-map: diff --git a/docs/upgrade.txt b/docs/upgrade.txt index 200e49c99..4a67b7fbe 100644 --- a/docs/upgrade.txt +++ b/docs/upgrade.txt @@ -23,8 +23,11 @@ implements the ``mongo`` extension API using this library and the new driver. While this adapter library is not officially supported by MongoDB, it does bear mentioning. -BSON Type Classes ------------------ +BSON +---- + +Type Classes +~~~~~~~~~~~~ When upgrading from the legacy driver, type classes such as MongoId must be replaced with classes in the @@ -103,6 +106,70 @@ the new driver. driver also does not provide any helpers for working with DBRef objects, since their use is not encouraged. +Emulating the Legacy Driver +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The legacy ``mongo`` extension returned both BSON documents and arrays as PHP +arrays. While PHP arrays are convenient to work with, this behavior was +problematic: + +- Different BSON types could deserialize to the same PHP value (e.g. + ``{"0": "foo"}`` and ``["foo"]``), which made it impossible to infer the + original BSON type. + +- Numerically-indexed PHP arrays would be serialized as BSON documents if there + was a gap in their key sequence. Such gaps were easily caused by unsetting a + key to remove an element and forgetting to numerically reindex the array. + +The |php-library|'s :phpclass:`BSONDocument ` and +:phpclass:`BSONArray ` classes address these concerns +by preserving the BSON type information during serialization and +deserialization; however, some users may still prefer the legacy behavior. If +desired, you can use the ``typeMap`` option to have the library return +everything as a PHP array: + +.. code-block:: php + + [ + 'array' => 'array', + 'document' => 'array', + 'root' => 'array', + ], + ] + ); + + $document = $client->test->zips->findOne(['_id' => '94301']); + + var_dump($document); + +The above example would output something similar to: + +.. code-block:: php + + array(5) { + ["_id"]=> + string(5) "94301" + ["city"]=> + string(9) "PALO ALTO" + ["loc"]=> + array(2) { + [0]=> + float(-122.149685) + [1]=> + float(37.444324) + } + ["pop"]=> + int(15965) + ["state"]=> + string(2) "CA" + } + Collection API --------------