Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Spatie\LaravelIgnition\Recorders\DumpRecorder;
4
 
5
use Illuminate\Contracts\Foundation\Application;
6
use Illuminate\Support\Arr;
7
use ReflectionMethod;
8
use ReflectionProperty;
9
use Symfony\Component\VarDumper\Cloner\Data;
10
use Symfony\Component\VarDumper\VarDumper;
11
 
12
class DumpRecorder
13
{
14
    /** @var array<array<int,mixed>> */
15
    protected array $dumps = [];
16
 
17
    protected Application $app;
18
 
19
    protected static bool $registeredHandler = false;
20
 
21
    public function __construct(Application $app)
22
    {
23
        $this->app = $app;
24
    }
25
 
26
    public function start(): self
27
    {
28
        $multiDumpHandler = new MultiDumpHandler();
29
 
30
        $this->app->singleton(MultiDumpHandler::class, fn () => $multiDumpHandler);
31
 
32
        if (! self::$registeredHandler) {
33
            static::$registeredHandler = true;
34
 
35
            $this->ensureOriginalHandlerExists();
36
 
37
            $originalHandler = VarDumper::setHandler(fn ($dumpedVariable) => $multiDumpHandler->dump($dumpedVariable));
38
 
39
            $multiDumpHandler?->addHandler($originalHandler);
40
 
41
            $multiDumpHandler->addHandler(fn ($var) => (new DumpHandler($this))->dump($var));
42
        }
43
 
44
        return $this;
45
    }
46
 
47
    public function record(Data $data): void
48
    {
49
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 11);
50
 
51
        $sourceFrame = $this->findSourceFrame($backtrace);
52
 
53
        $file = (string) Arr::get($sourceFrame, 'file');
54
        $lineNumber = (int) Arr::get($sourceFrame, 'line');
55
 
56
        $htmlDump = (new HtmlDumper())->dump($data);
57
 
58
        $this->dumps[] = new Dump($htmlDump, $file, $lineNumber);
59
    }
60
 
61
    public function getDumps(): array
62
    {
63
        return $this->toArray();
64
    }
65
 
66
    public function reset()
67
    {
68
        $this->dumps = [];
69
    }
70
 
71
    public function toArray(): array
72
    {
73
        $dumps = [];
74
 
75
        foreach ($this->dumps as $dump) {
76
            $dumps[] = $dump->toArray();
77
        }
78
 
79
        return $dumps;
80
    }
81
 
82
    /*
83
     * Only the `VarDumper` knows how to create the orignal HTML or CLI VarDumper.
84
     * Using reflection and the private VarDumper::register() method we can force it
85
     * to create and register a new VarDumper::$handler before we'll overwrite it.
86
     * Of course, we only need to do this if there isn't a registered VarDumper::$handler.
87
     *
88
     * @throws \ReflectionException
89
     */
90
    protected function ensureOriginalHandlerExists(): void
91
    {
92
        $reflectionProperty = new ReflectionProperty(VarDumper::class, 'handler');
93
        $reflectionProperty->setAccessible(true);
94
        $handler = $reflectionProperty->getValue();
95
 
96
        if (! $handler) {
97
            // No handler registered yet, so we'll force VarDumper to create one.
98
            $reflectionMethod = new ReflectionMethod(VarDumper::class, 'register');
99
            $reflectionMethod->setAccessible(true);
100
            $reflectionMethod->invoke(null);
101
        }
102
    }
103
 
104
    /**
105
     * Find the first meaningful stack frame that is not the `DumpRecorder` itself.
106
     *
107
     * @template T of array{class?: class-string, function?: string, line?: int, file?: string}
108
     *
109
     * @param array<T> $stacktrace
110
     *
111
     * @return null|T
112
     */
113
    protected function findSourceFrame(array $stacktrace): ?array
114
    {
115
        $seenVarDumper = false;
116
 
117
        foreach ($stacktrace as $frame) {
118
            // Keep looping until we're past the VarDumper::dump() call in Symfony's helper functions file.
119
            if (Arr::get($frame, 'class') === VarDumper::class && Arr::get($frame, 'function') === 'dump') {
120
                $seenVarDumper = true;
121
 
122
                continue;
123
            }
124
 
125
            if (! $seenVarDumper) {
126
                continue;
127
            }
128
 
129
            // Return the next frame in the stack after the VarDumper::dump() call:
130
            return $frame;
131
        }
132
 
133
        return null;
134
    }
135
}