Skip to content

Commit 8650660

Browse files
committed
Add basic codec infrastructure
1 parent 9f30d1c commit 8650660

File tree

5 files changed

+191
-0
lines changed

5 files changed

+191
-0
lines changed

src/Codec/Codec.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace MongoDB\Codec;
4+
5+
/**
6+
* @psalm-template BSONType
7+
* @psalm-template NativeType
8+
* @template-extends Decoder<BSONType, NativeType>
9+
* @template-extends Encoder<BSONType, NativeType>
10+
*/
11+
interface Codec extends Decoder, Encoder
12+
{
13+
}

src/Codec/Decoder.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace MongoDB\Codec;
4+
5+
/**
6+
* @internal
7+
* @psalm-template BSONType
8+
* @psalm-template NativeType
9+
*/
10+
interface Decoder
11+
{
12+
/**
13+
* @param mixed $value
14+
* @psalm-assert-if-true BSONType $value
15+
*/
16+
public function canDecode($value): bool;
17+
18+
/**
19+
* @param mixed $value
20+
* @psalm-param BSONType $value
21+
* @return mixed
22+
* @psalm-return NativeType
23+
*/
24+
public function decode($value);
25+
26+
/**
27+
* @param mixed $value
28+
* @psalm-param mixed $value
29+
* @return mixed
30+
* @psalm-return ($value is BSONType ? NativeType : $value)
31+
*/
32+
public function decodeIfSupported($value);
33+
}

src/Codec/DocumentCodec.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace MongoDB\Codec;
4+
5+
use MongoDB\BSON\Document;
6+
7+
/**
8+
* @psalm-template ObjectType of object
9+
* @template-extends Codec<Document, ObjectType>
10+
*/
11+
interface DocumentCodec extends Codec
12+
{
13+
}

src/Codec/Encoder.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace MongoDB\Codec;
4+
5+
/**
6+
* @internal
7+
* @psalm-template BSONType
8+
* @psalm-template NativeType
9+
*/
10+
interface Encoder
11+
{
12+
/**
13+
* @param mixed $value
14+
* @psalm-assert-if-true NativeType $value
15+
*/
16+
public function canEncode($value): bool;
17+
18+
/**
19+
* @param mixed $value
20+
* @psalm-param NativeType $value
21+
* @return mixed
22+
* @psalm-return BSONType
23+
*/
24+
public function encode($value);
25+
26+
/**
27+
* @param mixed $value
28+
* @psalm-param mixed $value
29+
* @return mixed
30+
* @psalm-return ($value is NativeType ? BSONType : $value)
31+
*/
32+
public function encodeIfSupported($value);
33+
}

src/Codec/architecture.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Converting BSON data through codecs
2+
3+
The codec system is a more advanced way to convert BSON data to native types and back, designed for libraries with more
4+
advanced use cases, e.g. object mappers. It is designed to decouple the serialisation logic from the data model,
5+
allowing for more flexible implementations.
6+
7+
## Encoders and Decoders
8+
9+
The codec interface is split into two smaller interfaces: encoders and decoders. Both interfaces are marked as internal,
10+
as users are only expected to interact with the Codec interface. The interfaces are typed using Psalm generics, allowing
11+
for better type checking when they are used. Without type annotations, the interfaces are equivalent to the following:
12+
13+
```php
14+
namespace MongoDB\Codec;
15+
16+
interface Decoder
17+
{
18+
public function canDecode(mixed $value): bool;
19+
20+
public function decode(mixed $value): mixed;
21+
22+
public function decodeIfSupported(mixed $value): mixed;
23+
}
24+
25+
interface Encoder
26+
{
27+
public function canEncode(mixed $value): bool;
28+
29+
public function encode(mixed $value): mixed;
30+
31+
public function encodeIfSupported(mixed $value): mixed;
32+
}
33+
```
34+
35+
## Codec interface
36+
37+
The `Codec` interface combines decoding and encoding into a single interface. This will be used for most values except
38+
for documents where a more specific `DocumentCodec` is provided.
39+
40+
The base interface supports encoding from a `NativeType` to a `BSONType` and back. Helper methods to determine whether a
41+
value is supported are provided. The `decodeIfSupported` and `encodeIfSupported` methods are useful to have a codec
42+
encode or decode a value only if it is supported. If it is not supported, the original value is returned.
43+
44+
```php
45+
namespace MongoDB\Codec;
46+
47+
/**
48+
* @psalm-template BSONType
49+
* @psalm-template NativeType
50+
* @template-extends Decoder<BSONType, NativeType>
51+
* @template-extends Encoder<BSONType, NativeType>
52+
*/
53+
interface Codec extends Decoder, Encoder
54+
{
55+
}
56+
```
57+
58+
## Document codec
59+
60+
The document codec is special as it is guaranteed to always encode to a BSON document instance and decode to a PHP
61+
object. Document codecs can be provided to a `MongoDB\Collection` instance to have it automatically decode data read
62+
from the database. Likewise, any supported value is encoded before writing to the database in `insert` and `replace`
63+
operations.
64+
65+
```php
66+
namespace MongoDB\Codec;
67+
68+
use MongoDB\BSON\Document;
69+
70+
/**
71+
* @template ObjectType of object
72+
* @extends Codec<ObjectType, Document>
73+
*/
74+
interface DocumentCodec extends Codec
75+
{
76+
}
77+
```
78+
79+
## Using codecs
80+
81+
The `MongoDB\Collection` class and all operations that work with documents now take a `codec` option. This can be
82+
an instance of a `DocumentCodec` that will be used to encode documents (for insert and replace operations) and decode
83+
them into PHP objects when reading data.
84+
85+
### Codecs and type maps
86+
87+
When providing a value for the `codec` option, it takes precedence over the `typeMap` option. An exception is made
88+
when the `codec` option was specified on the collection level, but an operation is given a `typeMap` option. In
89+
this case, the type map is used. The precedence order is as follows:
90+
91+
* operation-level `codec` option
92+
* operation-level `typeMap` option
93+
* collection-level `codec` option
94+
* collection-level `typeMap` option
95+
96+
Codecs are not inherited from the client or the database object, as they are purely used for operations that return
97+
documents. However, database- or client-level aggregation commands will take an operation-level codec option to
98+
decode the resulting documents.
99+

0 commit comments

Comments
 (0)