Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
87.50% covered (warning)
87.50%
63 / 72
82.35% covered (warning)
82.35%
14 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
DiscoveredSymbols
87.50% covered (warning)
87.50%
63 / 72
82.35% covered (warning)
82.35%
14 / 17
28.42
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 add
80.00% covered (warning)
80.00%
12 / 15
0.00% covered (danger)
0.00%
0 / 1
8.51
 getSymbols
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 getConstants
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getNamespaces
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getNamespace
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getGlobalClasses
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getAllClasses
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDiscoveredNamespaces
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 getDiscoveredClasses
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 getDiscoveredConstants
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 getDiscoveredFunctions
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAll
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDiscoveredTraits
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDiscoveredInterfaces
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getClassmapSymbols
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getNamespaceSymbolByString
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * @see \BrianHenryIE\Strauss\Pipeline\FileSymbolScanner
4 */
5
6namespace BrianHenryIE\Strauss\Types;
7
8class DiscoveredSymbols
9{
10    /**
11     * All discovered symbols, grouped by type, indexed by original name.
12     *
13     * @var array{T_NAME_QUALIFIED:array<string,NamespaceSymbol>, T_CONST:array<string,ConstantSymbol>, T_CLASS:array<string,ClassSymbol>}
14     */
15    protected array $types = [];
16
17    public function __construct()
18    {
19        $this->types = [
20            T_CLASS => [],
21            T_CONST => [],
22            T_NAMESPACE => [],
23            T_FUNCTION => [],
24            T_TRAIT => [],
25            T_INTERFACE => [],
26        ];
27
28        $this->types[T_NAMESPACE]['\\'] = new NamespaceSymbol('\\', new \BrianHenryIE\Strauss\Files\File(''));
29    }
30
31    /**
32     * @param DiscoveredSymbol $symbol
33     */
34    public function add(DiscoveredSymbol $symbol): void
35    {
36        switch (get_class($symbol)) {
37            case NamespaceSymbol::class:
38                $type = T_NAMESPACE;
39                break;
40            case ConstantSymbol::class:
41                $type = T_CONST;
42                break;
43            case ClassSymbol::class:
44                $type = T_CLASS;
45                break;
46            case FunctionSymbol::class:
47                $type = T_FUNCTION;
48                break;
49            case InterfaceSymbol::class:
50                $type = T_INTERFACE;
51                break;
52            case TraitSymbol::class:
53                $type = T_TRAIT;
54                break;
55            default:
56                throw new \InvalidArgumentException('Unknown symbol type: ' . get_class($symbol));
57        }
58        // TODO: This should merge the symbols instead of overwriting them.
59        $this->types[$type][$symbol->getOriginalSymbol()] = $symbol;
60    }
61
62    /**
63     * @return DiscoveredSymbol[]
64     */
65    public function getSymbols(): array
66    {
67        return array_merge(
68            array_values($this->getNamespaces()),
69            array_values($this->getGlobalClasses()),
70            array_values($this->getConstants()),
71            array_values($this->getDiscoveredFunctions()),
72        );
73    }
74
75    /**
76     * @return array<string, ConstantSymbol>
77     */
78    public function getConstants()
79    {
80        return $this->types[T_CONST];
81    }
82
83    /**
84     * @return array<string, NamespaceSymbol>
85     */
86    public function getNamespaces(): array
87    {
88        return $this->types[T_NAMESPACE];
89    }
90
91    public function getNamespace(string $namespace): ?NamespaceSymbol
92    {
93        return $this->types[T_NAMESPACE][$namespace] ?? null;
94    }
95
96    /**
97     * @return array<string, ClassSymbol>
98     */
99    public function getGlobalClasses(): array
100    {
101        return array_filter(
102            $this->types[T_CLASS],
103            fn($classSymbol) => '\\' === $classSymbol->getNamespace()
104        );
105    }
106
107    /**
108     * @return array<string, ClassSymbol>
109     */
110    public function getAllClasses(): array
111    {
112        return $this->types[T_CLASS];
113    }
114
115    /**
116     * TODO: Order by longest string first. (or instead, record classnames with their namespaces)
117     *
118     * @return array<string, NamespaceSymbol>
119     */
120    public function getDiscoveredNamespaces(?string $namespacePrefix = ''): array
121    {
122        $discoveredNamespaceReplacements = [];
123
124        // When running subsequent times, try to discover the original namespaces.
125        // This is naive: it will not work where namespace replacement patterns have been used.
126        foreach ($this->getNamespaces() as $key => $value) {
127            $discoveredNamespaceReplacements[ $value->getOriginalSymbol() ] = $value;
128        }
129
130        uksort($discoveredNamespaceReplacements, function ($a, $b) {
131            return strlen($a) <=> strlen($b);
132        });
133
134        unset($discoveredNamespaceReplacements['\\']);
135
136        return $discoveredNamespaceReplacements;
137    }
138
139    /**
140     * @return string[]
141     */
142    public function getDiscoveredClasses(?string $classmapPrefix = ''): array
143    {
144        $discoveredClasses = $this->getGlobalClasses();
145
146        $discoveredClasses = array_filter(
147            array_keys($discoveredClasses),
148            function (string $replacement) use ($classmapPrefix) {
149                return empty($classmapPrefix) || ! str_starts_with($replacement, $classmapPrefix);
150            }
151        );
152
153        return $discoveredClasses;
154    }
155
156    /**
157     * @return string[]
158     */
159    public function getDiscoveredConstants(?string $constantsPrefix = ''): array
160    {
161        $discoveredConstants = $this->getConstants();
162        $discoveredConstants = array_filter(
163            array_keys($discoveredConstants),
164            function (string $replacement) use ($constantsPrefix) {
165                return empty($constantsPrefix) || ! str_starts_with($replacement, $constantsPrefix);
166            }
167        );
168
169        return $discoveredConstants;
170    }
171
172    public function getDiscoveredFunctions()
173    {
174        return $this->types[T_FUNCTION];
175    }
176
177    public function getAll(): array
178    {
179        return array_merge(...$this->types);
180    }
181
182    public function getDiscoveredTraits(): array
183    {
184        return (array) $this->types[T_TRAIT];
185    }
186
187    public function getDiscoveredInterfaces(): array
188    {
189        return (array) $this->types[T_INTERFACE];
190    }
191
192    /**
193     * Get all discovered symbols that are classes, interfaces, or traits, i.e. only those that are autoloadable.
194     *
195     * @return array<DiscoveredSymbol>
196     */
197    public function getClassmapSymbols(): array
198    {
199        return array_merge(
200            $this->getDiscoveredClasses(),
201            $this->getDiscoveredInterfaces(),
202            $this->getDiscoveredTraits(),
203        );
204    }
205
206    public function getNamespaceSymbolByString(string $namespace): ?NamespaceSymbol
207    {
208        return $this->types[T_NAMESPACE][$namespace] ?? null;
209    }
210}