Skip to content

Commit 20b2c0f

Browse files
Add non regression test
1 parent a6421af commit 20b2c0f

1 file changed

Lines changed: 89 additions & 0 deletions

File tree

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Shopware\Core\Profiling\Doctrine;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Data {}
8+
class ParameterType {}
9+
10+
/**
11+
* @phpstan-type Backtrace list<array{function: string, line?: int, file?: string, class?: class-string, type?: '->'|'::', args?: list<mixed>, object?: object}>
12+
* @phpstan-type QueryInfo array{
13+
* sql: string,
14+
* executionMS: float,
15+
* types: array<int|string, int>,
16+
* params: array<mixed>,
17+
* backtrace?: Backtrace
18+
* }
19+
* @phpstan-type SanitizedQueryInfo array{sql: string, executionMS: float, types: array<(int | string), ParameterType|int>, params: Data, runnable: bool, explainable: bool, backtrace?: Backtrace}
20+
* @phpstan-type SanitizedQueryInfoGroup array{sql: string, executionMS: float, types: array<(int | string), ParameterType|int>, params: Data, runnable: bool, explainable: bool, backtrace?: Backtrace, count: int, index: int, executionPercent?: float}
21+
*/
22+
abstract class ConnectionProfiler
23+
{
24+
/**
25+
* @var ?array<string, array<int, SanitizedQueryInfoGroup>>
26+
*/
27+
public ?array $groupedQueries = null;
28+
29+
/**
30+
* @return array<string, array<int, SanitizedQueryInfo>>
31+
*/
32+
abstract public function getQueries(): array;
33+
34+
/**
35+
* @return array<string, array<int, SanitizedQueryInfoGroup>>
36+
*/
37+
public function getGroupedQueries(): array
38+
{
39+
if ($this->groupedQueries !== null) {
40+
return $this->groupedQueries;
41+
}
42+
43+
$this->groupedQueries = [];
44+
$totalExecutionMS = 0;
45+
foreach ($this->getQueries() as $connection => $queries) {
46+
$connectionGroupedQueries = [];
47+
foreach ($queries as $i => $query) {
48+
$key = $query['sql'];
49+
if (!isset($connectionGroupedQueries[$key])) {
50+
$connectionGroupedQueries[$key] = $query;
51+
$connectionGroupedQueries[$key]['executionMS'] = 0;
52+
$connectionGroupedQueries[$key]['count'] = 0;
53+
$connectionGroupedQueries[$key]['index'] = $i; // "Explain query" relies on query index in 'queries'.
54+
}
55+
56+
assertType("array<string, array{sql: string, executionMS: 0, types: array<int|string, int|Shopware\Core\Profiling\Doctrine\ParameterType>, params: Shopware\Core\Profiling\Doctrine\Data, runnable: bool, explainable: bool, backtrace?: list<array{function: string, line?: int, file?: string, class?: class-string, type?: '->'|'::', args?: list<mixed>, object?: object}>, count: 0, index: int}|array{sql: string, executionMS: float, types: array<int|string, int|Shopware\Core\Profiling\Doctrine\ParameterType>, params: Shopware\Core\Profiling\Doctrine\Data, runnable: bool, explainable: bool, backtrace?: list<array{function: string, line?: int, file?: string, class?: class-string, type?: '->'|'::', args?: list<mixed>, object?: object}>, count: int<1, max>, index: int}>", $connectionGroupedQueries);
57+
$connectionGroupedQueries[$key]['executionMS'] += $query['executionMS'];
58+
assertType("non-empty-array<string, array{sql: string, executionMS: float, types: array<int|string, int|Shopware\Core\Profiling\Doctrine\ParameterType>, params: Shopware\Core\Profiling\Doctrine\Data, runnable: bool, explainable: bool, backtrace?: list<array{function: string, line?: int, file?: string, class?: class-string, type?: '->'|'::', args?: list<mixed>, object?: object}>, count: int<0, max>, index: int}>", $connectionGroupedQueries);
59+
++$connectionGroupedQueries[$key]['count'];
60+
$totalExecutionMS += $query['executionMS'];
61+
}
62+
63+
assertType("array<string, array{sql: string, executionMS: float, types: array<int|string, int|Shopware\Core\Profiling\Doctrine\ParameterType>, params: Shopware\Core\Profiling\Doctrine\Data, runnable: bool, explainable: bool, backtrace?: list<array{function: string, line?: int, file?: string, class?: class-string, type?: '->'|'::', args?: list<mixed>, object?: object}>, count: int<1, max>, index: int}>", $connectionGroupedQueries);
64+
usort($connectionGroupedQueries, static fn (array $a, array $b): int => $b['executionMS'] <=> $a['executionMS']);
65+
$this->groupedQueries[$connection] = $connectionGroupedQueries;
66+
}
67+
68+
foreach ($this->groupedQueries as &$queries) {
69+
foreach ($queries as &$query) {
70+
$query['executionPercent'] = $this->executionTimePercentage($query['executionMS'], $totalExecutionMS);
71+
}
72+
unset($query);
73+
}
74+
unset($queries);
75+
76+
assertType("list<array{sql: string, executionMS: float, types: array<int|string, int|Shopware\Core\Profiling\Doctrine\ParameterType>, params: Shopware\Core\Profiling\Doctrine\Data, runnable: bool, explainable: bool, backtrace?: list<array{function: string, line?: int, file?: string, class?: class-string, type?: '->'|'::', args?: list<mixed>, object?: object}>, count: int<1, max>, index: int}>", $connectionGroupedQueries);
77+
78+
return $this->groupedQueries;
79+
}
80+
81+
private function executionTimePercentage(float $executionTimeMS, float $totalExecutionTimeMS): float
82+
{
83+
if (!$totalExecutionTimeMS) {
84+
return 0;
85+
}
86+
87+
return $executionTimeMS / $totalExecutionTimeMS * 100;
88+
}
89+
}

0 commit comments

Comments
 (0)