Type::convert()   B
last analyzed

Complexity

Conditions 8
Paths 8

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 8.013

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 17
c 1
b 0
f 0
nc 8
nop 1
dl 0
loc 26
ccs 16
cts 17
cp 0.9412
crap 8.013
rs 8.4444
1
<?php
2
3
namespace Bdf\Serializer\Type;
4
5
/**
6
 * Type
7
 *
8
 * @template T
9
 */
10
final class Type
11
{
12
    public const STRING = 'string';
13
    public const BOOLEAN = 'boolean';
14
    public const INTEGER = 'integer';
15
    public const FLOAT = 'float';
16
    public const DOUBLE = 'double';
17
    public const TARRAY = 'array';
18
    public const TNULL = 'null';
19
    public const MIXED = 'mixed';
20
21
    /**
22
     * @var class-string<T>|Type::*
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T>|Type:: at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>|Type::.
Loading history...
23
     */
24
    private $name;
25
26
    /**
27
     * @var boolean
28
     */
29
    private $isBuildin;
30
31
    /**
32
     * @var boolean
33
     */
34
    private $isArray;
35
36
    /**
37
     * @var Type|null
38
     */
39
    private $subType;
40
41
    /**
42
     * @var T|null
43
     */
44
    private $target;
45
46
    /**
47
     * Type constructor.
48
     *
49
     * @param class-string<T>|Type::* $name
0 ignored issues
show
Documentation Bug introduced by
The doc comment $name at position 0 could not be parsed: Unknown type name '$name' at position 0 in $name.
Loading history...
50
     * @param bool $isBuildin
51
     * @param bool $isArray
52
     * @param Type|null $subType
53
     * @param T|null $target
54
     */
55 354
    public function __construct(string $name, bool $isBuildin, bool $isArray = false, Type $subType = null, $target = null)
56
    {
57
        /** @psalm-suppress PropertyTypeCoercion */
58 354
        $this->name = $name;
59 354
        $this->isArray = $isArray;
60 354
        $this->subType = $subType;
61 354
        $this->isBuildin = $isBuildin;
62 354
        $this->target = $target;
63
    }
64
65
    /**
66
     * Returns the type name
67
     *
68
     * @return (T is object ? class-string<T> : Type::*)
0 ignored issues
show
Documentation Bug introduced by
The doc comment (T at position 1 could not be parsed: Expected ')' at position 1, but found 'T'.
Loading history...
69
     */
70 158
    public function name(): string
71
    {
72 158
        return $this->name;
73
    }
74
75
    /**
76
     * Check if the type is an array
77
     *
78
     * @return bool
79
     */
80 118
    public function isArray(): bool
81
    {
82 118
        return $this->isArray;
83
    }
84
85
    /**
86
     * Get the sub type (ex: Type<SubType> will return SubType)
87
     *
88
     * @return Type
89
     */
90 62
    public function subType(): ?Type
91
    {
92 62
        return $this->subType;
93
    }
94
95
    /**
96
     * Check if the current type is parametrized (i.e. Has a sub type)
97
     *
98
     * @return bool
99
     * @psalm-assert-if-true !null $this->subType()
100
     */
101 8
    public function isParametrized(): bool
102
    {
103 8
        return $this->subType !== null;
104
    }
105
106
    /**
107
     * Is a build in php type
108
     *
109
     * @return boolean
110
     */
111 106
    public function isBuildin(): bool
112
    {
113 106
        return $this->isBuildin;
114
    }
115
116
    /**
117
     * Get the target object of the type
118
     *
119
     * @return null|T
120
     */
121 78
    public function target()
122
    {
123 78
        return $this->target;
124
    }
125
126
    /**
127
     * Set the target
128
     *
129
     * @param T|null $target
130
     */
131 66
    public function setTarget($target): void
132
    {
133 66
        $this->target = $target;
134
    }
135
136
    /**
137
     * Check whether the type is mixed
138
     *
139
     * @return boolean
140
     */
141 90
    public function isMixed(): bool
142
    {
143 90
        return $this->name === self::MIXED;
144
    }
145
146
    /**
147
     * Add a hint on type from the value
148
     * Allowed the type to guess what is the real type to manage.
149
     *
150
     * Note: The current type instance is never modified by this method
151
     *
152
     * @param mixed &$value in/out parameter for the value. If a metadata type "@type" is found, the real data is set
153
     *
154
     * @return Type<T> The new type corresponding to the given value
155
     */
156 94
    public function hint(&$value): Type
157
    {
158 94
        if (isset($value['@type'])) {
159 14
            $type = TypeFactory::createType($value['@type']);
160
            // We change the type and keep the target.
161 14
            $type->target = $this->target;
162
163 14
            $value = $value['data'];
164
165 14
            return $type;
166
        }
167
168
        // The mixed type is a builtin type. We just need to manage array value.
169
        // We don't change the name of the mixed type because it is not fixed
170
        // and it will need to guess the next value in array case
171
        // We also clone the type to ensure that it'll not be modified later and cause side effects (http://redmine.b2pweb.com/issues/17469)
172 90
        if ($this->isMixed() === true) {
173 34
            $type = clone $this;
174
175 34
            if (is_array($value)) {
176 16
                $type->isArray = true;
177 16
                $type->subType = TypeFactory::mixedType();
178
            } else {
179 32
                $type->isArray = false;
180 32
                $type->subType = null;
181
            }
182
183 34
            return $type;
184
        }
185
186 80
        return $this;
187
    }
188
189
    /**
190
     * Convert the builtin value to the corresponding native type
191
     *
192
     * @param mixed $value
193
     *
194
     * @return T Native value type
195
     * @psalm-suppress InvalidReturnStatement
196
     */
197 78
    public function convert($value)
198
    {
199 78
        switch ($this->name) {
200 78
            case self::INTEGER:
201 28
                return (int) $value;
0 ignored issues
show
Bug Best Practice introduced by
The expression return (int)$value returns the type integer which is incompatible with the documented return type Bdf\Serializer\Type\T.
Loading history...
202
203 74
            case self::FLOAT:
204 2
                return (float) $value;
0 ignored issues
show
Bug Best Practice introduced by
The expression return (double)$value returns the type double which is incompatible with the documented return type Bdf\Serializer\Type\T.
Loading history...
205
206 72
            case self::DOUBLE:
207
                return (float) $value;
0 ignored issues
show
Bug Best Practice introduced by
The expression return (double)$value returns the type double which is incompatible with the documented return type Bdf\Serializer\Type\T.
Loading history...
208
209 72
            case self::STRING:
210 32
                return (string) $value;
0 ignored issues
show
Bug Best Practice introduced by
The expression return (string)$value returns the type string which is incompatible with the documented return type Bdf\Serializer\Type\T.
Loading history...
211
212 40
            case self::BOOLEAN:
213 2
                return !! $value;
0 ignored issues
show
Bug Best Practice introduced by
The expression return ! ! $value returns the type boolean which is incompatible with the documented return type Bdf\Serializer\Type\T.
Loading history...
214
215 38
            case self::TNULL:
216 2
                return null;
217
218 36
            case self::TARRAY:
219 2
                return (array) $value;
0 ignored issues
show
Bug Best Practice introduced by
The expression return (array)$value returns the type array which is incompatible with the documented return type Bdf\Serializer\Type\T.
Loading history...
220
221
            default:
222 34
                return $value;
223
        }
224
    }
225
226
    /**
227
     * Dont serialize target
228
     *
229
     * @return array
230
     */
231 2
    public function __sleep()
232
    {
233 2
        return [
234 2
            'name',
235 2
            'isArray',
236 2
            'subType',
237 2
            'isBuildin',
238 2
        ];
239
    }
240
}
241