Passed
Push — master ( 1416ae...b5a8b1 )
by Luis
54s queued 13s
created

TypeDeclaration::references()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 13
nc 5
nop 0
dl 0
loc 20
ccs 13
cts 13
cp 1
crap 6
rs 9.2222
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
/**
3
 * PHP version 8.1
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.1, 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', 'never',
26
        // pseudo-types
27
        'resource',
28
        // aliases
29
        'number', 'boolean', 'integer', 'double',
30
    ];
31
32
    /** @var Name[] */
33
    private readonly array $names;
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_ARRAY, expecting T_VARIABLE on line 33 at column 21
Loading history...
34
35 95
    public static function absent(): TypeDeclaration
36
    {
37 95
        return new TypeDeclaration();
38
    }
39
40 104
    public static function from(?string $type): TypeDeclaration
41
    {
42 104
        return new TypeDeclaration($type === null ? [] : [new Name($type)]);
43
    }
44
45 23
    public static function fromNullable(string $type): TypeDeclaration
46
    {
47 23
        return new TypeDeclaration([new Name($type)], isNullable: true);
48
    }
49
50
    /**
51
     * A composite type can be either a union or an intersection type
52
     *
53
     * @param string[] $types
54
     * @link https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.composite.union Union types documentation
55
     * @link https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.composite.intersection Intersection types documentation
56
     */
57 35
    public static function fromCompositeType(array $types, CompositeType $compositeType): TypeDeclaration
58
    {
59 35
        return new TypeDeclaration(
60 35
            array_map(static fn (string $type) => new Name($type), $types),
61
            compositeType: $compositeType
62
        );
63
    }
64
65
    /** @param Name[] $names */
66 157
    private function __construct(
67
        array $names = [],
68
        private readonly bool $isNullable = false,
69
        private readonly CompositeType $compositeType = CompositeType::NONE
70
    ) {
71 157
        $this->names = $names;
72
    }
73
74 71
    public function isPresent(): bool
75
    {
76 71
        return $this->names !== [];
77
    }
78
79
    /** @return Name[] */
80 27
    public function references(): array
81
    {
82 27
        if (! $this->isPresent()) {
83 11
            return [];
84
        }
85 26
        if ($this->isBuiltIn()) {
86 10
            return [];
87
        }
88 23
        if ($this->isRegularType()) {
89 21
            return [$this->isArray() ? new Name($this->removeArraySuffix()) : $this->names[0]];
90
        }
91
92 4
        $typesFromUnion = array_map(static fn (Name $name) => TypeDeclaration::from($name->fullName()), $this->names);
93 4
        $references = array_filter($typesFromUnion, static fn (TypeDeclaration $type) => ! $type->isBuiltIn());
94
95 4
        return array_map(
96 4
            static fn (TypeDeclaration $reference) => $reference->isArray()
97 2
                ? new Name($reference->removeArraySuffix())
98 4
                : $reference->names[0],
99
            $references
100
        );
101
    }
102
103
    /**
104
     * It helps building the relationships between classes/interfaces since built-in
105
     * types are not part of a UML class diagram
106
     */
107 44
    public function isBuiltIn(): bool
108
    {
109 44
        if (! $this->isRegularType()) {
110 6
            return false;
111
        }
112 43
        $type = (string) $this->names[0];
113 43
        if ($this->isArray()) {
114 8
            $type = $this->removeArraySuffix();
115
        }
116
117 43
        return in_array($type, self::BUILT_IN_TYPES, true);
118
    }
119
120 8
    private function removeArraySuffix(): string
121
    {
122 8
        return substr($this->names[0]->fullName(), 0, -2);
123
    }
124
125 32
    public function isBuiltInArray(): bool
126
    {
127 32
        if ($this->isRegularType()) {
128 29
            return (string) $this->names[0] === 'array';
129
        }
130 17
        return false;
131
    }
132
133 43
    private function isArray(): bool
134
    {
135 43
        return str_ends_with($this->names[0]->fullName(), '[]');
136
    }
137
138 1
    public function isNullable(): bool
139
    {
140 1
        return $this->isNullable;
141
    }
142
143 72
    private function isRegularType(): bool
144
    {
145 72
        return count($this->names) === 1;
146
    }
147
148 49
    public function __toString(): string
149
    {
150 49
        return ($this->isNullable ? '?' : '') . implode($this->compositeType->value, $this->names);
151
    }
152
}
153