Skip to content

Commit 706abee

Browse files
committed
refactor(bootstrapper): simplify query logging and output monitoring setup
- Replace `Dispatcher` with `Event` facade for query logging and output monitoring. - Simplify `getScores` logic using `whenEmpty` for cleaner readability. - Rename `logQuery` to `logQueries` to better reflect functionality. - Remove unnecessary container dependencies in `registerOutputMonitor`. - Streamline method calls for improved consistency and maintainability.
1 parent 52c7a93 commit 706abee

File tree

5 files changed

+73
-107
lines changed

5 files changed

+73
-107
lines changed

baselines/argument.unresolvableType.neon

Lines changed: 0 additions & 8 deletions
This file was deleted.

baselines/loader.neon

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
# total 10 errors
1+
# total 7 errors
22
includes:
3-
- argument.unresolvableType.neon
43
- method.notFound.neon
5-
- method.unresolvableReturnType.neon
64
- offsetAccess.nonArray.neon
75
- offsetAccess.notFound.neon
86
- staticMethod.dynamicCall.neon

baselines/method.unresolvableReturnType.neon

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/Bootstrapper.php

Lines changed: 72 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
use Illuminate\Contracts\Container\Container;
2020
use Illuminate\Contracts\Http\Kernel;
2121
use Illuminate\Database\Events\QueryExecuted;
22-
use Illuminate\Events\Dispatcher;
2322
use Illuminate\Support\Collection;
23+
use Illuminate\Support\Facades\Event;
2424
use Illuminate\Support\Str;
2525
use function Guanguans\LaravelSoar\Support\humanly_milliseconds;
2626
use function Guanguans\LaravelSoar\Support\star_for;
@@ -37,11 +37,6 @@ public function __construct(private Container $container)
3737
self::$scores = collect();
3838
}
3939

40-
public function isBooted(): bool
41-
{
42-
return $this->booted;
43-
}
44-
4540
/**
4641
* @throws BindingResolutionException
4742
*/
@@ -52,58 +47,58 @@ public function boot(): void
5247
}
5348

5449
$this->booted = true;
55-
$this->logQuery($this->container->make(\Illuminate\Contracts\Events\Dispatcher::class));
56-
$this->registerOutputMonitor($this->container);
50+
$this->logQueries();
51+
$this->registerOutputMonitor();
5752
}
5853

5954
/**
6055
* @throws \JsonException
6156
*/
6257
public function getScores(): Collection
6358
{
64-
if (self::$scores->isEmpty()) {
65-
self::$scores = $this->toScores(self::$queries)
59+
return self::$scores = self::$scores->whenEmpty(
60+
fn () => $this->toScores()
6661
->sortBy('Score')
67-
->map(function (array $score): array {
68-
$query = $this->matchQuery(self::$queries, $score);
69-
70-
return [
71-
'Summary' => \sprintf(
72-
'[%s|%d分|%s|%s]',
73-
$star = star_for($score['Score']),
74-
$score['Score'],
75-
$query['time'],
76-
$query['sql']
77-
),
78-
'Basic' => [
79-
'Sample' => $query['sql'],
80-
'Score' => $score['Score'],
81-
'Star' => $star,
82-
'Time' => $query['time'],
83-
'Connection' => $query['connection'],
84-
'Driver' => $query['driver'],
85-
'Tables' => (array) $score['Tables'],
86-
],
87-
'HeuristicRules' => (array) $score['HeuristicRules'],
88-
'IndexRules' => (array) $score['IndexRules'],
89-
'Explain' => $this->sanitizeExplain((array) $score['Explain']),
90-
'Backtraces' => $query['backtraces'],
91-
];
92-
})
93-
->values();
94-
}
62+
->map(fn (array $score): array => $this->hydrateScore($score))
63+
->values()
64+
);
65+
}
9566

96-
return self::$scores;
67+
private function hydrateScore(array $score): array
68+
{
69+
$query = $this->matchQuery($score);
70+
71+
return [
72+
'Summary' => \sprintf(
73+
'[%s|%d分|%s|%s]',
74+
$star = star_for($score['Score']),
75+
$score['Score'],
76+
$query['time'],
77+
$query['sql']
78+
),
79+
'Basic' => [
80+
'Sample' => $query['sql'],
81+
'Score' => $score['Score'],
82+
'Star' => $star,
83+
'Time' => $query['time'],
84+
'Connection' => $query['connection'],
85+
'Driver' => $query['driver'],
86+
'Tables' => (array) $score['Tables'],
87+
],
88+
'HeuristicRules' => (array) $score['HeuristicRules'],
89+
'IndexRules' => (array) $score['IndexRules'],
90+
'Explain' => $this->sanitizeExplain((array) $score['Explain']),
91+
'Backtraces' => $query['backtraces'],
92+
];
9793
}
9894

99-
private function logQuery(Dispatcher $dispatcher): void
95+
private function logQueries(): void
10096
{
101-
// 记录 SQL
102-
$dispatcher->listen(QueryExecuted::class, function (QueryExecuted $queryExecuted): void {
97+
Event::listen(QueryExecuted::class, function (QueryExecuted $queryExecuted): void {
10398
if (
10499
self::$queries->has($queryExecuted->sql)
105100
|| $this->isExceptSql($queryExecuted->sql)
106-
|| $this->isExceptSql($sql = $this->toSql($queryExecuted))
101+
|| $this->isExceptSql($sql = $this->toRawSql($queryExecuted))
107102
) {
108103
return;
109104
}
@@ -126,20 +121,25 @@ private function isExceptSql(string $sql): bool
126121
/**
127122
* @noinspection DebugFunctionUsageInspection
128123
*/
129-
private function toSql(QueryExecuted $queryExecuted): string
124+
private function toRawSql(QueryExecuted $queryExecuted): string
130125
{
126+
if (method_exists($queryExecuted, 'toRawSql')) {
127+
return $queryExecuted->toRawSql();
128+
}
129+
131130
if ([] === $queryExecuted->bindings) {
132131
return $queryExecuted->sql;
133132
}
134133

135-
$sqlWithPlaceholders = str_replace(['%', '?', '%s%s'], ['%%', '%s', '?'], $queryExecuted->sql);
136-
$bindings = $queryExecuted->connection->prepareBindings($queryExecuted->bindings);
137-
$pdo = $queryExecuted->connection->getPdo();
138-
139-
return vsprintf($sqlWithPlaceholders, array_map(
140-
static fn (mixed $binding): string => \is_string($binding) ? $pdo->quote($binding) : var_export($binding, true),
141-
$bindings
142-
));
134+
return vsprintf(
135+
str_replace(['%', '?', '%s%s'], ['%%', '%s', '?'], $queryExecuted->sql),
136+
array_map(
137+
static fn (mixed $binding): string => \is_string($binding)
138+
? $queryExecuted->connection->getPdo()->quote($binding)
139+
: var_export($binding, true),
140+
$queryExecuted->connection->prepareBindings($queryExecuted->bindings)
141+
)
142+
);
143143
}
144144

145145
/**
@@ -166,28 +166,26 @@ private function getBacktraces(int $limit = 0, int $forgetLines = 0): array
166166
/**
167167
* @throws \Illuminate\Contracts\Container\BindingResolutionException
168168
*/
169-
private function registerOutputMonitor(Container $container): void
169+
private function registerOutputMonitor(): void
170170
{
171-
// 注册输出监听
172-
$container->make(\Illuminate\Contracts\Events\Dispatcher::class)->listen(
171+
Event::listen(
173172
CommandFinished::class,
174-
fn (CommandFinished $commandFinished) => $container->make(OutputManager::class)->output(
173+
fn (CommandFinished $commandFinished) => $this->container->make(OutputManager::class)->output(
175174
$this->getScores(),
176175
$commandFinished
177176
)
178177
);
179178

180-
// 注册输出中间件
181-
$container->make(Kernel::class)->pushMiddleware(OutputScoresMiddleware::class);
179+
$this->container->make(Kernel::class)->prependMiddleware(OutputScoresMiddleware::class);
182180
}
183181

184182
/**
185183
* @throws \JsonException
186184
*/
187-
private function toScores(Collection $queries): Collection
185+
private function toScores(): Collection
188186
{
189-
return $queries
190-
->map(static fn (array $query): string => $query['sql'])
187+
return self::$queries
188+
->pluck('sql')
191189
->pipe(static fn (Collection $sqls): Collection => collect(resolve(Soar::class)->arrayScores($sqls->all())));
192190
}
193191

@@ -200,32 +198,27 @@ private function toScores(Collection $queries): Collection
200198
* backtraces: array<string>
201199
* }
202200
*/
203-
private function matchQuery(Collection $queries, array $score): array
201+
private function matchQuery(array $score): array
204202
{
205-
$query = $queries->first(static fn (array $query): bool => $score['Sample'] === $query['sql']);
206-
207-
if ($query) {
208-
return $query;
209-
}
203+
return self::$queries->first(
204+
static fn (array $query): bool => $score['Sample'] === $query['sql'],
205+
static fn (): array => self::$queries
206+
->map(static function (array $query) use ($score): array {
207+
$query['similarity'] = similar_text($score['Sample'], $query['sql']);
210208

211-
// @codeCoverageIgnoreStart
212-
return $queries
213-
->map(static function (array $query) use ($score): array {
214-
$query['similarity'] = similar_text($score['Sample'], $query['sql']);
215-
216-
return $query;
217-
})
218-
->sortByDesc('similarity')
219-
->first();
220-
// @codeCoverageIgnoreEnd
209+
return $query;
210+
})
211+
->sortByDesc('similarity')
212+
->first()
213+
);
221214
}
222215

223216
private function sanitizeExplain(array $explain): array
224217
{
225218
return collect($explain)
226219
->map(static function (array $explain): array {
227-
$explain['Content'] = collect(explode(\PHP_EOL, $explain['Content']))->filter()->values()->all();
228-
$explain['Case'] = collect(explode(\PHP_EOL, $explain['Case']))->filter()->values()->all();
220+
$explain['Content'] = str($explain['Content'])->explode(\PHP_EOL)->filter()->values()->all();
221+
$explain['Case'] = str($explain['Case'])->explode(\PHP_EOL)->filter()->values()->all();
229222

230223
return $explain;
231224
})

tests/BootstrapperTest.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@
2424
$this->bootstrapper = $this->app->make(Bootstrapper::class);
2525
});
2626

27-
it('can return `bool` for `isBooted`', function (): void {
28-
expect($this->bootstrapper)->isBooted()->toBeBool();
29-
})->group(__DIR__, __FILE__);
30-
3127
it('can boot `soar score` for `boot`', function (): void {
3228
expect($this->bootstrapper)->boot()->toBeNull();
3329
})->group(__DIR__, __FILE__);

0 commit comments

Comments
 (0)