@@ -16,31 +16,27 @@ Overview
1616--------
1717
1818Codecs are used to decode BSON documents into PHP objects, and encode PHP objects into BSON documents. In contrast to
19- other methods, they allow for more flexibility and customization of the process and how different data types are
20- handled. They allow separating the logic for BSON encoding and decoding from the domain classes, allowing to decode BSON
21- into plain old PHP objects (POPOs).
19+ other methods (e.g. type maps), codecs allow for greater customization and handling of different data types. They allow
20+ separating the logic for BSON encoding and decoding from the domain classes, allowing to decode BSON into plain old PHP
21+ objects (POPOs).
2222
23- Document Codec Usage
24- --------------------
23+ Handling Documents
24+ ------------------
2525
2626The main logic is contained in a document codec. This class implements the ``MongoDB\Codec\DocumentCodec`` interface and
2727defines what data types can be encoded/decoded and how. The following example defines a ``Person`` class and a codec to
28- encode/decode it:
28+ transform it:
2929
3030.. code-block:: php
3131
3232 <?php
3333
3434 final class Person
3535 {
36- public MongoDB\BSON\ObjectId $id;
37- public string $name;
38- 39- public function __construct(string $name)
40- {
41- $this->id = new MongoDB\BSON\ObjectId();
42- $this->name = $name;
43- }
36+ public function __construct(
37+ public string $name,
38+ public readonly MongoDB\BSON\ObjectId $id = new MongoDB\BSON\ObjectId(),
39+ ) {}
4440 }
4541
4642.. code-block:: php
@@ -69,10 +65,10 @@ encode/decode it:
6965 throw UnsupportedValueException::invalidDecodableValue($value);
7066 }
7167
72- $person = new Person($value->get('name'));
73- $person->id = $value->get('_id');
74- 75- return $person ;
68+ return new Person(
69+ $value->get('name'),
70+ $value->get('_id'),
71+ ) ;
7672 }
7773
7874 public function encode($value): MongoDB\BSON\Document
@@ -105,19 +101,21 @@ To then use this codec with a collection, specify the ``codec`` option when sele
105101 $person = $collection->findOne();
106102
107103The example above selects a collection and instructs it to use the ``PersonCodec`` for encoding and decoding documents.
108- When inserting data, the ``PersonCodec`` is used to encode the document. When retrieving data, the ``PersonCodec`` is
109- used to decode BSON data into a ``Person`` instance. Note that while the ``PersonCodec`` could technically decode any
104+ When inserting data, the ``PersonCodec`` is used to encode the document. When retrieving data, the same ``PersonCodec``
105+ is used to decode BSON data into a ``Person`` instance. Note that while the ``PersonCodec`` could technically decode any
110106BSON document that contains a name field, we wouldn't want to use it for any other documents. Document codecs are meant
111107to be used in a collection, or when decoding embedded documents.
112108
113109When working on a collection with a codec, the codec will only accept and return data of that type for certain
114- operations. The ``bulkWrite``, ```findOneAndReplace``, ``insertMany``, ``insertOne``, and ``replaceOne`` operations
115- will attempt to encode the given data using the provided codec. Trying to insert or replace a document that cannot be
116- encoded will result in an exception. The ``aggregate``, ``find``, ``findOne``, ``findOneAndDelete``,
117- ``findOneAndReplace``, and ``findOneAndUpdate`` operations will attempt to decode returned documents using the provided
118- codec. If the codec does not support the data returned, an exception will be thrown. You can disable codec usage for a
119- specific operation or use a different codec (e.g. to decode the result of an aggregation pipeline) by specifying the
120- nullable ``codec`` option for the operation. This will override the collection-level codec:
110+ operations. Insert and replace operations (e.g. ``insertOne``, ```findOneAndReplace``, and some ``bulkWrite``
111+ operations) will attempt to encode the given data using the provided codec. Trying to insert or replace a document that
112+ cannot be encoded will result in an exception. Read operations (e.g. ``aggregate``, ``find``, and ``findOneAndUpdate``)
113+ operations will attempt to decode returned documents using the provided codec. If the codec does not support the data
114+ returned, an exception will be thrown.
115+ 116+ You can disable codec usage for a specific operation or use a different codec (e.g. to decode the result of an
117+ aggregation pipeline) by specifying the ``null`` for the ``codec`` option for any operation. This will override the
118+ collection-level codec:
121119
122120.. code-block:: php
123121
@@ -136,12 +134,14 @@ nullable ``codec`` option for the operation. This will override the collection-l
136134 'codec' => null,
137135 ]);
138136
139- Generic Codecs
140- --------------
137+ Handling Fields and Data Types
138+ ------------------------------
139+ 140+ The previous example showed how to define a codec for a specific class. However, you may want to create a codec that
141+ handles a particular data type in any document. This can be achieved by implementing the ``MongoDB\Codec\Codec``
142+ interface.
141143
142- The previous example showed how to define a codec for a specific class. However, sometimes you want to define codecs to
143- handle a given type in all documents. For such codecs, you can implement the ``MongoDB\Codec\Codec`` interface. The
144- following example defines a codec to store ``DateTimeInterface`` instances as BSON dates including the timezone:
144+ The following example defines a codec to store ``DateTimeInterface`` instances as BSON dates including the timezone:
145145
146146.. code-block:: php
147147
@@ -203,7 +203,7 @@ following example defines a codec to store ``DateTimeInterface`` instances as BS
203203 }
204204 }
205205
206- This codec can now be leveraged by other codecs encode and decode dates . Let's return to the previous example and add a
206+ This codec can now be leveraged by other codecs handle date fields . Let's return to the previous example and add a
207207``createdAt`` field that contains the creation date. The modified encode and decode methods would look like this (other
208208code omitted for brevity):
209209
@@ -213,11 +213,15 @@ code omitted for brevity):
213213
214214 final class PersonCodec implements MongoDB\Codec\DocumentCodec
215215 {
216+ use MongoDB\Codec\DecodeIfSupported;
217+ use MongoDB\Codec\EncodeIfSupported;
218+ 216219 public function __construct(
217220 private readonly DateTimeCodec $dateTimeCodec = new DateTimeCodec(),
218221 ) {}
219222
220- // Other code omitted for brevity
223+ // Other methods omitted for brevity
224+ 221225 public function decode($value): Person
222226 {
223227 if (! $this->canDecode($value)) {
@@ -245,12 +249,12 @@ code omitted for brevity):
245249 }
246250 }
247251
248- Handling embedded documents
252+ Handling Embedded Documents
249253---------------------------
250254
251- The previous example showed how to handle a single document. However, sometimes you want to handle fields that contain
252- embedded documents. To show this, let's create an address document that we'll be embedding into our ``Person`` document.
253- To ensure consistency, we're going to make this a readonly class:
255+ A previous example showed how to handle a single document. However, sometimes you want to handle fields that contain
256+ embedded documents. We will demonstrate this using an ``Address`` document, which we will embed within a ``Person``
257+ document. To ensure consistency, we're going to make this a read-only class:
254258
255259.. code-block:: php
256260
@@ -274,7 +278,11 @@ We can now create a document codec for this class:
274278
275279 final class AddressCodec implements MongoDB\Codec\DocumentCodec
276280 {
277- // Other code omitted for brevity
281+ use MongoDB\Codec\DecodeIfSupported;
282+ use MongoDB\Codec\EncodeIfSupported;
283+ 284+ // Other methods omitted for brevity
285+ 278286 public function decode($value): Person
279287 {
280288 if (! $this->canDecode($value)) {
@@ -304,10 +312,7 @@ We can now create a document codec for this class:
304312 }
305313 }
306314
307- This codec is quite similar to the ``PersonCodec`` we had before, except that we're not adding an identifier to it. The
308- creation of the object also differs, as we have to pass all the fields to the constructor.
309- 310- In the ``PersonCodec``, we can now extend the ``decode`` and ``encode`` methods to handle the address field. Note that
315+ In the ``PersonCodec``, we can now modify the ``decode`` and ``encode`` methods to handle the address field. Note that
311316the example below excludes some code we've already shown in previous examples.
312317
313318.. code-block:: php
@@ -359,10 +364,10 @@ the example below excludes some code we've already shown in previous examples.
359364Codec Libraries
360365---------------
361366
362- If you have a number of codecs that you want to use in multiple places, you can create a codec library. A codec library
363- contains a list of codecs and checks each codec if it supports a value. If it does, it will use that codec to encode or
364- decode the given value. The following code snippet changes the ``PersonCodec`` to use a codec library instead of a
365- hard-coded ``DateTimeCodec``:
367+ A codec library contains a list of codecs and presents itself as a codec. When encoding or decoding a value, it will
368+ consult each registered codec in sequence and delegate to the first supporting codec to transform that value.
369+ 370+ The following code snippet changes the ``PersonCodec`` to use a codec library instead of a hard-coded ``DateTimeCodec``:
366371
367372.. code-block:: php
368373
0 commit comments