Skip to content

Commit 4aa2269

Browse files
committed
Support multiple requests
1 parent 6af8eed commit 4aa2269

File tree

2 files changed

+72
-8
lines changed

2 files changed

+72
-8
lines changed

src/QueryDetector.php

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,29 @@ class QueryDetector
1414
{
1515
/** @var Collection */
1616
private $queries;
17+
/**
18+
* @var bool
19+
*/
20+
private $booted = false;
1721

18-
public function __construct()
22+
private function resetQueries()
1923
{
2024
$this->queries = Collection::make();
2125
}
2226

27+
public function __construct()
28+
{
29+
$this->resetQueries();
30+
}
31+
2332
public function boot()
2433
{
25-
DB::listen(function($query) {
34+
if ($this->booted) {
35+
$this->resetQueries();
36+
return;
37+
}
38+
39+
DB::listen(function ($query) {
2640
$backtrace = collect(debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 50));
2741

2842
$this->logQuery($query, $backtrace);
@@ -32,6 +46,8 @@ public function boot()
3246
app()->singleton($outputType);
3347
app($outputType)->boot();
3448
}
49+
50+
$this->booted = true;
3551
}
3652

3753
public function isEnabled(): bool
@@ -52,13 +68,13 @@ public function logQuery($query, Collection $backtrace)
5268
});
5369

5470
// The query is coming from an Eloquent model
55-
if (! is_null($modelTrace)) {
71+
if (!is_null($modelTrace)) {
5672
/*
5773
* Relations get resolved by either calling the "getRelationValue" method on the model,
5874
* or if the class itself is a Relation.
5975
*/
6076
$relation = $backtrace->first(function ($trace) {
61-
return Arr::get($trace, 'function') === 'getRelationValue' || Arr::get($trace, 'class') === Relation::class ;
77+
return Arr::get($trace, 'function') === 'getRelationValue' || Arr::get($trace, 'class') === Relation::class;
6278
});
6379

6480
// We try to access a relation
@@ -77,8 +93,8 @@ public function logQuery($query, Collection $backtrace)
7793

7894
$key = md5($query->sql . $model . $relationName . $sources[0]->name . $sources[0]->line);
7995

80-
$count = Arr::get($this->queries, $key.'.count', 0);
81-
$time = Arr::get($this->queries, $key.'.time', 0);
96+
$count = Arr::get($this->queries, $key . '.count', 0);
97+
$time = Arr::get($this->queries, $key . '.time', 0);
8298

8399
$this->queries[$key] = [
84100
'count' => ++$count,
@@ -106,7 +122,7 @@ protected function findSource($stack)
106122

107123
public function parseTrace($index, array $trace)
108124
{
109-
$frame = (object) [
125+
$frame = (object)[
110126
'index' => $index,
111127
'name' => null,
112128
'line' => isset($trace['line']) ? $trace['line'] : '?',
@@ -191,7 +207,7 @@ protected function getOutputTypes()
191207
{
192208
$outputTypes = config('querydetector.output');
193209

194-
if (! is_array($outputTypes)) {
210+
if (!is_array($outputTypes)) {
195211
$outputTypes = [$outputTypes];
196212
}
197213

tests/QueryDetectorTest.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,54 @@ public function it_detects_n1_query_on_properties()
3434
$this->assertSame('profile', $queries[0]['relation']);
3535
}
3636

37+
/** @test */
38+
public function it_detects_n1_query_on_multiple_requests()
39+
{
40+
Route::get('/', function (){
41+
$authors = Author::get();
42+
43+
foreach ($authors as $author) {
44+
$author->profile;
45+
}
46+
});
47+
48+
// first request
49+
$this->get('/');
50+
$queries = app(QueryDetector::class)->getDetectedQueries();
51+
$this->assertCount(1, $queries);
52+
$this->assertSame(Author::count(), $queries[0]['count']);
53+
$this->assertSame(Author::class, $queries[0]['model']);
54+
$this->assertSame('profile', $queries[0]['relation']);
55+
56+
// second request
57+
$this->get('/');
58+
$queries = app(QueryDetector::class)->getDetectedQueries();
59+
$this->assertCount(1, $queries);
60+
$this->assertSame(Author::count(), $queries[0]['count']);
61+
$this->assertSame(Author::class, $queries[0]['model']);
62+
$this->assertSame('profile', $queries[0]['relation']);
63+
}
64+
65+
/** @test */
66+
public function it_does_not_detect_a_false_n1_query_on_multiple_requests()
67+
{
68+
Route::get('/', function (){
69+
$authors = Author::with("profile")->get();
70+
71+
foreach ($authors as $author) {
72+
$author->profile;
73+
}
74+
});
75+
76+
// first request
77+
$this->get('/');
78+
$this->assertCount(0, app(QueryDetector::class)->getDetectedQueries());
79+
80+
// second request
81+
$this->get('/');
82+
$this->assertCount(0, app(QueryDetector::class)->getDetectedQueries());
83+
}
84+
3785
/** @test */
3886
public function it_ignores_eager_loaded_relationships()
3987
{

0 commit comments

Comments
 (0)