Test Failed
Push — docs ( 541d16...38ea2c )
by Mark
35:24
created

Property::castValue()   A

Complexity

Conditions 6
Paths 3

Size

Total Lines 15
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 6
nc 3
nop 1
dl 0
loc 15
ccs 6
cts 6
cp 1
crap 6
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace League\Emoji\Util;
6
7
class Property
8
{
9
    public const REGEX = '/^(?:(?P<emptyNullable>[!?]{2})|(?P<nullable>[!?]))??(?P<customType>[^[<]+)?(?P<type>array|bool|boolean|double|float|int|integer|null|object|string)??(?P<iterable>\[\])?(?:<(?P<callback>[^[]+)>)??$/Ui';
10
11
    public const TYPES = ['array', 'bool', 'boolean', 'double', 'float', 'int', 'integer', 'null', 'object', 'string'];
12
13
    /** @var ?string */
14
    public $callback;
15
16
    /** @var ?string */
17
    public $customType;
18
19
    /** @var bool */
20
    public $emptyNullable;
21
22
    /** @var bool */
23
    public $nullable;
24
25
    /** @var bool */
26
    public $iterable;
27
28
    /** @var bool */
29
    public $isPhpType;
30
31
    /** @var string */
32
    public $type;
33
34 120
    public function __construct(string $type)
35
    {
36 120
        \preg_match(self::REGEX, $type, $matches, PREG_UNMATCHED_AS_NULL);
37 120
        $this->callback      = (string) ($matches['callback'] ?? null);
38 120
        $this->customType    = (string) ($matches['customType'] ?? null);
39 120
        $this->emptyNullable = ! ! ($matches['emptyNullable'] ?? false);
40 120
        $this->iterable      = ! ! ($matches['iterable'] ?? false);
41 120
        $this->nullable      = ! ! ($this->emptyNullable || ($matches['nullable'] ?? false));
42 120
        $this->type          = (string) ($matches['type'] ?? 'mixed');
43 120
        $this->isPhpType     = \in_array($this->type, self::TYPES, true);
44 120
    }
45
46
    /**
47
     * @param mixed $value
48
     *
49
     * @return mixed
50
     */
51 120
    public static function cast(string $type, $value)
52
    {
53 120
        return (new self($type))->castValue($value);
54
    }
55
56
    /**
57
     * @param mixed $value
58
     *
59
     * @return mixed[]
60
     */
61 39
    protected function castIterable($value): array
62
    {
63 39
        $value = (array) $value;
64 39
        $type  = $this->nullable
65
            ? \sprintf('?%s', $this->type)
66
            : $this->type;
67 39
68
        /** @var string[] $types */
69 39
        $types = \array_fill_keys(\array_keys($value), $type);
70
71
        return Normalize::properties($value, $types);
72
    }
73
74
    /**
75
     * @param mixed $value
76
     *
77 120
     * @return mixed
78
     */
79
    public function castValue($value)
80 120
    {
81 60
        // Immediately return if nullable or empty.
82
        if (($this->nullable && $value === null) || ($this->emptyNullable && ! $value)) {
83
            return null;
84 93
        }
85
86 93
        /** @psalm-var string $value */
87 39
        $value = $this->castValueCallback($value);
88
89
        if ($this->iterable) {
90 93
            return $this->castIterable($value);
91
        }
92
93
        return $this->castValueType($value);
94
    }
95
96
    /**
97
     * @param mixed $value
98 93
     *
99
     * @return mixed
100 93
     */
101 36
    protected function castValueCallback($value)
102
    {
103
        if (($callback = $this->callback) && \is_callable($callback)) {
104 93
            /** @psalm-var string $value */
105
            $value = $callback($value);
106
        }
107
108
        return $value;
109
    }
110
111
    /**
112 93
     * @param mixed $value
113
     *
114 93
     * @return mixed
115 36
     */
116
    protected function castValueType($value)
117 90
    {
118
        if (($type = $this->customType) && \class_exists($type)) {
119
            try {
120 93
                $ref   = new \ReflectionClass($type);
121
                $value = $ref->newInstanceArgs([$value]);
122
            } catch (\ReflectionException $e) {
123
                // Intentionally left empty.
124
            }
125
        } else {
126
            Normalize::setType($value, $this->type);
127
        }
128
129
        return $this->emptyNullable && ! $value
130
            ? null
131
            : $value;
132
    }
133
}
134