Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
79 / 79 |
|
100.00% |
15 / 15 |
CRAP | |
100.00% |
1 / 1 |
Debugger | |
100.00% |
79 / 79 |
|
100.00% |
15 / 15 |
25 | |
100.00% |
1 / 1 |
addCollection | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getCollections | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getCollection | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addCollector | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
setOptions | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getOptions | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getActivities | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
5 | |||
addActivityValues | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
setDebugbarView | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 | |||
getDebugbarView | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
renderDebugbar | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
makeSafeName | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
1 | |||
convertSize | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
makeDebugValue | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
2 | |||
roundVersion | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 |
1 | <?php declare(strict_types=1); |
2 | /* |
3 | * This file is part of Aplus Framework Debug Library. |
4 | * |
5 | * (c) Natan Felles <natanfelles@gmail.com> |
6 | * |
7 | * For the full copyright and license information, please view the LICENSE |
8 | * file that was distributed with this source code. |
9 | */ |
10 | namespace Framework\Debug; |
11 | |
12 | use Framework\Helpers\Isolation; |
13 | use InvalidArgumentException; |
14 | |
15 | /** |
16 | * Class Debugger. |
17 | * |
18 | * @package debug |
19 | */ |
20 | class Debugger |
21 | { |
22 | /** |
23 | * @var array<string,Collection> |
24 | */ |
25 | protected array $collections = []; |
26 | /** |
27 | * @var array<string,mixed> |
28 | */ |
29 | protected array $options = []; |
30 | protected string $debugbarView = __DIR__ . '/Views/debugbar/debugbar.php'; |
31 | |
32 | public function addCollection(Collection $collection) : static |
33 | { |
34 | $this->collections[$collection->getName()] = $collection; |
35 | return $this; |
36 | } |
37 | |
38 | /** |
39 | * @return array<string,Collection> |
40 | */ |
41 | public function getCollections() : array |
42 | { |
43 | return $this->collections; |
44 | } |
45 | |
46 | public function getCollection(string $name) : ?Collection |
47 | { |
48 | return $this->getCollections()[$name] ?? null; |
49 | } |
50 | |
51 | public function addCollector(Collector $collector, string $collectionName) : static |
52 | { |
53 | $collection = $this->getCollection($collectionName); |
54 | if ($collection === null) { |
55 | $collection = new Collection($collectionName); |
56 | $this->addCollection($collection); |
57 | } |
58 | $collection->addCollector($collector); |
59 | return $this; |
60 | } |
61 | |
62 | /** |
63 | * @param array<string,mixed> $options |
64 | * |
65 | * @return static |
66 | */ |
67 | public function setOptions(array $options) : static |
68 | { |
69 | $this->options = $options; |
70 | return $this; |
71 | } |
72 | |
73 | /** |
74 | * @return array<string,mixed> |
75 | */ |
76 | public function getOptions() : array |
77 | { |
78 | return $this->options; |
79 | } |
80 | |
81 | /** |
82 | * @return array<string,mixed> |
83 | */ |
84 | public function getActivities() : array |
85 | { |
86 | $collected = []; |
87 | foreach ($this->getCollections() as $collection) { |
88 | foreach ($collection->getActivities() as $activities) { |
89 | $collected = [...$collected, ...$activities]; |
90 | } |
91 | } |
92 | $min = .0; |
93 | $max = .0; |
94 | if ($collected) { |
95 | \usort($collected, static function ($c1, $c2) { |
96 | return $c1['start'] <=> $c2['start']; |
97 | }); |
98 | $min = \min(\array_column($collected, 'start')); |
99 | $max = \max(\array_column($collected, 'end')); |
100 | foreach ($collected as &$activity) { |
101 | $this->addActivityValues($activity, $min, $max); |
102 | } |
103 | } |
104 | return [ |
105 | 'min' => $min, |
106 | 'max' => $max, |
107 | 'total' => $max - $min, |
108 | 'collected' => $collected, |
109 | ]; |
110 | } |
111 | |
112 | /** |
113 | * @param array<string,mixed> $activity |
114 | * @param float $min |
115 | * @param float $max |
116 | */ |
117 | protected function addActivityValues(array &$activity, float $min, float $max) : void |
118 | { |
119 | $total = $max - $min; |
120 | $activity['total'] = $activity['end'] - $activity['start']; |
121 | $activity['left'] = \round(($activity['start'] - $min) * 100 / $total, 3); |
122 | $activity['width'] = \round($activity['total'] * 100 / $total, 3); |
123 | } |
124 | |
125 | public function setDebugbarView(string $file) : static |
126 | { |
127 | $realpath = \realpath($file); |
128 | if ( ! $realpath || ! \is_file($realpath)) { |
129 | throw new InvalidArgumentException( |
130 | 'Invalid debugbar view file: ' . $file |
131 | ); |
132 | } |
133 | $this->debugbarView = $realpath; |
134 | return $this; |
135 | } |
136 | |
137 | public function getDebugbarView() : string |
138 | { |
139 | return $this->debugbarView; |
140 | } |
141 | |
142 | public function renderDebugbar() : string |
143 | { |
144 | \ob_start(); |
145 | Isolation::require($this->getDebugbarView(), [ |
146 | 'collections' => $this->getCollections(), |
147 | 'activities' => $this->getActivities(), |
148 | 'options' => $this->getOptions(), |
149 | ]); |
150 | return \ob_get_clean(); // @phpstan-ignore-line |
151 | } |
152 | |
153 | public static function makeSafeName(string $name) : string |
154 | { |
155 | return \strtr(\trim(\strip_tags(\strtolower($name))), [ |
156 | 'ยท' => '-', |
157 | ':' => '-', |
158 | '(' => '-', |
159 | ')' => '-', |
160 | '/' => '-', |
161 | '\\' => '-', |
162 | ' ' => '-', |
163 | ]); |
164 | } |
165 | |
166 | public static function convertSize(float | int $size) : string |
167 | { |
168 | if (empty($size)) { |
169 | return '0 B'; |
170 | } |
171 | $unit = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']; |
172 | $index = \floor(\log($size, 1024)); |
173 | return \round($size / (1024 ** $index), 3) . ' ' . $unit[$index]; |
174 | } |
175 | |
176 | public static function makeDebugValue(mixed $value) : string |
177 | { |
178 | $type = \get_debug_type($value); |
179 | return (string) match ($type) { |
180 | 'array' => 'array', |
181 | 'bool' => $value ? 'true' : 'false', |
182 | 'float', 'int' => $value, |
183 | 'null' => 'null', |
184 | 'string' => "'" . \strtr($value, ["'" => "\\'"]) . "'", |
185 | default => 'instanceof ' . $type, |
186 | }; |
187 | } |
188 | |
189 | /** |
190 | * Remove dots and zeros from the end of the version. |
191 | * |
192 | * @param string $version |
193 | * |
194 | * @return string |
195 | */ |
196 | public static function roundVersion(string $version) : string |
197 | { |
198 | if (\str_ends_with($version, '.0')) { |
199 | $version = \substr($version, 0, -2); |
200 | return static::roundVersion($version); |
201 | } |
202 | return $version; |
203 | } |
204 | } |