PluginProbe
Media Cloud Sync / 1.2.4
Media Cloud Sync v1.2.4
1.4.2 1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 All 36 releases
media-cloud-sync / includes / sdk / google / google / gax / src / Serializer.php

Serializer.php in Media Cloud Sync 1.2.4, at includes/sdk/google/google/gax/src/Serializer.php

422 lines 16.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * Copyright 2017 Google LLC
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following disclaimer
15 * in the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Google Inc. nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 namespace Dudlewebs\WPMCS\Google\ApiCore;
34
35 use Dudlewebs\WPMCS\Google\Protobuf\Any;
36 use Dudlewebs\WPMCS\Google\Protobuf\Descriptor;
37 use Dudlewebs\WPMCS\Google\Protobuf\DescriptorPool;
38 use Dudlewebs\WPMCS\Google\Protobuf\FieldDescriptor;
39 use Dudlewebs\WPMCS\Google\Protobuf\Internal\Message;
40 use RuntimeException;
41 /**
42 * Collection of methods to help with serialization of protobuf objects
43 */
44 class Serializer
45 {
46 const MAP_KEY_FIELD_NAME = 'key';
47 const MAP_VALUE_FIELD_NAME = 'value';
48 private static $phpArraySerializer;
49 private static $metadataKnownTypes = ['google.rpc.retryinfo-bin' => \Dudlewebs\WPMCS\Google\Rpc\RetryInfo::class, 'google.rpc.debuginfo-bin' => \Dudlewebs\WPMCS\Google\Rpc\DebugInfo::class, 'google.rpc.quotafailure-bin' => \Dudlewebs\WPMCS\Google\Rpc\QuotaFailure::class, 'google.rpc.badrequest-bin' => \Dudlewebs\WPMCS\Google\Rpc\BadRequest::class, 'google.rpc.requestinfo-bin' => \Dudlewebs\WPMCS\Google\Rpc\RequestInfo::class, 'google.rpc.resourceinfo-bin' => \Dudlewebs\WPMCS\Google\Rpc\ResourceInfo::class, 'google.rpc.errorinfo-bin' => \Dudlewebs\WPMCS\Google\Rpc\ErrorInfo::class, 'google.rpc.help-bin' => \Dudlewebs\WPMCS\Google\Rpc\Help::class, 'google.rpc.localizedmessage-bin' => \Dudlewebs\WPMCS\Google\Rpc\LocalizedMessage::class];
50 private $fieldTransformers;
51 private $messageTypeTransformers;
52 private $decodeFieldTransformers;
53 private $decodeMessageTypeTransformers;
54 private $descriptorMaps = [];
55 /**
56 * Serializer constructor.
57 *
58 * @param array $fieldTransformers An array mapping field names to transformation functions
59 * @param array $messageTypeTransformers An array mapping message names to transformation functions
60 * @param array $decodeFieldTransformers An array mapping field names to transformation functions
61 * @param array $decodeMessageTypeTransformers An array mapping message names to transformation functions
62 */
63 public function __construct($fieldTransformers = [], $messageTypeTransformers = [], $decodeFieldTransformers = [], $decodeMessageTypeTransformers = [])
64 {
65 $this->fieldTransformers = $fieldTransformers;
66 $this->messageTypeTransformers = $messageTypeTransformers;
67 $this->decodeFieldTransformers = $decodeFieldTransformers;
68 $this->decodeMessageTypeTransformers = $decodeMessageTypeTransformers;
69 }
70 /**
71 * Encode protobuf message as a PHP array
72 *
73 * @param mixed $message
74 * @return array
75 * @throws ValidationException
76 */
77 public function encodeMessage($message)
78 {
79 // Get message descriptor
80 $pool = DescriptorPool::getGeneratedPool();
81 $messageType = $pool->getDescriptorByClassName(get_class($message));
82 try {
83 return $this->encodeMessageImpl($message, $messageType);
84 } catch (\Exception $e) {
85 throw new ValidationException("Error encoding message: " . $e->getMessage(), $e->getCode(), $e);
86 }
87 }
88 /**
89 * Decode PHP array into the specified protobuf message
90 *
91 * @param mixed $message
92 * @param array $data
93 * @return mixed
94 * @throws ValidationException
95 */
96 public function decodeMessage($message, array $data)
97 {
98 // Get message descriptor
99 $pool = DescriptorPool::getGeneratedPool();
100 $messageType = $pool->getDescriptorByClassName(get_class($message));
101 try {
102 return $this->decodeMessageImpl($message, $messageType, $data);
103 } catch (\Exception $e) {
104 throw new ValidationException("Error decoding message: " . $e->getMessage(), $e->getCode(), $e);
105 }
106 }
107 /**
108 * @param Message $message
109 * @return string Json representation of $message
110 * @throws ValidationException
111 */
112 public static function serializeToJson(Message $message)
113 {
114 return json_encode(self::serializeToPhpArray($message), \JSON_PRETTY_PRINT);
115 }
116 /**
117 * @param Message $message
118 * @return array PHP array representation of $message
119 * @throws ValidationException
120 */
121 public static function serializeToPhpArray(Message $message)
122 {
123 return self::getPhpArraySerializer()->encodeMessage($message);
124 }
125 /**
126 * Decode metadata received from gRPC status object
127 *
128 * @param array $metadata
129 * @return array
130 */
131 public static function decodeMetadata(array $metadata)
132 {
133 if (count($metadata) == 0) {
134 return [];
135 }
136 $result = [];
137 foreach ($metadata as $key => $values) {
138 foreach ($values as $value) {
139 $decodedValue = ['@type' => $key];
140 if (self::hasBinaryHeaderSuffix($key)) {
141 if (isset(self::$metadataKnownTypes[$key])) {
142 $class = self::$metadataKnownTypes[$key];
143 /** @var Message $message */
144 $message = new $class();
145 try {
146 $message->mergeFromString($value);
147 $decodedValue += self::serializeToPhpArray($message);
148 } catch (\Exception $e) {
149 // We encountered an error trying to deserialize the data
150 $decodedValue += ['data' => '<Unable to deserialize data>'];
151 }
152 } else {
153 // The metadata contains an unexpected binary type
154 $decodedValue += ['data' => '<Unknown Binary Data>'];
155 }
156 } else {
157 $decodedValue += ['data' => $value];
158 }
159 $result[] = $decodedValue;
160 }
161 }
162 return $result;
163 }
164 /**
165 * Decode an array of Any messages into a printable PHP array.
166 *
167 * @param iterable $anyArray
168 * @return array
169 */
170 public static function decodeAnyMessages($anyArray)
171 {
172 $results = [];
173 foreach ($anyArray as $any) {
174 try {
175 /** @var Any $any */
176 /** @var Message $unpacked */
177 $unpacked = $any->unpack();
178 $results[] = self::serializeToPhpArray($unpacked);
179 } catch (\Exception $ex) {
180 echo "{$ex}\n";
181 // failed to unpack the $any object - show as unknown binary data
182 $results[] = ['typeUrl' => $any->getTypeUrl(), 'value' => '<Unknown Binary Data>'];
183 }
184 }
185 return $results;
186 }
187 /**
188 * @param FieldDescriptor $field
189 * @param Message|array|string $data
190 * @return mixed
191 * @throws \Exception
192 */
193 private function encodeElement(FieldDescriptor $field, $data)
194 {
195 switch ($field->getType()) {
196 case GPBType::MESSAGE:
197 if (is_array($data)) {
198 $result = $data;
199 } else {
200 $result = $this->encodeMessageImpl($data, $field->getMessageType());
201 }
202 $messageType = $field->getMessageType()->getFullName();
203 if (isset($this->messageTypeTransformers[$messageType])) {
204 $result = $this->messageTypeTransformers[$messageType]($result);
205 }
206 break;
207 default:
208 $result = $data;
209 break;
210 }
211 if (isset($this->fieldTransformers[$field->getName()])) {
212 $result = $this->fieldTransformers[$field->getName()]($result);
213 }
214 return $result;
215 }
216 private function getDescriptorMaps(Descriptor $descriptor)
217 {
218 if (!isset($this->descriptorMaps[$descriptor->getFullName()])) {
219 $fieldsByName = [];
220 $fieldCount = $descriptor->getFieldCount();
221 for ($i = 0; $i < $fieldCount; $i++) {
222 $field = $descriptor->getField($i);
223 $fieldsByName[$field->getName()] = $field;
224 }
225 $fieldToOneof = [];
226 $oneofCount = $descriptor->getOneofDeclCount();
227 for ($i = 0; $i < $oneofCount; $i++) {
228 $oneof = $descriptor->getOneofDecl($i);
229 $oneofFieldCount = $oneof->getFieldCount();
230 for ($j = 0; $j < $oneofFieldCount; $j++) {
231 $field = $oneof->getField($j);
232 $fieldToOneof[$field->getName()] = $oneof->getName();
233 }
234 }
235 $this->descriptorMaps[$descriptor->getFullName()] = [$fieldsByName, $fieldToOneof];
236 }
237 return $this->descriptorMaps[$descriptor->getFullName()];
238 }
239 /**
240 * @param Message $message
241 * @param Descriptor $messageType
242 * @return array
243 * @throws \Exception
244 */
245 private function encodeMessageImpl(Message $message, Descriptor $messageType)
246 {
247 $data = [];
248 $fieldCount = $messageType->getFieldCount();
249 for ($i = 0; $i < $fieldCount; $i++) {
250 $field = $messageType->getField($i);
251 $key = $field->getName();
252 $getter = $this->getGetter($key);
253 $v = $message->{$getter}();
254 if (is_null($v)) {
255 continue;
256 }
257 // Check and skip unset fields inside oneofs
258 list($_, $fieldsToOneof) = $this->getDescriptorMaps($messageType);
259 if (isset($fieldsToOneof[$key])) {
260 $oneofName = $fieldsToOneof[$key];
261 $oneofGetter = $this->getGetter($oneofName);
262 if ($message->{$oneofGetter}() !== $key) {
263 continue;
264 }
265 }
266 if ($field->isMap()) {
267 list($mapFieldsByName, $_) = $this->getDescriptorMaps($field->getMessageType());
268 $keyField = $mapFieldsByName[self::MAP_KEY_FIELD_NAME];
269 $valueField = $mapFieldsByName[self::MAP_VALUE_FIELD_NAME];
270 $arr = [];
271 foreach ($v as $k => $vv) {
272 $arr[$this->encodeElement($keyField, $k)] = $this->encodeElement($valueField, $vv);
273 }
274 $v = $arr;
275 } elseif ($field->getLabel() === GPBLabel::REPEATED) {
276 $arr = [];
277 foreach ($v as $k => $vv) {
278 $arr[$k] = $this->encodeElement($field, $vv);
279 }
280 $v = $arr;
281 } else {
282 $v = $this->encodeElement($field, $v);
283 }
284 $key = self::toCamelCase($key);
285 $data[$key] = $v;
286 }
287 return $data;
288 }
289 /**
290 * @param FieldDescriptor $field
291 * @param mixed $data
292 * @return mixed
293 * @throws \Exception
294 */
295 private function decodeElement(FieldDescriptor $field, $data)
296 {
297 if (isset($this->decodeFieldTransformers[$field->getName()])) {
298 $data = $this->decodeFieldTransformers[$field->getName()]($data);
299 }
300 switch ($field->getType()) {
301 case GPBType::MESSAGE:
302 if ($data instanceof Message) {
303 return $data;
304 }
305 $messageType = $field->getMessageType();
306 $messageTypeName = $messageType->getFullName();
307 $klass = $messageType->getClass();
308 $msg = new $klass();
309 if (isset($this->decodeMessageTypeTransformers[$messageTypeName])) {
310 $data = $this->decodeMessageTypeTransformers[$messageTypeName]($data);
311 }
312 return $this->decodeMessageImpl($msg, $messageType, $data);
313 default:
314 return $data;
315 }
316 }
317 /**
318 * @param Message $message
319 * @param Descriptor $messageType
320 * @param array $data
321 * @return mixed
322 * @throws \Exception
323 */
324 private function decodeMessageImpl(Message $message, Descriptor $messageType, array $data)
325 {
326 list($fieldsByName, $_) = $this->getDescriptorMaps($messageType);
327 foreach ($data as $key => $v) {
328 // Get the field by tag number or name
329 $fieldName = self::toSnakeCase($key);
330 // Unknown field found
331 if (!isset($fieldsByName[$fieldName])) {
332 throw new RuntimeException(sprintf("cannot handle unknown field %s on message %s", $fieldName, $messageType->getFullName()));
333 }
334 /** @var FieldDescriptor $field */
335 $field = $fieldsByName[$fieldName];
336 if ($field->isMap()) {
337 list($mapFieldsByName, $_) = $this->getDescriptorMaps($field->getMessageType());
338 $keyField = $mapFieldsByName[self::MAP_KEY_FIELD_NAME];
339 $valueField = $mapFieldsByName[self::MAP_VALUE_FIELD_NAME];
340 $arr = [];
341 foreach ($v as $k => $vv) {
342 $arr[$this->decodeElement($keyField, $k)] = $this->decodeElement($valueField, $vv);
343 }
344 $value = $arr;
345 } elseif ($field->getLabel() === GPBLabel::REPEATED) {
346 $arr = [];
347 foreach ($v as $k => $vv) {
348 $arr[$k] = $this->decodeElement($field, $vv);
349 }
350 $value = $arr;
351 } else {
352 $value = $this->decodeElement($field, $v);
353 }
354 $setter = $this->getSetter($field->getName());
355 $message->{$setter}($value);
356 // We must unset $value here, otherwise the protobuf c extension will mix up the references
357 // and setting one value will change all others
358 unset($value);
359 }
360 return $message;
361 }
362 /**
363 * @param string $name
364 * @return string Getter function
365 */
366 public static function getGetter(string $name)
367 {
368 return 'get' . ucfirst(self::toCamelCase($name));
369 }
370 /**
371 * @param string $name
372 * @return string Setter function
373 */
374 public static function getSetter(string $name)
375 {
376 return 'set' . ucfirst(self::toCamelCase($name));
377 }
378 /**
379 * Convert string from camelCase to snake_case
380 *
381 * @param string $key
382 * @return string
383 */
384 public static function toSnakeCase(string $key)
385 {
386 return strtolower(preg_replace(['/([a-z\d])([A-Z])/', '/([^_])([A-Z][a-z])/'], '$1_$2', $key));
387 }
388 /**
389 * Convert string from snake_case to camelCase
390 *
391 * @param string $key
392 * @return string
393 */
394 public static function toCamelCase(string $key)
395 {
396 return lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $key))));
397 }
398 private static function hasBinaryHeaderSuffix(string $key)
399 {
400 return substr_compare($key, "-bin", strlen($key) - 4) === 0;
401 }
402 private static function getPhpArraySerializer()
403 {
404 if (is_null(self::$phpArraySerializer)) {
405 self::$phpArraySerializer = new Serializer();
406 }
407 return self::$phpArraySerializer;
408 }
409 public static function loadKnownMetadataTypes()
410 {
411 foreach (self::$metadataKnownTypes as $key => $class) {
412 new $class();
413 }
414 }
415 }
416 // It is necessary to call this when this file is included. Otherwise we cannot be
417 // guaranteed that the relevant classes will be loaded into the protobuf descriptor
418 // pool when we try to unpack an Any object containing that class.
419 // phpcs:disable PSR1.Files.SideEffects
420 Serializer::loadKnownMetadataTypes();
421 // phpcs:enable
422