Viewing file: DumpRecorder.php (3.77 KB) -rwxrwxr-x Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
namespace Spatie\LaravelIgnition\Recorders\DumpRecorder;
use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\Arr; use ReflectionMethod; use ReflectionProperty; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\VarDumper;
class DumpRecorder { /** @var array<array<int,mixed>> */ protected array $dumps = [];
protected Application $app;
protected static bool $registeredHandler = false;
public function __construct(Application $app) { $this->app = $app; }
public function start(): self { $multiDumpHandler = new MultiDumpHandler();
$this->app->singleton(MultiDumpHandler::class, fn () => $multiDumpHandler);
if (! self::$registeredHandler) { static::$registeredHandler = true;
$this->ensureOriginalHandlerExists();
$originalHandler = VarDumper::setHandler(fn ($dumpedVariable) => $multiDumpHandler->dump($dumpedVariable));
$multiDumpHandler?->addHandler($originalHandler);
$multiDumpHandler->addHandler(fn ($var) => (new DumpHandler($this))->dump($var)); }
return $this; }
public function record(Data $data): void { $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 11);
$sourceFrame = $this->findSourceFrame($backtrace);
$file = (string) Arr::get($sourceFrame, 'file'); $lineNumber = (int) Arr::get($sourceFrame, 'line');
$htmlDump = (new HtmlDumper())->dump($data);
$this->dumps[] = new Dump($htmlDump, $file, $lineNumber); }
public function getDumps(): array { return $this->toArray(); }
public function reset() { $this->dumps = []; }
public function toArray(): array { $dumps = [];
foreach ($this->dumps as $dump) { $dumps[] = $dump->toArray(); }
return $dumps; }
/* * Only the `VarDumper` knows how to create the orignal HTML or CLI VarDumper. * Using reflection and the private VarDumper::register() method we can force it * to create and register a new VarDumper::$handler before we'll overwrite it. * Of course, we only need to do this if there isn't a registered VarDumper::$handler. * * @throws \ReflectionException */ protected function ensureOriginalHandlerExists(): void { $reflectionProperty = new ReflectionProperty(VarDumper::class, 'handler'); $reflectionProperty->setAccessible(true); $handler = $reflectionProperty->getValue();
if (! $handler) { // No handler registered yet, so we'll force VarDumper to create one. $reflectionMethod = new ReflectionMethod(VarDumper::class, 'register'); $reflectionMethod->setAccessible(true); $reflectionMethod->invoke(null); } }
/** * Find the first meaningful stack frame that is not the `DumpRecorder` itself. * * @template T of array{class?: class-string, function?: string, line?: int, file?: string} * * @param array<T> $stacktrace * * @return null|T */ protected function findSourceFrame(array $stacktrace): ?array { $seenVarDumper = false;
foreach ($stacktrace as $frame) { // Keep looping until we're past the VarDumper::dump() call in Symfony's helper functions file. if (Arr::get($frame, 'class') === VarDumper::class && Arr::get($frame, 'function') === 'dump') { $seenVarDumper = true;
continue; }
if (! $seenVarDumper) { continue; }
// Return the next frame in the stack after the VarDumper::dump() call: return $frame; }
return null; } }
|