Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
65.46% covered (warning)
65.46%
127 / 194
15.38% covered (danger)
15.38%
2 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
ObjectSerializer
65.46% covered (warning)
65.46%
127 / 194
15.38% covered (danger)
15.38%
2 / 13
691.57
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
61.76% covered (warning)
61.76%
21 / 34
0.00% covered (danger)
0.00%
0 / 1
59.94
 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.88% covered (success)
96.88%
31 / 32
0.00% covered (danger)
0.00%
0 / 1
16
 isEmptyValue
72.73% covered (warning)
72.73%
8 / 11
0.00% covered (danger)
0.00%
0 / 1
10.64
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::RFC3339_EXTENDED;
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 int and DateTime union in query
195        if ('int|\DateTime' === $openApiType || '\DateTime|int' === $openApiType) {
196            if ($value instanceof \DateTime) {
197                return ["$paramName" => $value->format(self::$dateTimeFormat)];
198            }
199        }
200
201        # Handle DateTime objects in query
202        if ('\DateTime' === $openApiType && $value instanceof \DateTime) {
203            return ["$paramName" => $value->format(self::$dateTimeFormat)];
204        }
205
206        # Handle BackedEnum objects in query
207        if ($value instanceof \BackedEnum) {
208            return ["$paramName" => (string) $value->value];
209        }
210
211        $query = [];
212        $value = (in_array($openApiType, ['object', 'array'], true)) ? (array) $value : $value;
213
214        // since \GuzzleHttp\Psr7\Query::build fails with nested arrays
215        // need to flatten array first
216        $flattenArray = function ($arr, $name, &$result = []) use (&$flattenArray, $style, $explode) {
217            if (!is_array($arr)) {
218                return $arr;
219            }
220
221            foreach ($arr as $k => $v) {
222                $prop = ('deepObject' === $style) ? "{$name}[$k]" : $k;
223
224                if (is_array($v)) {
225                    $flattenArray($v, $prop, $result);
226                } else {
227                    if ('deepObject' !== $style && !$explode) {
228                        // push key itself
229                        $result[] = $prop;
230                    }
231                    $result[$prop] = $v;
232                }
233            }
234
235            return $result;
236        };
237
238        $value = $flattenArray($value, $paramName);
239
240        // https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#style-values
241        if ('array' === $openApiType && 'deepObject' === $style && $explode) {
242            return $value;
243        }
244
245        if ('object' === $openApiType && ('deepObject' === $style || $explode)) {
246            return $value;
247        }
248
249        if ('boolean' === $openApiType && is_bool($value)) {
250            $value = self::convertBoolToQueryStringFormat($value);
251        }
252
253        // handle style in serializeCollection
254        $query[$paramName] = ($explode) ? $value : self::serializeCollection((array) $value, $style);
255
256        return $query;
257    }
258
259    /**
260     * Convert boolean value to format for query string.
261     *
262     * @param bool $value Boolean value
263     *
264     * @return string Boolean value
265     */
266    public static function convertBoolToQueryStringFormat(bool $value): string
267    {
268        return $value ? 'true' : 'false';
269    }
270
271    /**
272     * Take value and turn it into a string suitable for inclusion in
273     * the header. If it's a string, pass through unchanged
274     * If it's a datetime object, format it in ISO8601.
275     *
276     * @param mixed $value an object which will be part of the header
277     *
278     * @return string the header string
279     */
280    public static function toHeaderValue(mixed $value): string
281    {
282        $callable = [$value, 'toHeaderValue'];
283        if (is_callable($callable)) {
284            return $callable();
285        }
286
287        return self::toString($value);
288    }
289
290    /**
291     * Take value and turn it into a string suitable for inclusion in
292     * the parameter. If it's a string, pass through unchanged
293     * If it's a datetime object, format it in ISO8601
294     * If it's a boolean, convert it to "true" or "false".
295     *
296     * @param float|int|bool|\DateTime $value the value of the parameter
297     *
298     * @return string the header string
299     */
300    public static function toString(mixed $value): string
301    {
302        if ($value instanceof \DateTime) { // datetime in ISO8601 format
303            return $value->format(self::$dateTimeFormat);
304        }
305        if (is_bool($value)) {
306            return $value ? 'true' : 'false';
307        }
308
309        return (string) $value;
310    }
311
312    /**
313     * Serialize an array to a string.
314     *
315     * @param array  $collection                 collection to serialize to a string
316     * @param string $style                      the format use for serialization (csv,
317     *                                           ssv, tsv, pipes, multi)
318     * @param bool   $allowCollectionFormatMulti allow collection format to be a multidimensional array
319     *
320     */
321    public static function serializeCollection(array $collection, string $style, bool $allowCollectionFormatMulti = false): string
322    {
323        if ($allowCollectionFormatMulti && ('multi' === $style)) {
324            // http_build_query() almost does the job for us. We just
325            // need to fix the result of multidimensional arrays.
326            return preg_replace('/%5B[0-9]+%5D=/', '=', http_build_query($collection, '', '&'));
327        }
328
329        return match ($style) {
330            'pipeDelimited', 'pipes' => implode('|', $collection),
331            'tsv' => implode("\t", $collection),
332            'spaceDelimited', 'ssv' => implode(' ', $collection),
333            default => implode(',', $collection),
334        };
335    }
336
337    /**
338     * Deserialize a JSON string into an object.
339     *
340     * @param mixed  $data  object or primitive to be deserialized
341     * @param string $class class name is passed as a string
342     *
343     * @return object|array|null a single or an array of $class instances
344     *
345     * @throws \DateMalformedStringException
346     */
347    public static function deserialize(mixed $data, string $class): mixed
348    {
349        if (null === $data) {
350            return null;
351        }
352
353        if (0 === strcasecmp(substr($class, -2), '[]')) {
354            $data = is_string($data) ? json_decode($data) : $data;
355
356            if (!is_array($data)) {
357                throw new \InvalidArgumentException("Invalid array '$class'");
358            }
359
360            $subClass = substr($class, 0, -2);
361            $values = [];
362            foreach ($data as $value) {
363                $values[] = self::deserialize($value, $subClass);
364            }
365
366            return $values;
367        }
368
369        if (preg_match('/^(array<|map\[)/', $class)) { // for associative array e.g. array<string,int>
370            $data = is_string($data) ? json_decode($data) : $data;
371            settype($data, 'array');
372            $inner = substr($class, 4, -1);
373            $deserialized = [];
374            if (false !== strrpos($inner, ',')) {
375                $subClass_array = explode(',', $inner, 2);
376                $subClass = $subClass_array[1];
377                foreach ($data as $key => $value) {
378                    $deserialized[$key] = self::deserialize($value, $subClass);
379                }
380            }
381
382            return $deserialized;
383        }
384
385        if ('object' === $class) {
386            settype($data, 'array');
387
388            return $data;
389        }
390        if ('mixed' === $class) {
391            settype($data, gettype($data));
392
393            return $data;
394        }
395
396        if ('\DateTime' === $class) {
397            // Some APIs return an invalid, empty string as a
398            // date-time property. DateTime::__construct() will return
399            // the current time for empty input which is probably not
400            // what is meant. The invalid empty string is probably to
401            // be interpreted as a missing field/value. Let's handle
402            // this graceful.
403            if (!empty($data)) {
404                try {
405                    return new \DateTime($data);
406                } catch (\Exception) {
407                    // Some APIs return a date-time with too high nanosecond
408                    // precision for php's DateTime to handle.
409                    // With provided regexp 6 digits of microseconds saved
410                    return new \DateTime(self::sanitizeTimestamp($data));
411                }
412            } else {
413                return null;
414            }
415        }
416
417        /* @psalm-suppress ParadoxicalCondition */
418        if (in_array($class, ['\DateTime', '\SplFileObject', 'array', 'bool', 'boolean', 'byte', 'float', 'int', 'integer', 'mixed', 'number', 'object', 'string', 'void'], true)) {
419            settype($data, $class);
420
421            return $data;
422        }
423
424        if (enum_exists($class)) {
425            /* @var \BackedEnum $class */
426            try {
427                return $class::from($data);
428            } catch (\ValueError $e) {
429                $allowedValues = array_map(fn ($case) => $case->value, $class::cases());
430                $imploded = implode("', '", $allowedValues);
431
432                throw new \InvalidArgumentException("Invalid value for enum '$class', must be one of: '$imploded'", previous: $e);
433            }
434        }
435
436        $data = is_string($data) ? json_decode($data) : $data;
437
438        if (is_array($data)) {
439            $data = (object) $data;
440        }
441
442        // If a discriminator is defined and points to a valid subclass, use it.
443        $discriminator = defined("$class::DISCRIMINATOR") ? $class::DISCRIMINATOR : null;
444        if (!empty($discriminator) && isset($data->{$discriminator}) && is_string($data->{$discriminator})) {
445            $subclass = '\Fingerprint\ServerSdk\Model\\'.$data->{$discriminator};
446            if (is_subclass_of($subclass, $class)) {
447                $class = $subclass;
448            }
449        }
450
451        /** @var ModelInterface $instance */
452        $instance = new $class();
453        foreach ($instance::openAPITypes() as $property => $type) {
454            $propertySetter = $instance::setters()[$property];
455
456            if (!isset($propertySetter)) {
457                continue;
458            }
459
460            if (!isset($data->{$instance::attributeMap()[$property]})) {
461                if ($instance::isNullable($property)) {
462                    $instance->{$propertySetter}(null);
463                }
464
465                continue;
466            }
467
468            $propertyValue = $data->{$instance::attributeMap()[$property]};
469            $instance->{$propertySetter}(self::deserialize($propertyValue, $type));
470        }
471
472        return $instance;
473    }
474
475    /**
476     * Build a query string from an array of key value pairs.
477     *
478     * This function can use the return value of `parse()` to build a query
479     * string. This function does not modify the provided keys when an array is
480     * encountered (like `http_build_query()` would).
481     *
482     * The function is copied from https://github.com/guzzle/psr7/blob/a243f80a1ca7fe8ceed4deee17f12c1930efe662/src/Query.php#L59-L112
483     * with a modification which is described in https://github.com/guzzle/psr7/pull/603
484     *
485     * @param array     $params   query string parameters
486     * @param int|false $encoding set false to not encode, PHP_QUERY_RFC3986
487     *                            to encode using RFC3986, or PHP_QUERY_RFC1738
488     *                            to encode using RFC1738
489     */
490    public static function buildQuery(array $params, bool|int $encoding = PHP_QUERY_RFC3986): string
491    {
492        if (!$params) {
493            return '';
494        }
495
496        if (false === $encoding) {
497            $encoder = function (string $str): string {
498                return $str;
499            };
500        } elseif (PHP_QUERY_RFC3986 === $encoding) {
501            $encoder = 'rawurlencode';
502        } elseif (PHP_QUERY_RFC1738 === $encoding) {
503            $encoder = 'urlencode';
504        } else {
505            throw new \InvalidArgumentException('Invalid type');
506        }
507
508        $castBool = function ($v) { return $v ? 'true' : 'false'; };
509
510        $qs = '';
511        foreach ($params as $k => $v) {
512            $k = $encoder((string) $k);
513            if (!is_array($v)) {
514                $qs .= $k;
515                $v = is_bool($v) ? $castBool($v) : $v;
516                if ($v instanceof \BackedEnum) {
517                    $v = $v->value;
518                }
519                if (null !== $v) {
520                    $qs .= '='.$encoder((string) $v);
521                }
522                $qs .= '&';
523            } else {
524                foreach ($v as $vv) {
525                    $qs .= $k;
526                    $vv = is_bool($vv) ? $castBool($vv) : $vv;
527                    if ($vv instanceof \BackedEnum) {
528                        $vv = $vv->value;
529                    }
530                    if (null !== $vv) {
531                        $qs .= '='.$encoder((string) $vv);
532                    }
533                    $qs .= '&';
534                }
535            }
536        }
537
538        return $qs ? substr($qs, 0, -1) : '';
539    }
540
541    /**
542     * Checks if a value is empty, based on its OpenAPI type.
543     *
544     * @return bool true if $value is empty
545     */
546    private static function isEmptyValue(mixed $value, string $openApiType): bool
547    {
548        # If empty() returns false, it is not empty regardless of its type.
549        if (!empty($value)) {
550            return false;
551        }
552
553        # Null is always empty, as we cannot send a real "null" value in a query parameter.
554        if (null === $value) {
555            return true;
556        }
557
558        return match ($openApiType) {
559            # For numeric values, false and '' are considered empty.
560            # This comparison is safe for floating point values, since the previous call to empty() will
561            # filter out values that don't match 0.
562            'int', 'integer', 'int|\DateTime', '\DateTime|int' => 0 !== $value,
563            'number', 'float' => 0 !== $value && 0.0 !== $value,
564            # For boolean values, '' is considered empty
565            'bool', 'boolean' => !in_array($value, [false, 0], true),
566            # For string values, '' is considered empty.
567            'string' => '' === $value,
568            # For all the other types, any value at this point can be considered empty.
569            default => true,
570        };
571    }
572}