diff --git a/src/Serializer.php b/src/Serializer.php index 49f4031c4..1c39ced47 100644 --- a/src/Serializer.php +++ b/src/Serializer.php @@ -69,6 +69,11 @@ class Serializer private $messageTypeTransformers; private $decodeFieldTransformers; private $decodeMessageTypeTransformers; + // Array of key-value pairs which specify a custom encoding function. + // The key is the proto class and the value is the function + // which will be used to convert the proto instead of the + // encodeMessage method from the Serializer class. + private $customEncoders; private $descriptorMaps = []; @@ -84,12 +89,14 @@ public function __construct( $fieldTransformers = [], $messageTypeTransformers = [], $decodeFieldTransformers = [], - $decodeMessageTypeTransformers = [] + $decodeMessageTypeTransformers = [], + $customEncoders = [], ) { $this->fieldTransformers = $fieldTransformers; $this->messageTypeTransformers = $messageTypeTransformers; $this->decodeFieldTransformers = $decodeFieldTransformers; $this->decodeMessageTypeTransformers = $decodeMessageTypeTransformers; + $this->customEncoders = $customEncoders; } /** @@ -101,6 +108,14 @@ public function __construct( */ public function encodeMessage($message) { + $cls = get_class($message); + + // If we have supplied a customEncoder for this class type, + // then we use that instead of the general encodeMessage definition. + if (array_key_exists($cls, $this->customEncoders)) { + $func = $this->customEncoders[$cls]; + return call_user_func($func, $message); + } // Get message descriptor $pool = DescriptorPool::getGeneratedPool(); $messageType = $pool->getDescriptorByClassName(get_class($message)); diff --git a/tests/Tests/Unit/SerializerTest.php b/tests/Tests/Unit/SerializerTest.php index 393305327..386f7b254 100644 --- a/tests/Tests/Unit/SerializerTest.php +++ b/tests/Tests/Unit/SerializerTest.php @@ -291,4 +291,64 @@ public function testSpecialEncodingDecodingByFieldType() $this->assertEqualsWithDelta($data['blue'], $array['blue'], 0.0000001); $this->assertEqualsWithDelta($data['alpha']['value'], $array['alpha']['value'], 0.0000001); } + + /** + * @dataProvider customEncoderProvider + */ + public function testCustomEncoderForEncodeMessage($customEncoder, $protoObj, $expectedData) + { + $serializer = new Serializer([], [], [], [], $customEncoder); + + $data = $serializer->encodeMessage($protoObj); + array_walk($expectedData, function ($val, $key, $expectedData) { + $this->assertEquals($val, $expectedData[$key]); + }, $expectedData); + } + + public function customEncoderProvider() + { + $original = [ + 'red' => 50.0, + 'blue' => 50.0 + ]; + + $expected = [ + 'red' => 100.0, + 'blue' => 100.0 + ]; + + return [ + [ + [ + Color::class => function ($message) { + return [ + 'red' => $message->getRed() * 2, + 'blue' => $message->getBlue() * 2 + ]; + } + ], + new Color($original), + $expected + ], + [ + // When no custom encoder is supplied, the encodeMessage will return the data + // that is passed into the proto + [ + ], + new Color($original), + $original + ], + [ + // When a custom encoder for a different protois supplied, + // the encodeMessage will return the data as if no custom encoder was supplied + [ + Status::class => function ($message) { + return ['foo' => 'bar']; + } + ], + new Color($original), + $original + ] + ]; + } }