• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tylernathanreed / jira-client-php / 13993845991

21 Mar 2025 02:19PM UTC coverage: 78.648% (+3.1%) from 75.543%
13993845991

push

github

tylernathanreed
~ Fixed several tests

5400 of 6866 relevant lines covered (78.65%)

9.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.86
/src/Deserializer.php
1
<?php
2

3
namespace Jira\Client;
4

5
use DateTimeImmutable;
6
use Jira\Client\Exceptions\DeserializationException;
7
use ReflectionClass;
8
use ReflectionNamedType;
9
use ReflectionProperty;
10

11
class Deserializer
12
{
13
    /**
14
     * @phpstan-template TDto of Dto
15
     * @param ($array is true ? list<array<string,mixed>> : array<string,mixed>) $data
16
     * @param class-string<TDto> $class
17
     * @return ($array is true ? (TDto is PolymorphicDto ? list<Dto> : list<TDto>) : (TDto is PolymorphicDto ? Dto : TDto))
18
     */
19
    public function deserialize(array $data, string $class, bool $array = false)
407✔
20
    {
21
        if ($array) {
407✔
22
            $values = [];
232✔
23

24
            foreach ($data as $value) {
232✔
25
                $values[] = self::deserialize($value, $class);
232✔
26
            }
27

28
            return $values;
232✔
29
        }
30

31
        if (is_subclass_of($class, PolymorphicDto::class)) {
407✔
32
            $class = $class::discriminateFromData($data);
1✔
33
        }
34

35
        return $this->from($class, $data);
407✔
36
    }
37

38
    /**
39
     * @phpstan-template T of Dto
40
     * @param class-string<T> $class
41
     * @param array<string,mixed> $data
42
     * @return T
43
     */
44
    public function from(string $class, array $data): Dto
407✔
45
    {
46
        $reflector = new ReflectionClass($class);
407✔
47

48
        $parameters = $reflector->getConstructor()?->getParameters() ?? [];
407✔
49

50
        $args = [];
407✔
51

52
        foreach ($parameters as $parameter) {
407✔
53
            $name = $parameter->getName();
407✔
54
            $key = str_starts_with($name, '_')
407✔
55
                ? substr($name, 1)
49✔
56
                : $name;
407✔
57

58
            $property = $reflector->getProperty($name);
407✔
59

60
            $value = array_key_exists($key, $data)
407✔
61
                ? $data[$key]
405✔
62
                : (
407✔
63
                    $parameter->isDefaultValueAvailable()
265✔
64
                    ? $parameter->getDefaultValue()
265✔
65
                    : null
265✔
66
                );
407✔
67

68
            $type = $parameter->getType();
407✔
69

70
            if (is_null($value)) {
407✔
71
                $args[] = $value;
265✔
72
            } elseif (is_null($type)) {
405✔
73
                $args[] = $value;
×
74
            } elseif (! $type instanceof ReflectionNamedType) {
405✔
75
                $args[] = $value;
×
76
            } elseif (is_array($value) && empty($value) && $type->allowsNull()) {
405✔
77
                $args[] = null;
47✔
78
            } elseif ($type->getName() === 'array' && is_array($value)) {
405✔
79
                $args[] = $this->fromArray($class, $property, $value);
252✔
80
            } elseif ($type->getName() === DateTimeImmutable::class && is_string($value)) {
395✔
81
                $args[] = new DateTimeImmutable($value);
31✔
82
            } elseif ($type->getName() === DateTimeImmutable::class && is_int($value)) {
395✔
83
                $args[] = (new DateTimeImmutable)->setTimestamp($value);
4✔
84
            } elseif (! $type->isBuiltin() && is_subclass_of($type->getName(), Dto::class) && is_array($value)) {
395✔
85
                // @phpstan-ignore argument.type
86
                $args[] = $this->from($type->getName(), $value);
150✔
87
            } else {
88
                $args[] = $value;
395✔
89
            }
90
        }
91

92
        return $reflector->newInstanceArgs($args);
407✔
93
    }
94

95
    /**
96
     * @param class-string<Dto> $class
97
     * @param array<mixed,mixed> $array
98
     * @return array<mixed,mixed>
99
     */
100
    protected function fromArray(string $class, ReflectionProperty $property, array $array): array
252✔
101
    {
102
        $doc = $property->getDocComment();
252✔
103

104
        if (! $doc) {
252✔
105
            return $array;
×
106
        }
107

108
        $var = preg_match('/@var \??([^ ]+)(?:\n| \*)/', $doc, $matches)
252✔
109
            ? $matches[1]
252✔
110
            : null;
×
111

112
        if (! $var) {
252✔
113
            return $array;
×
114
        }
115

116
        if (str_starts_with($var, 'list')) {
252✔
117
            $type = substr($var, strlen('list<'), -strlen('>'));
228✔
118
        } else {
119
            if (! preg_match('/^array<(?<key>[^>]+), ?(?<type>.+)>$/', $var, $matches)) {
59✔
120
                return $array;
×
121
            }
122

123
            $type = $matches['type'];
59✔
124
        }
125

126
        if ($type === 'mixed' || str_starts_with($type, 'list')) {
252✔
127
            return $array;
24✔
128
        }
129

130
        if (in_array($type, ['int', 'float', 'string', 'boolean', 'bool'])) {
250✔
131
            return array_map(function ($v) use ($type) {
115✔
132
                settype($v, $type);
112✔
133
                return $v;
112✔
134
            }, $array);
115✔
135
        }
136

137
        if (class_exists($subclass = 'Jira\\Client\\Schema\\' . $type) && is_subclass_of($subclass, Dto::class)) {
198✔
138
            // @phpstan-ignore argument.type
139
            return $this->deserialize($array, $subclass, array: true);
198✔
140
        }
141

142
        throw new DeserializationException("Unknown class [{$subclass}] when deserializing [{$class}].");
×
143
    }
144
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc