Skip to content

Commit aeec90d

Browse files
committed
Add section on handling embedded documents
1 parent 1cac7fe commit aeec90d

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed

docs/tutorial/codecs.txt

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,120 @@ code omitted for brevity):
228228
}
229229
}
230230

231+
Handling embedded documents
232+
---------------------------
233+
234+
The previous example showed how to handle a single document. However, sometimes you want to handle fields that contain
235+
embedded documents. To show this, let's create an address document that we'll be embedding into our ``Person`` document.
236+
To ensure consistency, we're going to make this a readonly class:
237+
238+
.. code-block:: php
239+
240+
<?php
241+
242+
final readonly class Address
243+
{
244+
public function __construct(
245+
public string $street,
246+
public string $postCode,
247+
public string $city,
248+
public string $country,
249+
) {
250+
}
251+
252+
We can now create a document codec for this class:
253+
254+
.. code-block:: php
255+
256+
<?php
257+
258+
final class AddressCodec implements MongoDB\Codec\DocumentCodec
259+
{
260+
// Other code omitted for brevity
261+
public function decode($value): Person
262+
{
263+
if (! $this->canDecode($value)) {
264+
throw UnsupportedValueException::invalidDecodableValue($value);
265+
}
266+
267+
return new Address(
268+
$value->get('street'),
269+
$value->get('postCode'),
270+
$value->get('city'),
271+
$value->get('country'),
272+
);
273+
}
274+
275+
public function encode($value): MongoDB\BSON\Document
276+
{
277+
if (! $this->canEncode($value)) {
278+
throw UnsupportedValueException::invalidEncodableValue($value);
279+
}
280+
281+
return MongoDB\BSON\Document::fromPHP([
282+
'street' => $value->street,
283+
'postCode' => $value->postCode,
284+
'city' => $value->city,
285+
'country' => $value->country,
286+
]);
287+
}
288+
}
289+
290+
This codec is quite similar to the ``PersonCodec`` we had before, except that we're not adding an identifier to it. The
291+
creation of the object also differs, as we have to pass all the fields to the constructor.
292+
293+
In the ``PersonCodec``, we can now extend the ``decode`` and ``encode`` methods to handle the address field. Note that
294+
the example below excludes some code we've already shown in previous examples.
295+
296+
.. code-block:: php
297+
298+
<?php
299+
300+
final class PersonCodec implements MongoDB\Codec\DocumentCodec
301+
{
302+
private AddressCodec $addressCodec;
303+
304+
public function __construct()
305+
{
306+
$this->addressCodec = new AddressCodec();
307+
}
308+
309+
// Other code omitted for brevity
310+
public function decode($value): Person
311+
{
312+
if (! $this->canDecode($value)) {
313+
throw UnsupportedValueException::invalidDecodableValue($value);
314+
}
315+
316+
$person = new Person($value->get('name'));
317+
$person->id = $value->get('_id');
318+
319+
if ($value->has('address')) {
320+
$person->address = $this->addressCodec->decode($value->get('address'));
321+
}
322+
323+
return $person;
324+
}
325+
326+
public function encode($value): MongoDB\BSON\Document
327+
{
328+
if (! $this->canEncode($value)) {
329+
throw UnsupportedValueException::invalidEncodableValue($value);
330+
}
331+
332+
$data = [
333+
'_id' => $value->id,
334+
'name' => $value->name,
335+
];
336+
337+
if ($value->address) {
338+
$data['address'] = $this->addressCodec->encode($value->address);
339+
}
340+
341+
return MongoDB\BSON\Document::fromPHP($data);
342+
}
343+
}
344+
231345
Codec Libraries
232346
---------------
233347

0 commit comments

Comments
 (0)