Skip to content

Commit 1f9efc8

Browse files
committed
Introduce codec library
1 parent 8650660 commit 1f9efc8

File tree

6 files changed

+396
-0
lines changed

6 files changed

+396
-0
lines changed

psalm-baseline.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@
2222
<code>$mergedDriver['platform']</code>
2323
</MixedAssignment>
2424
</file>
25+
<file src="src/Codec/DecodeIfSupported.php">
26+
<MixedInferredReturnType occurrences="1">
27+
<code>($value is BSONType ? NativeType : $value)</code>
28+
</MixedInferredReturnType>
29+
</file>
30+
<file src="src/Codec/EncodeIfSupported.php">
31+
<MixedInferredReturnType occurrences="1">
32+
<code>($value is NativeType ? BSONType : $value)</code>
33+
</MixedInferredReturnType>
34+
</file>
2535
<file src="src/Command/ListCollections.php">
2636
<MixedAssignment occurrences="2">
2737
<code>$cmd[$option]</code>

src/Codec/CodecLibrary.php

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<?php
2+
3+
namespace MongoDB\Codec;
4+
5+
use MongoDB\Exception\InvalidArgumentException;
6+
use MongoDB\Exception\UnexpectedValueException;
7+
8+
use function get_debug_type;
9+
use function sprintf;
10+
11+
class CodecLibrary implements Codec
12+
{
13+
use DecodeIfSupported;
14+
use EncodeIfSupported;
15+
16+
/** @var array<Decoder> */
17+
private $decoders = [];
18+
19+
/** @var array<Encoder> */
20+
private $encoders = [];
21+
22+
/** @param Decoder|Encoder $items */
23+
public function __construct(...$items)
24+
{
25+
foreach ($items as $item) {
26+
if (! $item instanceof Decoder && ! $item instanceof Encoder) {
27+
throw InvalidArgumentException::invalidType('$items', $item, [Decoder::class, Encoder::class]);
28+
}
29+
30+
if ($item instanceof Codec) {
31+
// Use attachCodec to avoid multiple calls to attachLibrary
32+
$this->attachCodec($item);
33+
34+
continue;
35+
}
36+
37+
if ($item instanceof Decoder) {
38+
$this->attachDecoder($item);
39+
}
40+
41+
if ($item instanceof Encoder) {
42+
$this->attachEncoder($item);
43+
}
44+
}
45+
}
46+
47+
/** @return static */
48+
final public function attachCodec(Codec $codec): self
49+
{
50+
$this->decoders[] = $codec;
51+
$this->encoders[] = $codec;
52+
if ($codec instanceof KnowsCodecLibrary) {
53+
$codec->attachLibrary($this);
54+
}
55+
56+
return $this;
57+
}
58+
59+
/** @return static */
60+
final public function attachDecoder(Decoder $decoder): self
61+
{
62+
$this->decoders[] = $decoder;
63+
if ($decoder instanceof KnowsCodecLibrary) {
64+
$decoder->attachLibrary($this);
65+
}
66+
67+
return $this;
68+
}
69+
70+
/** @return static */
71+
final public function attachEncoder(Encoder $encoder): self
72+
{
73+
$this->encoders[] = $encoder;
74+
if ($encoder instanceof KnowsCodecLibrary) {
75+
$encoder->attachLibrary($this);
76+
}
77+
78+
return $this;
79+
}
80+
81+
/** @param mixed $value */
82+
final public function canDecode($value): bool
83+
{
84+
foreach ($this->decoders as $decoder) {
85+
if ($decoder->canDecode($value)) {
86+
return true;
87+
}
88+
}
89+
90+
return false;
91+
}
92+
93+
/** @param mixed $value */
94+
final public function canEncode($value): bool
95+
{
96+
foreach ($this->encoders as $encoder) {
97+
if ($encoder->canEncode($value)) {
98+
return true;
99+
}
100+
}
101+
102+
return false;
103+
}
104+
105+
/**
106+
* @param mixed $value
107+
* @return mixed
108+
*/
109+
final public function decode($value)
110+
{
111+
foreach ($this->decoders as $decoder) {
112+
if ($decoder->canDecode($value)) {
113+
return $decoder->decode($value);
114+
}
115+
}
116+
117+
throw new UnexpectedValueException(sprintf('No decoder found for value of type "%s"', get_debug_type($value)));
118+
}
119+
120+
/**
121+
* @param mixed $value
122+
* @return mixed
123+
*/
124+
final public function encode($value)
125+
{
126+
foreach ($this->encoders as $encoder) {
127+
if ($encoder->canEncode($value)) {
128+
return $encoder->encode($value);
129+
}
130+
}
131+
132+
throw new UnexpectedValueException(sprintf('No encoder found for value of type "%s"', get_debug_type($value)));
133+
}
134+
}

src/Codec/DecodeIfSupported.php

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

src/Codec/EncodeIfSupported.php

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

src/Codec/KnowsCodecLibrary.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace MongoDB\Codec;
4+
5+
interface KnowsCodecLibrary
6+
{
7+
public function attachLibrary(CodecLibrary $library): void;
8+
}

0 commit comments

Comments
 (0)