Passed
Pull Request — master (#9)
by Luis
13:24
created

TypeDeclaration::references()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 13
nc 5
nop 0
dl 0
loc 20
ccs 8
cts 8
cp 1
crap 6
rs 9.2222
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
/**
3
 * PHP version 8.0
4
 *
5
 * This source file is subject to the license that is bundled with this package in the file LICENSE.
6
 */
7
8
namespace PhUml\Code\Variables;
9
10
use PhUml\Code\Name;
11
use Stringable;
12
13
/**
14
 * It represents a variable's type declaration
15
 */
16
final class TypeDeclaration implements Stringable
17
{
18
    /** @var string[] All valid types for PHP 8.0, pseudo-types, and aliases */
19
    private const BUILT_IN_TYPES = [
20
        // https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.base
21
        'int', 'bool', 'string', 'array', 'float', 'callable', 'iterable', 'mixed', 'object',
22
        // https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.union.nullable
23
        'null',
24
        // https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.return-only
25
        'void',
26
        // pseudo-types
27
        'resource',
28
        // aliases
29
        'number', 'boolean', 'integer', 'double',
30 213
    ];
31
32 213
    /** @var Name[] */
33
    private array $names;
34
35 249
    public static function absent(): TypeDeclaration
36
    {
37 249
        return new TypeDeclaration();
38
    }
39
40 183
    public static function from(?string $type): TypeDeclaration
41
    {
42 183
        return new TypeDeclaration($type === null ? [] : [new Name($type)]);
43
    }
44
45
    public static function fromNullable(string $type): TypeDeclaration
46
    {
47
        return new TypeDeclaration([new Name($type)], isNullable: true);
48
    }
49
50
    /** @param string[] $types */
51 117
    public static function fromUnionType(array $types): TypeDeclaration
52
    {
53 117
        return new TypeDeclaration(array_map(static fn (string $type) => new Name($type), $types));
54 117
    }
55 27
56
    public function isPresent(): bool
57 117
    {
58
        return count($this->names) > 0;
59
    }
60 117
61
    /** @return Name[] */
62 117
    public function references(): array
63
    {
64
        if (! $this->isPresent()) {
65 27
            return [];
66
        }
67 27
        if ($this->isBuiltIn()) {
68
            return [];
69
        }
70 318
        if ($this->isRegularType()) {
71
            return [$this->isArray() ? new Name($this->removeArraySuffix()) : $this->names[0]];
72 318
        }
73 318
74
        $typesFromUnion = array_map(fn (Name $name) => TypeDeclaration::from((string) $name), $this->names);
75 93
        $references = array_filter($typesFromUnion, fn (TypeDeclaration $type) => ! $type->isBuiltIn());
76
77 93
        return array_map(
78
            fn (TypeDeclaration $reference) => $reference->isArray()
79
                ? new Name($reference->removeArraySuffix())
80
                : $reference->names[0],
81
            $references
82
        );
83
    }
84
85
    /**
86
     * It helps building the relationships between classes/interfaces since built-in
87
     * types are not part of a UML class diagram
88
     */
89
    public function isBuiltIn(): bool
90
    {
91
        if (! $this->isRegularType()) {
92
            return false;
93
        }
94
        $type = (string) $this->names[0];
95
        if ($this->isArray()) {
96
            $type = $this->removeArraySuffix();
97
        }
98
99
        return in_array($type, self::BUILT_IN_TYPES, true);
100
    }
101
102
    private function removeArraySuffix(): string
103
    {
104
        return substr((string) $this->names[0], 0, -2);
105
    }
106
107
    public function isBuiltInArray(): bool
108
    {
109
        if ($this->isRegularType()) {
110
            return (string) $this->names[0] === 'array';
111
        }
112
        return false;
113
    }
114
115
    private function isArray(): bool
116
    {
117
        return strpos((string) $this->names[0], '[]') === strlen((string) $this->names[0]) - 2;
118
    }
119
120
    public function isNullable(): bool
121
    {
122
        return $this->isNullable;
123
    }
124
125
    private function isRegularType(): bool
126
    {
127
        return count($this->names) === 1;
128
    }
129
130
    public function __toString(): string
131
    {
132
        return ($this->isNullable ? '?' : '') . implode('|', $this->names);
133
    }
134
135
    /** @param Name[] $names */
136
    private function __construct(array $names = [], private bool $isNullable = false)
137
    {
138
        $this->names = $names;
139
    }
140
}
141