Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
50.81% covered (warning)
50.81%
94 / 185
15.38% covered (danger)
15.38%
2 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
ObjectSerializer
50.81% covered (warning)
50.81%
94 / 185
15.38% covered (danger)
15.38%
2 / 13
1632.73
0.00% covered (danger)
0.00%
0 / 1
 setDateTimeFormat
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 sanitizeForSerialization
73.33% covered (warning)
73.33%
22 / 30
0.00% covered (danger)
0.00%
0 / 1
25.85
 sanitizeFilename
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 sanitizeTimestamp
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 toPathValue
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 toQueryValue
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
506
 convertBoolToQueryStringFormat
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 toHeaderValue
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 toString
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
20
 serializeCollection
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
56
 deserialize
65.08% covered (warning)
65.08%
41 / 63
0.00% covered (danger)
0.00%
0 / 1
64.81
 buildQuery
96.43% covered (success)
96.43%
27 / 28
0.00% covered (danger)
0.00%
0 / 1
14
 isEmptyValue
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
90
1<?php
2
3/**
4 * ObjectSerializer.
5 *
6 * @category Class
7 *
8 * @author   OpenAPI Generator team
9 *
10 * @see     https://openapi-generator.tech
11 */
12
13/**
14 * Server API.
15 *
16 * Fingerprint Server API allows you to get, search, and update Events in a server environment. It can be used for data exports, decision-making, and data analysis scenarios. Server API is intended for server-side usage, it's not intended to be used from the client side, whether it's a browser or a mobile device.
17 *
18 * The version of the OpenAPI document: 4
19 * Contact: support@fingerprint.com
20 * Generated by: https://openapi-generator.tech
21 * Generator version: 7.21.0
22 */
23
24/**
25 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
26 * https://openapi-generator.tech
27 * Do not edit the class manually.
28 */
29
30namespace Fingerprint\ServerSdk;
31
32use Fingerprint\ServerSdk\Model\ModelInterface;
33
34/**
35 * ObjectSerializer Class Doc Comment.
36 *
37 * @category Class
38 *
39 * @author   OpenAPI Generator team
40 *
41 * @see     https://openapi-generator.tech
42 */
43class ObjectSerializer
44{
45    private static string $dateTimeFormat = \DateTimeInterface::ATOM;
46
47    /**
48     * Change the date format.
49     *
50     * @param string $format the new date format to use
51     */
52    public static function setDateTimeFormat(string $format): void
53    {
54        self::$dateTimeFormat = $format;
55    }
56
57    /**
58     * Serialize data.
59     *
60     * @param mixed       $data   the data to serialize
61     * @param string|null $format the format of the OpenAPITools type of the data
62     *
63     * @return scalar|object|array|null serialized form of $data
64     */
65    public static function sanitizeForSerialization(mixed $data, ?string $format = null): mixed
66    {
67        if (is_scalar($data) || null === $data) {
68            return $data;
69        }
70
71        if ($data instanceof \DateTime) {
72            return ('date' === $format) ? $data->format('Y-m-d') : $data->format(self::$dateTimeFormat);
73        }
74
75        if (is_array($data)) {
76            foreach ($data as $property => $value) {
77                $data[$property] = self::sanitizeForSerialization($value);
78            }
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 instanceof \BackedEnum) {
91                        $value = $value->value;
92                    } elseif (null !== $value && !in_array($openAPIType, ['\DateTime', '\SplFileObject', 'array', 'bool', 'boolean', 'byte', 'float', 'int', 'integer', 'mixed', 'number', 'object', 'string', 'void'], true)) {
93                        $callable = [$openAPIType, 'getAllowableEnumValues'];
94                        if (is_callable($callable)) {
95                            /** array $callable */
96                            $allowedEnumTypes = $callable();
97                            if (!in_array($value, $allowedEnumTypes, true)) {
98                                $imploded = implode("', '", $allowedEnumTypes);
99
100                                throw new \InvalidArgumentException("Invalid value for enum '$openAPIType', must be one of: '$imploded'");
101                            }
102                        }
103                    }
104                    if (($data::isNullable($property) && $data->isNullableSetToNull($property)) || null !== $value) {
105                        $values[$data::attributeMap()[$property]] = self::sanitizeForSerialization($value, $formats[$property]);
106                    }
107                }
108            } else {
109                foreach ($data as $property => $value) {
110                    $values[$property] = self::sanitizeForSerialization($value);
111                }
112            }
113
114            return (object) $values;
115        }
116
117        return (string) $data;
118    }
119
120    /**
121     * Sanitize filename by removing path.
122     * e.g. ../../sun.gif becomes sun.gif.
123     *
124     * @param string $filename filename to be sanitized
125     *
126     * @return string the sanitized filename
127     */
128    public static function sanitizeFilename(string $filename): string
129    {
130        if (preg_match('/.*[\/\\\](.*)$/', $filename, $match)) {
131            return $match[1];
132        }
133
134        return $filename;
135    }
136
137    /**
138     * Shorter timestamp microseconds to 6 digits length.
139     *
140     * @param string $timestamp Original timestamp
141     *
142     * @return string the shorten timestamp
143     */
144    public static function sanitizeTimestamp(string $timestamp): string
145    {
146        return preg_replace('/(:\d{2}.\d{6})\d*/', '$1', $timestamp);
147    }
148
149    /**
150     * Take value and turn it into a string suitable for inclusion in
151     * the path, by url-encoding.
152     *
153     * @param string $value a string which will be part of the path
154     *
155     * @return string the serialized object
156     */
157    public static function toPathValue(string $value): string
158    {
159        return rawurlencode(self::toString($value));
160    }
161
162    /**
163     * Take query parameter properties and turn it into an array suitable for
164     * native http_build_query or GuzzleHttp\Psr7\Query::build.
165     *
166     * @param mixed  $value       Parameter value
167     * @param string $paramName   Parameter name
168     * @param string $openApiType OpenAPIType eg. array or object
169     * @param string $style       Parameter serialization style
170     * @param bool   $explode     Parameter explode option
171     * @param bool   $required    Whether query param is required or not
172     *
173     */
174    public static function toQueryValue(
175        mixed $value,
176        string $paramName,
177        string $openApiType = 'string',
178        string $style = 'form',
179        bool $explode = true,
180        bool $required = true
181    ): array {
182        # Check if we should omit this parameter from the query. This should only happen when:
183        #  - Parameter is NOT required; AND
184        #  - its value is set to a value that is equivalent to "empty", depending on its OpenAPI type. For
185        #    example, 0 as "int" or "boolean" is NOT an empty value.
186        if (self::isEmptyValue($value, $openApiType)) {
187            if ($required) {
188                return ["$paramName" => ''];
189            }
190
191            return [];
192        }
193
194        # Handle DateTime objects in query
195        if ('\DateTime' === $openApiType && $value instanceof \DateTime) {
196            return ["$paramName" => $value->format(self::$dateTimeFormat)];
197        }
198
199        # Handle BackedEnum objects in query
200        if ($value instanceof \BackedEnum) {
201            return ["$paramName" => (string) $value->value];
202        }
203
204        $query = [];
205        $value = (in_array($openApiType, ['object', 'array'], true)) ? (array) $value : $value;
206
207        // since \GuzzleHttp\Psr7\Query::build fails with nested arrays
208        // need to flatten array first
209        $flattenArray = function ($arr, $name, &$result = []) use (&$flattenArray, $style, $explode) {
210            if (!is_array($arr)) {
211                return $arr;
212            }
213
214            foreach ($arr as $k => $v) {
215                $prop = ('deepObject' === $style) ? "{$name}[$k]" : $k;
216
217                if (is_array($v)) {
218                    $flattenArray($v, $prop, $result);
219                } else {
220                    if ('deepObject' !== $style && !$explode) {
221                        // push key itself
222                        $result[] = $prop;
223                    }
224                    $result[$prop] = $v;
225                }
226            }
227
228            return $result;
229        };
230
231        $value = $flattenArray($value, $paramName);
232
233        // https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#style-values
234        if ('array' === $openApiType && 'deepObject' === $style && $explode) {
235            return $value;
236        }
237
238        if ('object' === $openApiType && ('deepObject' === $style || $explode)) {
239            return $value;
240        }
241
242        if ('boolean' === $openApiType && is_bool($value)) {
243            $value = self::convertBoolToQueryStringFormat($value);
244        }
245
246        // handle style in serializeCollection
247        $query[$paramName] = ($explode) ? $value : self::serializeCollection((array) $value, $style);
248
249        return $query;
250    }
251
252    /**
253     * Convert boolean value to format for query string.
254     *
255     * @param bool $value Boolean value
256     *
257     * @return string Boolean value
258     */
259    public static function convertBoolToQueryStringFormat(bool $value): string
260    {
261        return $value ? 'true' : 'false';
262    }
263
264    /**
265     * Take value and turn it into a string suitable for inclusion in
266     * the header. If it's a string, pass through unchanged
267     * If it's a datetime object, format it in ISO8601.
268     *
269     * @param mixed $value an object which will be part of the header
270     *
271     * @return string the header string
272     */
273    public static function toHeaderValue(mixed $value): string
274    {
275        $callable = [$value, 'toHeaderValue'];
276        if (is_callable($callable)) {
277            return $callable();
278        }
279
280        return self::toString($value);
281    }
282
283    /**
284     * Take value and turn it into a string suitable for inclusion in
285     * the parameter. If it's a string, pass through unchanged
286     * If it's a datetime object, format it in ISO8601
287     * If it's a boolean, convert it to "true" or "false".
288     *
289     * @param float|int|bool|\DateTime $value the value of the parameter
290     *
291     * @return string the header string
292     */
293    public static function toString(mixed $value): string
294    {
295        if ($value instanceof \DateTime) { // datetime in ISO8601 format
296            return $value->format(self::$dateTimeFormat);
297        }
298        if (is_bool($value)) {
299            return $value ? 'true' : 'false';
300        }
301
302        return (string) $value;
303    }
304
305    /**
306     * Serialize an array to a string.
307     *
308     * @param array  $collection                 collection to serialize to a string
309     * @param string $style                      the format use for serialization (csv,
310     *                                           ssv, tsv, pipes, multi)
311     * @param bool   $allowCollectionFormatMulti allow collection format to be a multidimensional array
312     *
313     */
314    public static function serializeCollection(array $collection, string $style, bool $allowCollectionFormatMulti = false): string
315    {
316        if ($allowCollectionFormatMulti && ('multi' === $style)) {
317            // http_build_query() almost does the job for us. We just
318            // need to fix the result of multidimensional arrays.
319            return preg_replace('/%5B[0-9]+%5D=/', '=', http_build_query($collection, '', '&'));
320        }
321
322        return match ($style) {
323            'pipeDelimited', 'pipes' => implode('|', $collection),
324            'tsv' => implode("\t", $collection),
325            'spaceDelimited', 'ssv' => implode(' ', $collection),
326            default => implode(',', $collection),
327        };
328    }
329
330    /**
331     * Deserialize a JSON string into an object.
332     *
333     * @param mixed  $data  object or primitive to be deserialized
334     * @param string $class class name is passed as a string
335     *
336     * @return object|array|null a single or an array of $class instances
337     *
338     * @throws \DateMalformedStringException
339     */
340    public static function deserialize(mixed $data, string $class): mixed
341    {
342        if (null === $data) {
343            return null;
344        }
345
346        if (0 === strcasecmp(substr($class, -2), '[]')) {
347            $data = is_string($data) ? json_decode($data) : $data;
348
349            if (!is_array($data)) {
350                throw new \InvalidArgumentException("Invalid array '$class'");
351            }
352
353            $subClass = substr($class, 0, -2);
354            $values = [];
355            foreach ($data as $value) {
356                $values[] = self::deserialize($value, $subClass);
357            }
358
359            return $values;
360        }
361
362        if (preg_match('/^(array<|map\[)/', $class)) { // for associative array e.g. array<string,int>
363            $data = is_string($data) ? json_decode($data) : $data;
364            settype($data, 'array');
365            $inner = substr($class, 4, -1);
366            $deserialized = [];
367            if (false !== strrpos($inner, ',')) {
368                $subClass_array = explode(',', $inner, 2);
369                $subClass = $subClass_array[1];
370                foreach ($data as $key => $value) {
371                    $deserialized[$key] = self::deserialize($value, $subClass);
372                }
373            }
374
375            return $deserialized;
376        }
377
378        if ('object' === $class) {
379            settype($data, 'array');
380
381            return $data;
382        }
383        if ('mixed' === $class) {
384            settype($data, gettype($data));
385
386            return $data;
387        }
388
389        if ('\DateTime' === $class) {
390            // Some APIs return an invalid, empty string as a
391            // date-time property. DateTime::__construct() will return
392            // the current time for empty input which is probably not
393            // what is meant. The invalid empty string is probably to
394            // be interpreted as a missing field/value. Let's handle
395            // this graceful.
396            if (!empty($data)) {
397                try {
398                    return new \DateTime($data);
399                } catch (\Exception) {
400                    // Some APIs return a date-time with too high nanosecond
401                    // precision for php's DateTime to handle.
402                    // With provided regexp 6 digits of microseconds saved
403                    return new \DateTime(self::sanitizeTimestamp($data));
404                }
405            } else {
406                return null;
407            }
408        }
409
410        /* @psalm-suppress ParadoxicalCondition */
411        if (in_array($class, ['\DateTime', '\SplFileObject', 'array', 'bool', 'boolean', 'byte', 'float', 'int', 'integer', 'mixed', 'number', 'object', 'string', 'void'], true)) {
412            settype($data, $class);
413
414            return $data;
415        }
416
417        if (enum_exists($class)) {
418            /* @var \BackedEnum $class */
419            try {
420                return $class::from($data);
421            } catch (\ValueError $e) {
422                $allowedValues = array_map(fn ($case) => $case->value, $class::cases());
423                $imploded = implode("', '", $allowedValues);
424
425                throw new \InvalidArgumentException("Invalid value for enum '$class', must be one of: '$imploded'", previous: $e);
426            }
427        }
428
429        $data = is_string($data) ? json_decode($data) : $data;
430
431        if (is_array($data)) {
432            $data = (object) $data;
433        }
434
435        // If a discriminator is defined and points to a valid subclass, use it.
436        $discriminator = defined("$class::DISCRIMINATOR") ? $class::DISCRIMINATOR : null;
437        if (!empty($discriminator) && isset($data->{$discriminator}) && is_string($data->{$discriminator})) {
438            $subclass = '\Fingerprint\ServerSdk\Model\\'.$data->{$discriminator};
439            if (is_subclass_of($subclass, $class)) {
440                $class = $subclass;
441            }
442        }
443
444        /** @var ModelInterface $instance */
445        $instance = new $class();
446        foreach ($instance::openAPITypes() as $property => $type) {
447            $propertySetter = $instance::setters()[$property];
448
449            if (!isset($propertySetter)) {
450                continue;
451            }
452
453            if (!isset($data->{$instance::attributeMap()[$property]})) {
454                if ($instance::isNullable($property)) {
455                    $instance->{$propertySetter}(null);
456                }
457
458                continue;
459            }
460
461            $propertyValue = $data->{$instance::attributeMap()[$property]};
462            $instance->{$propertySetter}(self::deserialize($propertyValue, $type));
463        }
464
465        return $instance;
466    }
467
468    /**
469     * Build a query string from an array of key value pairs.
470     *
471     * This function can use the return value of `parse()` to build a query
472     * string. This function does not modify the provided keys when an array is
473     * encountered (like `http_build_query()` would).
474     *
475     * The function is copied from https://github.com/guzzle/psr7/blob/a243f80a1ca7fe8ceed4deee17f12c1930efe662/src/Query.php#L59-L112
476     * with a modification which is described in https://github.com/guzzle/psr7/pull/603
477     *
478     * @param array     $params   query string parameters
479     * @param int|false $encoding set false to not encode, PHP_QUERY_RFC3986
480     *                            to encode using RFC3986, or PHP_QUERY_RFC1738
481     *                            to encode using RFC1738
482     */
483    public static function buildQuery(array $params, bool|int $encoding = PHP_QUERY_RFC3986): string
484    {
485        if (!$params) {
486            return '';
487        }
488
489        if (false === $encoding) {
490            $encoder = function (string $str): string {
491                return $str;
492            };
493        } elseif (PHP_QUERY_RFC3986 === $encoding) {
494            $encoder = 'rawurlencode';
495        } elseif (PHP_QUERY_RFC1738 === $encoding) {
496            $encoder = 'urlencode';
497        } else {
498            throw new \InvalidArgumentException('Invalid type');
499        }
500
501        $castBool = function ($v) { return $v ? 'true' : 'false'; };
502
503        $qs = '';
504        foreach ($params as $k => $v) {
505            $k = $encoder((string) $k);
506            if (!is_array($v)) {
507                $qs .= $k;
508                $v = is_bool($v) ? $castBool($v) : $v;
509                if (null !== $v) {
510                    $qs .= '='.$encoder((string) $v);
511                }
512                $qs .= '&';
513            } else {
514                foreach ($v as $vv) {
515                    $qs .= $k;
516                    $vv = is_bool($vv) ? $castBool($vv) : $vv;
517                    if (null !== $vv) {
518                        $qs .= '='.$encoder((string) $vv);
519                    }
520                    $qs .= '&';
521                }
522            }
523        }
524
525        return $qs ? substr($qs, 0, -1) : '';
526    }
527
528    /**
529     * Checks if a value is empty, based on its OpenAPI type.
530     *
531     * @return bool true if $value is empty
532     */
533    private static function isEmptyValue(mixed $value, string $openApiType): bool
534    {
535        # If empty() returns false, it is not empty regardless of its type.
536        if (!empty($value)) {
537            return false;
538        }
539
540        # Null is always empty, as we cannot send a real "null" value in a query parameter.
541        if (null === $value) {
542            return true;
543        }
544
545        return match ($openApiType) {
546            # For numeric values, false and '' are considered empty.
547            # This comparison is safe for floating point values, since the previous call to empty() will
548            # filter out values that don't match 0.
549            'int', 'integer' => 0 !== $value,
550            'number', 'float' => 0 !== $value && 0.0 !== $value,
551            # For boolean values, '' is considered empty
552            'bool', 'boolean' => !in_array($value, [false, 0], true),
553            # For string values, '' is considered empty.
554            'string' => '' === $value,
555            # For all the other types, any value at this point can be considered empty.
556            default => true,
557        };
558    }
559}