-
-
Notifications
You must be signed in to change notification settings - Fork 160
Expand file tree
/
Copy pathDebug.php
More file actions
145 lines (121 loc) · 4.31 KB
/
Debug.php
File metadata and controls
145 lines (121 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<?php
declare(strict_types=1);
namespace Tempest\Debug;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\VarDumper;
use Tempest\Container\GenericContainer;
use Tempest\EventBus\EventBus;
use Tempest\Highlight\Themes\TerminalStyle;
use Tempest\Support\Filesystem;
use Throwable;
final readonly class Debug
{
private function __construct(
private ?DebugConfig $config = null,
private ?EventBus $eventBus = null,
) {}
public static function resolve(): self
{
try {
return new self(
config: GenericContainer::instance()->get(DebugConfig::class),
eventBus: GenericContainer::instance()->get(EventBus::class),
);
} catch (Throwable) {
return new self();
}
}
/**
* Logs and/or dumps the given items.
*
* @param bool $writeToLog Whether to write the items to the log file.
* @param bool $writeToOut Whether to dump the items to the standard output.
*/
public function log(array $items, bool $writeToLog = true, bool $writeToOut = true): void
{
static $isDispatchingItemsDebuggedEvent = false;
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
$callPath = ($trace[1]['file'] ?? 'unknown') . ':' . ($trace[1]['line'] ?? 0);
if ($writeToLog) {
$this->writeToLog($items, $callPath);
}
if ($writeToOut) {
$this->writeToOut($items, $callPath);
}
if (! $this->eventBus || $isDispatchingItemsDebuggedEvent) {
return;
}
$isDispatchingItemsDebuggedEvent = true;
try {
$this->eventBus->dispatch(new ItemsDebugged($items));
} finally {
$isDispatchingItemsDebuggedEvent = false;
}
}
private function writeToLog(array $items, string $callPath): void
{
if (! $this->config?->logPath) {
return;
}
Filesystem\create_directory_for_file($this->config->logPath);
if (! ($handle = @fopen($this->config->logPath, 'a'))) {
return;
}
foreach ($items as $key => $item) {
fwrite($handle, TerminalStyle::BG_BLUE(" {$key} ") . TerminalStyle::FG_GRAY(' → ' . TerminalStyle::ITALIC($callPath)));
fwrite($handle, $this->createCliDump($item) . PHP_EOL);
}
fclose($handle);
}
private function writeToOut(array $items, string $callPath): void
{
foreach ($items as $key => $item) {
if (defined('STDOUT')) {
fwrite(STDOUT, TerminalStyle::BG_BLUE(" {$key} ") . ' ');
fwrite(STDOUT, $this->createCliDump($item));
fwrite(STDOUT, TerminalStyle::DIM('→ ' . TerminalStyle::ITALIC($callPath)) . PHP_EOL . PHP_EOL);
} else {
echo
vsprintf(
<<<HTML
<span style="
display:inline-block;
color: #fff;
font-family: %s;
padding: 2px 4px;
font-size: 0.8rem;
margin-bottom: -12px;
background: #0071BC;"
>%s (%s)</span>
HTML,
[
'Source Code Pro, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace',
$key,
$callPath,
],
)
;
VarDumper::dump($item);
}
}
}
private function createCliDump(mixed $input): string
{
$cloner = new VarCloner();
$output = '';
$dumper = new CliDumper(function ($line, $depth) use (&$output): void {
if ($depth < 0) {
return;
}
$output .= str_repeat(' ', $depth) . $line . "\n";
});
$dumper->setColors(true);
$dumper->dump($cloner->cloneVar($input));
return preg_replace(
pattern: '/\e](.*)\e]8;;\e/',
replacement: '',
subject: $output,
);
}
}