-
Notifications
You must be signed in to change notification settings - Fork 264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PHPLIB-1180: Add basic infrastructure for codecs #1125
Changes from all commits
1678dd9
e6810d1
8e818a3
3134ef0
fb5a7a7
5f530b9
2fe40d2
9e93ba9
1d2859b
3ae9681
b6db635
6476ede
31c5414
00592ae
dd35ad4
6a70032
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?php | ||
/* | ||
* Copyright 2023-present MongoDB, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
namespace MongoDB\Codec; | ||
|
||
/** | ||
* The Codec interface allows decoding BSON data to native PHP types and back | ||
* to BSON. | ||
* | ||
* @psalm-template BSONType | ||
* @psalm-template NativeType | ||
* @template-extends Decoder<BSONType, NativeType> | ||
* @template-extends Encoder<BSONType, NativeType> | ||
*/ | ||
interface Codec extends Decoder, Encoder | ||
{ | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
<?php | ||
/* | ||
* Copyright 2023-present MongoDB, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
namespace MongoDB\Codec; | ||
|
||
use MongoDB\Exception\InvalidArgumentException; | ||
use MongoDB\Exception\UnsupportedValueException; | ||
|
||
class CodecLibrary implements Codec | ||
{ | ||
use DecodeIfSupported; | ||
use EncodeIfSupported; | ||
|
||
/** @var array<Decoder> */ | ||
private $decoders = []; | ||
|
||
/** @var array<Encoder> */ | ||
private $encoders = []; | ||
|
||
/** @param Decoder|Encoder $items */ | ||
public function __construct(...$items) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Before we settle on this signature, I just want to confirm that you don't expect we'd ever need to solicit additional params in the constructor (e.g. options array). If so, consider making this an array argument. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so - this particular library is a first-come-first-serve library. If we have the need for different behaviour, I'd rather create a separate library class for the purpose. |
||
{ | ||
foreach ($items as $item) { | ||
if (! $item instanceof Decoder && ! $item instanceof Encoder) { | ||
throw InvalidArgumentException::invalidType('$items', $item, [Decoder::class, Encoder::class]); | ||
} | ||
|
||
if ($item instanceof Codec) { | ||
// Use attachCodec to avoid multiple calls to attachLibrary | ||
$this->attachCodec($item); | ||
|
||
continue; | ||
} | ||
|
||
if ($item instanceof Decoder) { | ||
$this->attachDecoder($item); | ||
} | ||
|
||
if ($item instanceof Encoder) { | ||
$this->attachEncoder($item); | ||
} | ||
} | ||
} | ||
|
||
/** @return static */ | ||
final public function attachCodec(Codec $codec): self | ||
{ | ||
$this->decoders[] = $codec; | ||
$this->encoders[] = $codec; | ||
if ($codec instanceof KnowsCodecLibrary) { | ||
$codec->attachCodecLibrary($this); | ||
} | ||
|
||
return $this; | ||
} | ||
|
||
/** @return static */ | ||
final public function attachDecoder(Decoder $decoder): self | ||
{ | ||
$this->decoders[] = $decoder; | ||
if ($decoder instanceof KnowsCodecLibrary) { | ||
$decoder->attachCodecLibrary($this); | ||
} | ||
|
||
return $this; | ||
} | ||
|
||
/** @return static */ | ||
final public function attachEncoder(Encoder $encoder): self | ||
{ | ||
$this->encoders[] = $encoder; | ||
if ($encoder instanceof KnowsCodecLibrary) { | ||
$encoder->attachCodecLibrary($this); | ||
} | ||
|
||
return $this; | ||
} | ||
|
||
/** @param mixed $value */ | ||
final public function canDecode($value): bool | ||
{ | ||
foreach ($this->decoders as $decoder) { | ||
if ($decoder->canDecode($value)) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** @param mixed $value */ | ||
final public function canEncode($value): bool | ||
{ | ||
foreach ($this->encoders as $encoder) { | ||
if ($encoder->canEncode($value)) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* @param mixed $value | ||
* @return mixed | ||
*/ | ||
final public function decode($value) | ||
{ | ||
foreach ($this->decoders as $decoder) { | ||
if ($decoder->canDecode($value)) { | ||
return $decoder->decode($value); | ||
} | ||
} | ||
|
||
throw UnsupportedValueException::invalidDecodableValue($value); | ||
} | ||
|
||
/** | ||
* @param mixed $value | ||
* @return mixed | ||
*/ | ||
final public function encode($value) | ||
{ | ||
foreach ($this->encoders as $encoder) { | ||
if ($encoder->canEncode($value)) { | ||
return $encoder->encode($value); | ||
} | ||
} | ||
|
||
throw UnsupportedValueException::invalidEncodableValue($value); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
<?php | ||
/* | ||
* Copyright 2023-present MongoDB, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
namespace MongoDB\Codec; | ||
|
||
use MongoDB\Exception\UnsupportedValueException; | ||
|
||
/** | ||
* @psalm-template BSONType | ||
* @psalm-template NativeType | ||
*/ | ||
trait DecodeIfSupported | ||
{ | ||
/** | ||
* @param mixed $value | ||
* @psalm-assert-if-true BSONType $value | ||
*/ | ||
abstract public function canDecode($value): bool; | ||
|
||
/** | ||
* @param mixed $value | ||
* @psalm-param BSONType $value | ||
* @return mixed | ||
* @psalm-return NativeType | ||
* @throws UnsupportedValueException if the decoder does not support the value | ||
*/ | ||
abstract public function decode($value); | ||
|
||
/** | ||
* @param mixed $value | ||
* @return mixed | ||
* @psalm-return ($value is BSONType ? NativeType : $value) | ||
*/ | ||
public function decodeIfSupported($value) | ||
{ | ||
return $this->canDecode($value) ? $this->decode($value) : $value; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<?php | ||
/* | ||
* Copyright 2023-present MongoDB, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
namespace MongoDB\Codec; | ||
|
||
use MongoDB\Exception\UnsupportedValueException; | ||
|
||
/** | ||
* @psalm-template BSONType | ||
* @psalm-template NativeType | ||
*/ | ||
interface Decoder | ||
{ | ||
/** | ||
* Checks if the decoder supports a given value. | ||
* | ||
* @param mixed $value | ||
* @psalm-assert-if-true BSONType $value | ||
*/ | ||
public function canDecode($value): bool; | ||
|
||
/** | ||
* Decodes a given value. If the decoder does not support the value, it | ||
* should throw an exception. | ||
* | ||
* @param mixed $value | ||
* @psalm-param BSONType $value | ||
* @return mixed | ||
* @psalm-return NativeType | ||
* @throws UnsupportedValueException if the decoder does not support the value | ||
*/ | ||
public function decode($value); | ||
|
||
/** | ||
* Decodes a given value if supported, otherwise returns the value as-is. | ||
* | ||
* The DecodeIfSupported trait provides a default implementation of this | ||
* method. | ||
* | ||
* @param mixed $value | ||
* @return mixed | ||
* @psalm-return ($value is BSONType ? NativeType : $value) | ||
*/ | ||
public function decodeIfSupported($value); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?php | ||
/* | ||
* Copyright 2023-present MongoDB, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
namespace MongoDB\Codec; | ||
|
||
use MongoDB\BSON\Document; | ||
use MongoDB\Exception\UnsupportedValueException; | ||
|
||
/** | ||
* The DocumentCodec interface allows decoding BSON document data to native PHP | ||
* objects and back to BSON documents. | ||
* | ||
* @psalm-template ObjectType of object | ||
* @template-extends Codec<Document, ObjectType> | ||
*/ | ||
interface DocumentCodec extends Codec | ||
{ | ||
/** | ||
* @param mixed $value | ||
* @psalm-param Document $value | ||
* @psalm-return ObjectType | ||
* @throws UnsupportedValueException if the decoder does not support the value | ||
*/ | ||
public function decode($value): object; | ||
jmikola marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** | ||
* @param mixed $value | ||
* @psalm-param ObjectType $value | ||
* @throws UnsupportedValueException if the encoder does not support the value | ||
*/ | ||
public function encode($value): Document; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget to add copyright copypasta to all of the source files:
Not needed in tests and I think we can skip this for the stubs, too.