Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
95.83% |
69 / 72 |
|
96.77% |
30 / 31 |
CRAP | |
0.00% |
0 / 1 |
Debugger | |
95.83% |
69 / 72 |
|
96.77% |
30 / 31 |
52 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
8 | |||
addHandlers | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
addHandler | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 | |||
hasHandler | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getHandler | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getHandlers | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setStorage | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
hasStorage | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getStorage | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getData | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
getById | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getByType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
has | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
delete | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
clear | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
save | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
render | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
getRequestId | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
renderWithHeaders | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
generateId | |
40.00% |
2 / 5 |
|
0.00% |
0 / 1 |
4.94 | |||
count | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getIterator | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
__set | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
__get | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
__isset | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
__unset | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
offsetSet | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
offsetGet | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
offsetExists | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
offsetUnset | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
__toString | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * Pop PHP Framework (http://www.popphp.org/) |
4 | * |
5 | * @link https://github.com/popphp/popphp-framework |
6 | * @author Nick Sagona, III <dev@nolainteractive.com> |
7 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
8 | * @license http://www.popphp.org/license New BSD License |
9 | */ |
10 | |
11 | /** |
12 | * @namespace |
13 | */ |
14 | namespace Pop\Debug; |
15 | |
16 | use Pop\Debug\Handler\HandlerInterface; |
17 | use Pop\Debug\Storage\StorageInterface; |
18 | use ArrayIterator; |
19 | |
20 | /** |
21 | * Debugger class |
22 | * |
23 | * @category Pop |
24 | * @package Pop\Debug |
25 | * @author Nick Sagona, III <dev@nolainteractive.com> |
26 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
27 | * @license http://www.popphp.org/license New BSD License |
28 | * @version 2.0.0 |
29 | */ |
30 | class Debugger implements \ArrayAccess, \Countable, \IteratorAggregate |
31 | { |
32 | |
33 | /** |
34 | * Debugger handlers |
35 | * @var array |
36 | */ |
37 | protected array $handlers = []; |
38 | |
39 | /** |
40 | * Debugger storage object |
41 | * @var ?StorageInterface |
42 | */ |
43 | protected ?StorageInterface $storage = null; |
44 | |
45 | /** |
46 | * Debugger request ID |
47 | * @var ?string |
48 | */ |
49 | protected ?string $requestId = null; |
50 | |
51 | /** |
52 | * Constructor |
53 | * |
54 | * Instantiate a debug object |
55 | */ |
56 | public function __construct() |
57 | { |
58 | $args = func_get_args(); |
59 | |
60 | foreach ($args as $arg) { |
61 | if (is_array($arg)) { |
62 | foreach ($arg as $a) { |
63 | if ($a instanceof HandlerInterface) { |
64 | $this->addHandler($a); |
65 | } else if ($a instanceof StorageInterface) { |
66 | $this->setStorage($a); |
67 | } |
68 | } |
69 | } else if ($arg instanceof HandlerInterface) { |
70 | $this->addHandler($arg); |
71 | } else if ($arg instanceof StorageInterface) { |
72 | $this->setStorage($arg); |
73 | } |
74 | } |
75 | } |
76 | |
77 | /** |
78 | * Add handlers |
79 | * |
80 | * @param array $handlers |
81 | * @return Debugger |
82 | */ |
83 | public function addHandlers(array $handlers): Debugger |
84 | { |
85 | foreach ($handlers as $handler) { |
86 | $this->addHandler($handler); |
87 | } |
88 | |
89 | return $this; |
90 | } |
91 | |
92 | /** |
93 | * Add a handler |
94 | * |
95 | * @param HandlerInterface $handler |
96 | * @return Debugger |
97 | */ |
98 | public function addHandler(HandlerInterface $handler): Debugger |
99 | { |
100 | $type = strtolower(str_replace('Handler', '', get_class($handler))); |
101 | if (strrpos($type, '\\') !== false) { |
102 | $type = substr($type, (strrpos($type, '\\') + 1)); |
103 | if (!empty($handler->getName())) { |
104 | $type = str_replace(' ', '-', strtolower($handler->getName())) . '-' . $type; |
105 | } |
106 | } |
107 | |
108 | $this->handlers[$type] = $handler; |
109 | |
110 | return $this; |
111 | } |
112 | |
113 | /** |
114 | * Determine if the debug object has a handler |
115 | * |
116 | * @param string $name |
117 | * @return bool |
118 | */ |
119 | public function hasHandler(string $name): bool |
120 | { |
121 | return isset($this->handlers[$name]); |
122 | } |
123 | |
124 | /** |
125 | * Get a handler |
126 | * |
127 | * @param string $name |
128 | * @return ?HandlerInterface |
129 | */ |
130 | public function getHandler(string $name): ?HandlerInterface |
131 | { |
132 | return $this->handlers[$name] ?? null; |
133 | } |
134 | |
135 | /** |
136 | * Get all handlers |
137 | * |
138 | * @return array |
139 | */ |
140 | public function getHandlers(): array |
141 | { |
142 | return $this->handlers; |
143 | } |
144 | |
145 | /** |
146 | * Set the storage object |
147 | * |
148 | * @param StorageInterface $storage |
149 | * @return Debugger |
150 | */ |
151 | public function setStorage(StorageInterface $storage): Debugger |
152 | { |
153 | $this->storage = $storage; |
154 | return $this; |
155 | } |
156 | |
157 | /** |
158 | * Determine if the debug object has storage |
159 | * |
160 | * @return bool |
161 | */ |
162 | public function hasStorage(): bool |
163 | { |
164 | return ($this->storage !== null); |
165 | } |
166 | |
167 | /** |
168 | * Get the storage object |
169 | * |
170 | * @return StorageInterface |
171 | */ |
172 | public function getStorage(): StorageInterface |
173 | { |
174 | return $this->storage; |
175 | } |
176 | |
177 | /** |
178 | * Get all data from handlers |
179 | * |
180 | * @return array |
181 | */ |
182 | public function getData(): array |
183 | { |
184 | $data = []; |
185 | foreach ($this->handlers as $name => $handler) { |
186 | $data[$name] = ($this->storage->getFormat() == 'TEXT') ? $handler->prepareAsString() : $handler->prepare(); |
187 | } |
188 | return $data; |
189 | } |
190 | |
191 | /** |
192 | * Get stored request by ID |
193 | * |
194 | * @param string $id |
195 | * @return mixed |
196 | */ |
197 | public function getById(string $id): mixed |
198 | { |
199 | return $this->storage->getById($id); |
200 | } |
201 | |
202 | /** |
203 | * Get stored request by type |
204 | * |
205 | * @param string $type |
206 | * @return mixed |
207 | */ |
208 | public function getByType(string $type): mixed |
209 | { |
210 | return $this->storage->getByType($type); |
211 | } |
212 | |
213 | /** |
214 | * Determine if debug data exists by ID |
215 | * |
216 | * @param string $id |
217 | * @return bool |
218 | */ |
219 | public function has(string $id): bool |
220 | { |
221 | return $this->storage->has($id); |
222 | } |
223 | |
224 | /** |
225 | * Delete debug data by ID |
226 | * |
227 | * @param string $id |
228 | * @return void |
229 | */ |
230 | public function delete(string $id): void |
231 | { |
232 | $this->storage->delete($id); |
233 | } |
234 | |
235 | /** |
236 | * Clear storage |
237 | * |
238 | * @return void |
239 | */ |
240 | public function clear(): void |
241 | { |
242 | $this->storage->clear(); |
243 | } |
244 | |
245 | /** |
246 | * Save the debug handlers' data to storage |
247 | * |
248 | * @return string |
249 | */ |
250 | public function save(): string |
251 | { |
252 | foreach ($this->handlers as $name => $handler) { |
253 | $data = ($this->storage->getFormat() == 'TEXT') ? $handler->prepareAsString() : $handler->prepare(); |
254 | $this->storage->save($this->getRequestId() . '-' . $name, $data); |
255 | } |
256 | |
257 | return $this->getRequestId(); |
258 | } |
259 | |
260 | /** |
261 | * Render the debug handlers' data to string |
262 | * |
263 | * @return string |
264 | */ |
265 | public function render(): string |
266 | { |
267 | $output = ''; |
268 | |
269 | foreach ($this->handlers as $handler) { |
270 | $output .= $handler->prepareAsString(); |
271 | } |
272 | |
273 | return $output; |
274 | } |
275 | |
276 | /** |
277 | * Get current request ID |
278 | * |
279 | * @return string |
280 | */ |
281 | public function getRequestId(): string |
282 | { |
283 | if ($this->requestId === null) { |
284 | $this->requestId = $this->generateId(); |
285 | } |
286 | |
287 | return $this->requestId; |
288 | } |
289 | |
290 | /** |
291 | * Render the debug handlers' data to string with headers |
292 | * |
293 | * @return string |
294 | */ |
295 | public function renderWithHeaders(): string |
296 | { |
297 | $output = ''; |
298 | |
299 | foreach ($this->handlers as $handler) { |
300 | $output .= $handler->prepareHeaderAsString() . $handler->prepareAsString(); |
301 | } |
302 | |
303 | return $output; |
304 | } |
305 | |
306 | /** |
307 | * Generate unique ID |
308 | * |
309 | * @return string |
310 | */ |
311 | public function generateId(): string |
312 | { |
313 | if (function_exists('random_bytes')) { |
314 | return bin2hex(random_bytes(16)); |
315 | } else if (function_exists('openssl_random_pseudo_bytes')) { |
316 | return bin2hex(openssl_random_pseudo_bytes(16)); |
317 | } else { |
318 | return md5(uniqid()); |
319 | } |
320 | } |
321 | /** |
322 | * Method to get the count of the handlers |
323 | * |
324 | * @return int |
325 | */ |
326 | public function count(): int |
327 | { |
328 | return count($this->handlers); |
329 | } |
330 | |
331 | /** |
332 | * Method to iterate over the handlers |
333 | * |
334 | * @return ArrayIterator |
335 | */ |
336 | public function getIterator(): ArrayIterator |
337 | { |
338 | return new ArrayIterator($this->handlers); |
339 | } |
340 | |
341 | /** |
342 | * Set a handler |
343 | * |
344 | * @param string $name |
345 | * @param mixed $value |
346 | * @throws Exception |
347 | * @return void |
348 | */ |
349 | public function __set(string $name, mixed $value): void |
350 | { |
351 | $this->offsetSet($name, $value); |
352 | } |
353 | |
354 | /** |
355 | * Get a handler |
356 | * |
357 | * @param string $name |
358 | * @return mixed |
359 | */ |
360 | public function __get(string $name): mixed |
361 | { |
362 | return $this->offsetGet($name); |
363 | } |
364 | |
365 | /** |
366 | * Is handler set |
367 | * |
368 | * @param string $name |
369 | * @return bool |
370 | */ |
371 | public function __isset(string $name): bool |
372 | { |
373 | return $this->offsetExists($name); |
374 | } |
375 | |
376 | /** |
377 | * Unset a handler |
378 | * |
379 | * @param string $name |
380 | * @return void |
381 | */ |
382 | public function __unset(string $name): void |
383 | { |
384 | $this->offsetUnset($name); |
385 | } |
386 | |
387 | /** |
388 | * ArrayAccess offsetSet |
389 | * |
390 | * @param mixed $offset |
391 | * @param mixed $value |
392 | * @throws Exception |
393 | * @return void |
394 | */ |
395 | public function offsetSet(mixed $offset, mixed $value): void |
396 | { |
397 | if (!($value instanceof HandlerInterface)) { |
398 | throw new Exception('Error: The value passed must be an instance of HandlerInterface'); |
399 | } |
400 | $this->handlers[$offset] = $value; |
401 | } |
402 | |
403 | /** |
404 | * ArrayAccess offsetGet |
405 | * |
406 | * @param mixed $offset |
407 | * @return mixed |
408 | */ |
409 | public function offsetGet(mixed $offset): mixed |
410 | { |
411 | return $this->handlers[$offset] ?? null; |
412 | } |
413 | |
414 | /** |
415 | * ArrayAccess offsetExists |
416 | * |
417 | * @param mixed $offset |
418 | * @return bool |
419 | */ |
420 | public function offsetExists(mixed $offset): bool |
421 | { |
422 | return isset($this->handlers[$offset]); |
423 | } |
424 | |
425 | /** |
426 | * ArrayAccess offsetUnset |
427 | * |
428 | * @param mixed $offset |
429 | * @return void |
430 | */ |
431 | public function offsetUnset(mixed $offset): void |
432 | { |
433 | if (isset($this->handlers[$offset])) { |
434 | unset($this->handlers[$offset]); |
435 | } |
436 | } |
437 | |
438 | /** |
439 | * Render to string |
440 | * |
441 | * @return string |
442 | */ |
443 | public function __toString(): string |
444 | { |
445 | return $this->renderWithHeaders(); |
446 | } |
447 | |
448 | } |