1: | <?php |
2: | |
3: | |
4: | |
5: | |
6: | |
7: | |
8: | |
9: | |
10: | |
11: | |
12: | |
13: | |
14: | |
15: | |
16: | |
17: | |
18: | |
19: | |
20: | |
21: | |
22: | |
23: | |
24: | |
25: | |
26: | |
27: | |
28: | |
29: | namespace Ally\PetStore; |
30: | |
31: | use GuzzleHttp\Psr7\Utils; |
32: | use Ally\PetStore\Schema\ModelInterface; |
33: | |
34: | |
35: | |
36: | |
37: | |
38: | |
39: | |
40: | |
41: | |
42: | class ObjectSerializer |
43: | { |
44: | |
45: | private static $dateTimeFormat = \DateTime::ATOM; |
46: | |
47: | |
48: | |
49: | |
50: | |
51: | |
52: | public static function setDateTimeFormat($format) |
53: | { |
54: | self::$dateTimeFormat = $format; |
55: | } |
56: | |
57: | |
58: | |
59: | |
60: | |
61: | |
62: | |
63: | |
64: | |
65: | |
66: | public static function sanitizeForSerialization($data, $type = null, $format = null) |
67: | { |
68: | if (is_scalar($data) || null === $data) { |
69: | return $data; |
70: | } |
71: | |
72: | if ($data instanceof \DateTime) { |
73: | return ($format === 'date') ? $data->format('Y-m-d') : $data->format(self::$dateTimeFormat); |
74: | } |
75: | |
76: | if (is_array($data)) { |
77: | foreach ($data as $property => $value) { |
78: | $data[$property] = self::sanitizeForSerialization($value); |
79: | } |
80: | return $data; |
81: | } |
82: | |
83: | if (is_object($data)) { |
84: | $values = []; |
85: | if ($data instanceof ModelInterface) { |
86: | $formats = $data::openAPIFormats(); |
87: | foreach ($data::openAPITypes() as $property => $openAPIType) { |
88: | $getter = $data::getters()[$property]; |
89: | $value = $data->$getter(); |
90: | if ($value !== null && !in_array($openAPIType, ['\DateTime', '\SplFileObject', 'array', 'bool', 'boolean', 'byte', 'double', 'float', 'int', 'integer', 'mixed', 'number', 'object', 'string', 'void'], true)) { |
91: | $callable = [$openAPIType, 'getAllowableEnumValues']; |
92: | if (is_callable($callable)) { |
93: | |
94: | $allowedEnumTypes = $callable(); |
95: | if (!in_array($value, $allowedEnumTypes, true)) { |
96: | $imploded = implode("', '", $allowedEnumTypes); |
97: | throw new \InvalidArgumentException("Invalid value for enum '$openAPIType', must be one of: '$imploded'"); |
98: | } |
99: | } |
100: | } |
101: | if (($data::isNullable($property) && $data->isNullableSetToNull($property)) || $value !== null) { |
102: | $values[$data::attributeMap()[$property]] = self::sanitizeForSerialization($value, $openAPIType, $formats[$property]); |
103: | } |
104: | } |
105: | } else { |
106: | foreach($data as $property => $value) { |
107: | $values[$property] = self::sanitizeForSerialization($value); |
108: | } |
109: | } |
110: | return (object)$values; |
111: | } else { |
112: | return (string)$data; |
113: | } |
114: | } |
115: | |
116: | |
117: | |
118: | |
119: | |
120: | |
121: | |
122: | |
123: | |
124: | public static function sanitizeFilename($filename) |
125: | { |
126: | if (preg_match("/.*[\/\\\\](.*)$/", $filename, $match)) { |
127: | return $match[1]; |
128: | } else { |
129: | return $filename; |
130: | } |
131: | } |
132: | |
133: | |
134: | |
135: | |
136: | |
137: | |
138: | |
139: | |
140: | public static function sanitizeTimestamp($timestamp) |
141: | { |
142: | if (!is_string($timestamp)) return $timestamp; |
143: | |
144: | return preg_replace('/(:\d{2}.\d{6})\d*/', '$1', $timestamp); |
145: | } |
146: | |
147: | |
148: | |
149: | |
150: | |
151: | |
152: | |
153: | |
154: | |
155: | public static function toPathValue($value) |
156: | { |
157: | return rawurlencode(self::toString($value)); |
158: | } |
159: | |
160: | |
161: | |
162: | |
163: | |
164: | |
165: | |
166: | |
167: | |
168: | |
169: | |
170: | |
171: | |
172: | |
173: | public static function toQueryValue( |
174: | $value, |
175: | string $paramName, |
176: | string $openApiType = 'string', |
177: | string $style = 'form', |
178: | bool $explode = true, |
179: | bool $required = true |
180: | ): array { |
181: | if ( |
182: | empty($value) |
183: | && ($value !== false || $openApiType !== 'boolean') |
184: | ) { |
185: | if ($required) { |
186: | return ["{$paramName}" => '']; |
187: | } else { |
188: | return []; |
189: | } |
190: | } |
191: | |
192: | $query = []; |
193: | $value = (in_array($openApiType, ['object', 'array'], true)) ? (array)$value : $value; |
194: | |
195: | |
196: | |
197: | $flattenArray = function ($arr, $name, &$result = []) use (&$flattenArray, $style, $explode) { |
198: | if (!is_array($arr)) return $arr; |
199: | |
200: | foreach ($arr as $k => $v) { |
201: | $prop = ($style === 'deepObject') ? $prop = "{$name}[{$k}]" : $k; |
202: | |
203: | if (is_array($v)) { |
204: | $flattenArray($v, $prop, $result); |
205: | } else { |
206: | if ($style !== 'deepObject' && !$explode) { |
207: | |
208: | $result[] = $prop; |
209: | } |
210: | $result[$prop] = $v; |
211: | } |
212: | } |
213: | return $result; |
214: | }; |
215: | |
216: | $value = $flattenArray($value, $paramName); |
217: | |
218: | if ($openApiType === 'object' && ($style === 'deepObject' || $explode)) { |
219: | return $value; |
220: | } |
221: | |
222: | if ('boolean' === $openApiType && is_bool($value)) { |
223: | $value = self::convertBoolToQueryStringFormat($value); |
224: | } |
225: | |
226: | |
227: | $query[$paramName] = ($explode) ? $value : self::serializeCollection((array)$value, $style); |
228: | |
229: | return $query; |
230: | } |
231: | |
232: | |
233: | |
234: | |
235: | |
236: | |
237: | |
238: | |
239: | public static function convertBoolToQueryStringFormat(bool $value) |
240: | { |
241: | if (Configuration::BOOLEAN_FORMAT_STRING == Configuration::getDefaultConfiguration()->getBooleanFormatForQueryString()) { |
242: | return $value ? 'true' : 'false'; |
243: | } |
244: | |
245: | return (int) $value; |
246: | } |
247: | |
248: | |
249: | |
250: | |
251: | |
252: | |
253: | |
254: | |
255: | |
256: | |
257: | public static function toHeaderValue($value) |
258: | { |
259: | $callable = [$value, 'toHeaderValue']; |
260: | if (is_callable($callable)) { |
261: | return $callable(); |
262: | } |
263: | |
264: | return self::toString($value); |
265: | } |
266: | |
267: | |
268: | |
269: | |
270: | |
271: | |
272: | |
273: | |
274: | |
275: | |
276: | public static function toFormValue($value) |
277: | { |
278: | if ($value instanceof \SplFileObject) { |
279: | return $value->getRealPath(); |
280: | } else { |
281: | return self::toString($value); |
282: | } |
283: | } |
284: | |
285: | |
286: | |
287: | |
288: | |
289: | |
290: | |
291: | |
292: | |
293: | |
294: | |
295: | public static function toString($value) |
296: | { |
297: | if ($value instanceof \DateTime) { |
298: | return $value->format(self::$dateTimeFormat); |
299: | } elseif (is_bool($value)) { |
300: | return $value ? 'true' : 'false'; |
301: | } else { |
302: | return (string) $value; |
303: | } |
304: | } |
305: | |
306: | |
307: | |
308: | |
309: | |
310: | |
311: | |
312: | |
313: | |
314: | |
315: | |
316: | public static function serializeCollection(array $collection, $style, $allowCollectionFormatMulti = false) |
317: | { |
318: | if ($allowCollectionFormatMulti && ('multi' === $style)) { |
319: | |
320: | |
321: | return preg_replace('/%5B[0-9]+%5D=/', '=', http_build_query($collection, '', '&')); |
322: | } |
323: | switch ($style) { |
324: | case 'pipeDelimited': |
325: | case 'pipes': |
326: | return implode('|', $collection); |
327: | |
328: | case 'tsv': |
329: | return implode("\t", $collection); |
330: | |
331: | case 'spaceDelimited': |
332: | case 'ssv': |
333: | return implode(' ', $collection); |
334: | |
335: | case 'simple': |
336: | case 'csv': |
337: | |
338: | default: |
339: | return implode(',', $collection); |
340: | } |
341: | } |
342: | |
343: | |
344: | |
345: | |
346: | |
347: | |
348: | |
349: | |
350: | |
351: | |
352: | |
353: | public static function deserialize($data, $class, $httpHeaders = null) |
354: | { |
355: | if (null === $data) { |
356: | return null; |
357: | } |
358: | |
359: | if (strcasecmp(substr($class, -2), '[]') === 0) { |
360: | $data = is_string($data) ? json_decode($data) : $data; |
361: | |
362: | if (!is_array($data)) { |
363: | throw new \InvalidArgumentException("Invalid array '$class'"); |
364: | } |
365: | |
366: | $subClass = substr($class, 0, -2); |
367: | $values = []; |
368: | foreach ($data as $key => $value) { |
369: | $values[] = self::deserialize($value, $subClass, null); |
370: | } |
371: | return $values; |
372: | } |
373: | |
374: | if (preg_match('/^(array<|map\[)/', $class)) { |
375: | $data = is_string($data) ? json_decode($data) : $data; |
376: | settype($data, 'array'); |
377: | $inner = substr($class, 4, -1); |
378: | $deserialized = []; |
379: | if (strrpos($inner, ",") !== false) { |
380: | $subClass_array = explode(',', $inner, 2); |
381: | $subClass = $subClass_array[1]; |
382: | foreach ($data as $key => $value) { |
383: | $deserialized[$key] = self::deserialize($value, $subClass, null); |
384: | } |
385: | } |
386: | return $deserialized; |
387: | } |
388: | |
389: | if ($class === 'object') { |
390: | settype($data, 'array'); |
391: | return $data; |
392: | } elseif ($class === 'mixed') { |
393: | settype($data, gettype($data)); |
394: | return $data; |
395: | } |
396: | |
397: | if ($class === '\DateTime') { |
398: | |
399: | |
400: | |
401: | |
402: | |
403: | |
404: | if (!empty($data)) { |
405: | try { |
406: | return new \DateTime($data); |
407: | } catch (\Exception $exception) { |
408: | |
409: | |
410: | |
411: | return new \DateTime(self::sanitizeTimestamp($data)); |
412: | } |
413: | } else { |
414: | return null; |
415: | } |
416: | } |
417: | |
418: | if ($class === '\SplFileObject') { |
419: | $data = Utils::streamFor($data); |
420: | |
421: | |
422: | |
423: | |
424: | if ( |
425: | is_array($httpHeaders) |
426: | && array_key_exists('Content-Disposition', $httpHeaders) |
427: | && preg_match('/inline; filename=[\'"]?([^\'"\s]+)[\'"]?$/i', $httpHeaders['Content-Disposition'], $match) |
428: | ) { |
429: | $filename = Configuration::getDefaultConfiguration()->getTempFolderPath() . DIRECTORY_SEPARATOR . self::sanitizeFilename($match[1]); |
430: | } else { |
431: | $filename = tempnam(Configuration::getDefaultConfiguration()->getTempFolderPath(), ''); |
432: | } |
433: | |
434: | $file = fopen($filename, 'w'); |
435: | while ($chunk = $data->read(200)) { |
436: | fwrite($file, $chunk); |
437: | } |
438: | fclose($file); |
439: | |
440: | return new \SplFileObject($filename, 'r'); |
441: | } |
442: | |
443: | |
444: | if (in_array($class, ['\DateTime', '\SplFileObject', 'array', 'bool', 'boolean', 'byte', 'double', 'float', 'int', 'integer', 'mixed', 'number', 'object', 'string', 'void'], true)) { |
445: | settype($data, $class); |
446: | return $data; |
447: | } |
448: | |
449: | |
450: | if (method_exists($class, 'getAllowableEnumValues')) { |
451: | if (!in_array($data, $class::getAllowableEnumValues(), true)) { |
452: | $imploded = implode("', '", $class::getAllowableEnumValues()); |
453: | throw new \InvalidArgumentException("Invalid value for enum '$class', must be one of: '$imploded'"); |
454: | } |
455: | return $data; |
456: | } else { |
457: | $data = is_string($data) ? json_decode($data) : $data; |
458: | |
459: | if (is_array($data)) { |
460: | $data = (object)$data; |
461: | } |
462: | |
463: | |
464: | $discriminator = $class::DISCRIMINATOR; |
465: | if (!empty($discriminator) && isset($data->{$discriminator}) && is_string($data->{$discriminator})) { |
466: | $subclass = '\Ally\PetStore\Model\\' . $data->{$discriminator}; |
467: | if (is_subclass_of($subclass, $class)) { |
468: | $class = $subclass; |
469: | } |
470: | } |
471: | |
472: | |
473: | $instance = new $class(); |
474: | foreach ($instance::openAPITypes() as $property => $type) { |
475: | $propertySetter = $instance::setters()[$property]; |
476: | |
477: | if (!isset($propertySetter)) { |
478: | continue; |
479: | } |
480: | |
481: | if (!isset($data->{$instance::attributeMap()[$property]})) { |
482: | if ($instance::isNullable($property)) { |
483: | $instance->$propertySetter(null); |
484: | } |
485: | |
486: | continue; |
487: | } |
488: | |
489: | if (isset($data->{$instance::attributeMap()[$property]})) { |
490: | $propertyValue = $data->{$instance::attributeMap()[$property]}; |
491: | $instance->$propertySetter(self::deserialize($propertyValue, $type, null)); |
492: | } |
493: | } |
494: | return $instance; |
495: | } |
496: | } |
497: | |
498: | |
499: | |
500: | |
501: | |
502: | |
503: | |
504: | |
505: | |
506: | |
507: | |
508: | |
509: | public static function buildQuery( |
510: | $data, |
511: | string $numeric_prefix = '', |
512: | ?string $arg_separator = null, |
513: | int $encoding_type = \PHP_QUERY_RFC3986 |
514: | ): string { |
515: | return \GuzzleHttp\Psr7\Query::build($data, $encoding_type); |
516: | } |
517: | } |
518: | |