Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit cf3a5ea

Browse files
committed
Add array and object codecs
These codecs iterate over an array or stdClass instance and handle all of its values
1 parent c581c3f commit cf3a5ea

File tree

6 files changed

+421
-0
lines changed

6 files changed

+421
-0
lines changed

‎psalm-baseline.xml‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,33 @@
2323
</MixedAssignment>
2424
</file>
2525
<file src="src/Codec/DecodeIfSupported.php">
26+
<InvalidReturnType occurrences="1">
27+
<code>($value is BSONType ? NativeType : $value)</code>
28+
</InvalidReturnType>
29+
<MixedArgumentTypeCoercion occurrences="1">
30+
<code>$value</code>
31+
</MixedArgumentTypeCoercion>
2632
<MixedInferredReturnType occurrences="1">
2733
<code>($value is BSONType ? NativeType : $value)</code>
2834
</MixedInferredReturnType>
2935
</file>
3036
<file src="src/Codec/EncodeIfSupported.php">
37+
<InvalidReturnType occurrences="1">
38+
<code>($value is NativeType ? BSONType : $value)</code>
39+
</InvalidReturnType>
40+
<MixedArgumentTypeCoercion occurrences="1">
41+
<code>$value</code>
42+
</MixedArgumentTypeCoercion>
3143
<MixedInferredReturnType occurrences="1">
3244
<code>($value is NativeType ? BSONType : $value)</code>
3345
</MixedInferredReturnType>
3446
</file>
47+
<file src="src/Codec/ObjectCodec.php">
48+
<RawObjectIteration occurrences="2">
49+
<code>$value</code>
50+
<code>$value</code>
51+
</RawObjectIteration>
52+
</file>
3553
<file src="src/Command/ListCollections.php">
3654
<MixedAssignment occurrences="2">
3755
<code>$cmd[$option]</code>

‎src/Codec/ArrayCodec.php‎

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
namespace MongoDB\Codec;
4+
5+
use MongoDB\Exception\InvalidArgumentException;
6+
7+
use function array_map;
8+
use function is_array;
9+
10+
/**
11+
* Codec to recursively encode/decode values in arrays.
12+
*
13+
* @template-implements Codec<array, array>
14+
*/
15+
class ArrayCodec implements Codec, KnowsCodecLibrary
16+
{
17+
/** @template-use DecodeIfSupported<array, array> */
18+
use DecodeIfSupported;
19+
/** @template-use EncodeIfSupported<array, array> */
20+
use EncodeIfSupported;
21+
22+
/** @var CodecLibrary|null */
23+
private $library = null;
24+
25+
public function attachLibrary(CodecLibrary $library): void
26+
{
27+
$this->library = $library;
28+
}
29+
30+
/** @inheritDoc */
31+
public function canDecode($value): bool
32+
{
33+
return is_array($value);
34+
}
35+
36+
/** @inheritDoc */
37+
public function canEncode($value): bool
38+
{
39+
return is_array($value);
40+
}
41+
42+
/** @inheritDoc */
43+
public function decode($value): array
44+
{
45+
if (! $this->canDecode($value)) {
46+
throw InvalidArgumentException::invalidType('$value', $value, 'array');
47+
}
48+
49+
return array_map(
50+
/**
51+
* @param mixed $item
52+
* @return mixed
53+
*/
54+
function ($item) {
55+
return $this->getLibrary()->decodeIfSupported($item);
56+
},
57+
$value
58+
);
59+
}
60+
61+
/** @inheritDoc */
62+
public function encode($value): array
63+
{
64+
if (! $this->canEncode($value)) {
65+
throw InvalidArgumentException::invalidType('$value', $value, 'array');
66+
}
67+
68+
return array_map(
69+
/**
70+
* @param mixed $item
71+
* @return mixed
72+
*/
73+
function ($item) {
74+
return $this->getLibrary()->encodeIfSupported($item);
75+
},
76+
$value
77+
);
78+
}
79+
80+
private function getLibrary(): CodecLibrary
81+
{
82+
if (! $this->library) {
83+
$this->library = new CodecLibrary();
84+
}
85+
86+
return $this->library;
87+
}
88+
}

‎src/Codec/ObjectCodec.php‎

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
namespace MongoDB\Codec;
4+
5+
use MongoDB\Exception\InvalidArgumentException;
6+
use stdClass;
7+
8+
use function assert;
9+
use function is_string;
10+
11+
/**
12+
* Codec for lazy decoding of BSON PackedArray instances
13+
*
14+
* @template-implements Codec<stdClass, stdClass>
15+
*/
16+
class ObjectCodec implements Codec, KnowsCodecLibrary
17+
{
18+
/** @template-use DecodeIfSupported<stdClass, stdClass> */
19+
use DecodeIfSupported;
20+
/** @template-use EncodeIfSupported<stdClass, stdClass> */
21+
use EncodeIfSupported;
22+
23+
/** @var CodecLibrary|null */
24+
private $library = null;
25+
26+
public function attachLibrary(CodecLibrary $library): void
27+
{
28+
$this->library = $library;
29+
}
30+
31+
/** @inheritDoc */
32+
public function canDecode($value): bool
33+
{
34+
return $value instanceof stdClass;
35+
}
36+
37+
/** @inheritDoc */
38+
public function canEncode($value): bool
39+
{
40+
return $value instanceof stdClass;
41+
}
42+
43+
/** @inheritDoc */
44+
public function decode($value): stdClass
45+
{
46+
if (! $this->canDecode($value)) {
47+
throw InvalidArgumentException::invalidType('$value', $value, 'stdClass');
48+
}
49+
50+
$return = new stdClass();
51+
52+
/** @var mixed $item */
53+
foreach ($value as $key => $item) {
54+
assert(is_string($key));
55+
$return->{$key} = $this->getLibrary()->decodeIfSupported($item);
56+
}
57+
58+
return $return;
59+
}
60+
61+
/** @inheritDoc */
62+
public function encode($value): stdClass
63+
{
64+
if (! $this->canEncode($value)) {
65+
throw InvalidArgumentException::invalidType('$value', $value, 'stdClass');
66+
}
67+
68+
$return = new stdClass();
69+
70+
/** @var mixed $item */
71+
foreach ($value as $key => $item) {
72+
assert(is_string($key));
73+
$return->{$key} = $this->getLibrary()->encodeIfSupported($item);
74+
}
75+
76+
return $return;
77+
}
78+
79+
private function getLibrary(): CodecLibrary
80+
{
81+
if (! $this->library) {
82+
$this->library = new CodecLibrary();
83+
}
84+
85+
return $this->library;
86+
}
87+
}

‎src/Codec/architecture.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,8 @@ Codecs are not inherited from the client or the database object, as they are pur
9797
documents. However, database- or client-level aggregation commands will take an operation-level codec option to
9898
decode the resulting documents.
9999

100+
## Built-in codecs
101+
102+
By default, two codecs are provided: an `ArrayCodec` and an `ObjectCodec`. These two codecs are used to recursively
103+
encode and decode values in arrays and `stdClass` instances, respectively. `ObjectCodec` only handles public properties
104+
in objects and ignores other properties.

‎tests/Codec/ArrayCodecTest.php‎

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
3+
namespace MongoDB\Tests\Codec;
4+
5+
use MongoDB\Codec\ArrayCodec;
6+
use MongoDB\Codec\Codec;
7+
use MongoDB\Codec\CodecLibrary;
8+
use MongoDB\Codec\DecodeIfSupported;
9+
use MongoDB\Codec\EncodeIfSupported;
10+
use MongoDB\Tests\TestCase;
11+
12+
class ArrayCodecTest extends TestCase
13+
{
14+
public function testDecodeList(): void
15+
{
16+
$value = [
17+
'magic',
18+
'cigam',
19+
];
20+
21+
$this->assertSame(['magic', 'magic'], $this->getCodec()->decode($value));
22+
}
23+
24+
public function testDecodeListWithGaps(): void
25+
{
26+
$value = [
27+
0 => 'magic',
28+
2 => 'cigam',
29+
];
30+
31+
$this->assertSame([0 => 'magic', 2 => 'magic'], $this->getCodec()->decode($value));
32+
}
33+
34+
public function testDecodeHash(): void
35+
{
36+
$value = [
37+
'foo' => 'magic',
38+
'bar' => 'cigam',
39+
];
40+
41+
$this->assertSame(['foo' => 'magic', 'bar' => 'magic'], $this->getCodec()->decode($value));
42+
}
43+
44+
public function testEncode(): void
45+
{
46+
$value = [
47+
'magic',
48+
'cigam',
49+
];
50+
51+
$this->assertSame(['cigam', 'cigam'], $this->getCodec()->encode($value));
52+
}
53+
54+
public function testEncodeListWithGaps(): void
55+
{
56+
$value = [
57+
0 => 'magic',
58+
2 => 'cigam',
59+
];
60+
61+
$this->assertSame([0 => 'cigam', 2 => 'cigam'], $this->getCodec()->encode($value));
62+
}
63+
64+
public function testEncodeHash(): void
65+
{
66+
$value = [
67+
'foo' => 'magic',
68+
'bar' => 'cigam',
69+
];
70+
71+
$this->assertSame(['foo' => 'cigam', 'bar' => 'cigam'], $this->getCodec()->encode($value));
72+
}
73+
74+
private function getCodec(): ArrayCodec
75+
{
76+
$arrayCodec = new ArrayCodec();
77+
$arrayCodec->attachLibrary($this->getCodecLibrary());
78+
79+
return $arrayCodec;
80+
}
81+
82+
private function getCodecLibrary(): CodecLibrary
83+
{
84+
return new CodecLibrary(
85+
/** @template-implements Codec<string, string> */
86+
new class implements Codec
87+
{
88+
use DecodeIfSupported;
89+
use EncodeIfSupported;
90+
91+
public function canDecode($value): bool
92+
{
93+
return $value === 'cigam';
94+
}
95+
96+
public function canEncode($value): bool
97+
{
98+
return $value === 'magic';
99+
}
100+
101+
public function decode($value)
102+
{
103+
return 'magic';
104+
}
105+
106+
public function encode($value)
107+
{
108+
return 'cigam';
109+
}
110+
}
111+
);
112+
}
113+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /