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

tylernathanreed / jira-client-php / 13900943155

17 Mar 2025 01:41PM UTC coverage: 71.493% (-3.8%) from 75.271%
13900943155

push

github

tylernathanreed
~ Fixed unknown list<string> type

12 of 12 new or added lines in 1 file covered. (100.0%)

313 existing lines in 133 files now uncovered.

4908 of 6865 relevant lines covered (71.49%)

9.06 hits per line

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

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

3
namespace Jira\Client;
4

5
use DateTimeImmutable;
6
use InvalidArgumentException;
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)
392✔
20
    {
21
        if ($array) {
392✔
22
            $values = [];
68✔
23

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

28
            return $values;
68✔
29
        }
30

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

35
        return $this->from($class, $data);
392✔
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
392✔
45
    {
46
        $reflector = new ReflectionClass($class);
392✔
47

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

50
        $args = [];
392✔
51

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

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

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

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

70
            if (is_null($value)) {
392✔
71
                $args[] = $value;
216✔
72
            } elseif (is_null($type)) {
390✔
73
                $args[] = $value;
×
74
            } elseif (! $type instanceof ReflectionNamedType) {
390✔
75
                $args[] = $value;
×
76
            } elseif ($type->getName() === 'array' && is_array($value)) {
390✔
77
                $args[] = $this->fromArray($class, $property, $value);
245✔
78
            } elseif ($type->getName() === DateTimeImmutable::class && is_string($value)) {
344✔
79
                $args[] = new DateTimeImmutable($value);
19✔
80
            } elseif ($type->getName() === DateTimeImmutable::class && is_int($value)) {
344✔
81
                $args[] = (new DateTimeImmutable)->setTimestamp($value);
4✔
82
            } elseif (! $type->isBuiltin() && is_subclass_of($type->getName(), Dto::class) && is_array($value)) {
344✔
83
                // @phpstan-ignore argument.type
84
                $args[] = $this->from($type->getName(), $value);
99✔
85
            } else {
86
                $args[] = $value;
341✔
87
            }
88
        }
89

90
        return $reflector->newInstanceArgs($args);
392✔
91
    }
92

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

102
        if (! $doc) {
245✔
UNCOV
103
            return $array;
×
104
        }
105

106
        $var = preg_match('/@var (.*)\n/', $doc, $matches)
245✔
107
            ? $matches[1]
231✔
108
            : null;
26✔
109

110
        if (! $var) {
245✔
111
            return $array;
26✔
112
        }
113

114
        if (str_starts_with($var, 'list')) {
231✔
115
            $type = substr($var, strlen('list<'), -strlen('>'));
50✔
116
        } else {
117
            if (! preg_match('/^array<(?<key>[^>]+), ?(?<type>.+)>$/', $var, $matches)) {
201✔
118
                return $array;
180✔
119
            }
120

121
            $type = $matches['type'];
36✔
122
        }
123

124
        if ($type === 'mixed' || str_starts_with($type, 'list')) {
80✔
125
            return $array;
11✔
126
        }
127

128
        if (in_array($type, ['int', 'float', 'string', 'boolean'])) {
76✔
129
            return array_map(function ($v) use ($type) {
59✔
130
                settype($v, $type);
58✔
131
                return $v;
58✔
132
            }, $array);
59✔
133
        }
134

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

UNCOV
140
        throw new InvalidArgumentException("Unknown class [{$subclass}] when deserializing [{$class}].");
×
141
    }
142
}
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