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