1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Yiisoft\Db\Debug; |
||
6 | |||
7 | use Throwable; |
||
8 | use Yiisoft\Yii\Debug\Collector\CollectorTrait; |
||
9 | use Yiisoft\Yii\Debug\Collector\SummaryCollectorInterface; |
||
10 | |||
11 | final class DatabaseCollector implements SummaryCollectorInterface |
||
12 | { |
||
13 | use CollectorTrait; |
||
14 | |||
15 | private const ACTION_QUERY_START = 'query.start'; |
||
16 | private const ACTION_QUERY_END = 'query.end'; |
||
17 | private const ACTION_QUERY_ERROR = 'query.error'; |
||
18 | |||
19 | private const ACTION_TRANSACTION_START = 'transaction.start'; |
||
20 | private const ACTION_TRANSACTION_ROLLBACK = 'transaction.rollback'; |
||
21 | private const ACTION_TRANSACTION_COMMIT = 'transaction.commit'; |
||
22 | |||
23 | private const TRANSACTION_STATUS_COMMIT = 'commit'; |
||
24 | private const TRANSACTION_STATUS_ROLLBACK = 'rollback'; |
||
25 | private const TRANSACTION_STATUS_START = 'start'; |
||
26 | |||
27 | private const QUERY_STATUS_INITIALIZED = 'initialized'; |
||
28 | private const QUERY_STATUS_ERROR = 'error'; |
||
29 | private const QUERY_STATUS_SUCCESS = 'success'; |
||
30 | |||
31 | /** |
||
32 | * @psalm-var array<string, array{ |
||
33 | * rowNumber: int, |
||
34 | * transactionId: int, |
||
35 | * sql: string, |
||
36 | * rawSql: string, |
||
37 | * params: array, |
||
38 | * line: string, |
||
39 | * status: string, |
||
40 | * actions: array<string, mixed> |
||
41 | * }> |
||
42 | */ |
||
43 | private array $queries = []; |
||
44 | /** |
||
45 | * @psalm-var array<int, array{ |
||
46 | * id: int, |
||
47 | * position: int, |
||
48 | * status: string, |
||
49 | * line: string, |
||
50 | * level: string|null, |
||
51 | * actions: array<string, mixed>, |
||
52 | * exception: Throwable|null, |
||
53 | * }> |
||
54 | */ |
||
55 | private array $transactions = []; |
||
56 | |||
57 | private int $position = 0; |
||
58 | private int $currentTransactionId = 0; |
||
59 | |||
60 | /** |
||
61 | * @psalm-suppress InvalidPropertyAssignmentValue |
||
62 | */ |
||
63 | public function collectQueryStart( |
||
64 | string $id, |
||
65 | string $sql, |
||
66 | string $rawSql, |
||
67 | array $params, |
||
68 | string $line, |
||
69 | ): void { |
||
70 | $this->queries[$id] = [ |
||
71 | 'position' => $this->position++, |
||
72 | 'transactionId' => $this->currentTransactionId, |
||
73 | 'sql' => $sql, |
||
74 | 'rawSql' => $rawSql, |
||
75 | 'params' => $params, |
||
76 | 'line' => $line, |
||
77 | 'status' => self::QUERY_STATUS_INITIALIZED, |
||
78 | 'actions' => [ |
||
79 | [ |
||
80 | 'action' => self::ACTION_QUERY_START, |
||
81 | 'time' => microtime(true), |
||
82 | ], |
||
83 | ], |
||
84 | ]; |
||
85 | } |
||
86 | |||
87 | /** |
||
88 | * @psalm-suppress InvalidPropertyAssignmentValue |
||
89 | */ |
||
90 | public function collectQueryEnd( |
||
91 | string $id, |
||
92 | int $rowsNumber, |
||
93 | ): void { |
||
94 | $this->queries[$id]['rowsNumber'] = $rowsNumber; |
||
95 | $this->queries[$id]['status'] = self::QUERY_STATUS_SUCCESS; |
||
96 | $this->queries[$id]['actions'][] = [ |
||
97 | 'action' => self::ACTION_QUERY_END, |
||
98 | 'time' => microtime(true), |
||
99 | ]; |
||
100 | } |
||
101 | |||
102 | /** |
||
103 | * @psalm-suppress InvalidPropertyAssignmentValue |
||
104 | */ |
||
105 | public function collectQueryError( |
||
106 | string $id, |
||
107 | Throwable $exception, |
||
108 | ): void { |
||
109 | $this->queries[$id]['exception'] = $exception; |
||
110 | $this->queries[$id]['status'] = self::QUERY_STATUS_ERROR; |
||
111 | $this->queries[$id]['actions'][] = [ |
||
112 | 'action' => self::ACTION_QUERY_ERROR, |
||
113 | 'time' => microtime(true), |
||
114 | ]; |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * @psalm-suppress InvalidPropertyAssignmentValue |
||
119 | */ |
||
120 | public function collectTransactionStart( |
||
121 | ?string $isolationLevel, |
||
122 | string $line, |
||
123 | ): void { |
||
124 | $id = ++$this->currentTransactionId; |
||
125 | $this->transactions[$id] = [ |
||
126 | 'id' => $id, |
||
127 | 'position' => $this->position++, |
||
128 | 'status' => self::TRANSACTION_STATUS_START, |
||
129 | 'line' => $line, |
||
130 | 'level' => $isolationLevel, |
||
131 | 'actions' => [ |
||
132 | [ |
||
133 | 'action' => self::ACTION_TRANSACTION_START, |
||
134 | 'time' => microtime(true), |
||
135 | ], |
||
136 | ], |
||
137 | ]; |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * @psalm-suppress InvalidPropertyAssignmentValue |
||
142 | */ |
||
143 | public function collectTransactionRollback( |
||
144 | string $line, |
||
145 | ): void { |
||
146 | $this->transactions[$this->currentTransactionId]['status'] = self::TRANSACTION_STATUS_ROLLBACK; |
||
147 | $this->transactions[$this->currentTransactionId]['actions'][] = [ |
||
148 | 'action' => self::ACTION_TRANSACTION_ROLLBACK, |
||
149 | 'line' => $line, |
||
150 | 'time' => microtime(true), |
||
151 | ]; |
||
152 | ++$this->currentTransactionId; |
||
153 | } |
||
154 | |||
155 | /** |
||
156 | * @psalm-suppress InvalidPropertyAssignmentValue |
||
157 | */ |
||
158 | public function collectTransactionCommit( |
||
159 | string $line, |
||
160 | ): void { |
||
161 | $this->transactions[$this->currentTransactionId]['status'] = self::TRANSACTION_STATUS_COMMIT; |
||
162 | $this->transactions[$this->currentTransactionId]['actions'][] = [ |
||
163 | 'action' => self::ACTION_TRANSACTION_COMMIT, |
||
164 | 'line' => $line, |
||
165 | 'time' => microtime(true), |
||
166 | ]; |
||
167 | ++$this->currentTransactionId; |
||
168 | } |
||
169 | |||
170 | public function getCollected(): array |
||
171 | { |
||
172 | $queries = array_values($this->queries); |
||
173 | usort($queries, fn (array $a, array $b) => $a['position'] <=> $b['position']); |
||
174 | |||
175 | return [ |
||
176 | 'queries' => $this->queries, |
||
177 | 'transactions' => $this->transactions, |
||
178 | ]; |
||
179 | } |
||
180 | |||
181 | public function getSummary(): array |
||
182 | { |
||
183 | return [ |
||
184 | 'db' => [ |
||
185 | 'queries' => [ |
||
186 | 'error' => count( |
||
187 | array_filter($this->queries, fn (array $query) => $query['status'] === self::QUERY_STATUS_ERROR) |
||
188 | ), |
||
189 | 'total' => count($this->queries), |
||
190 | ], |
||
191 | 'transactions' => [ |
||
192 | 'error' => count( |
||
193 | array_filter( |
||
194 | $this->transactions, |
||
195 | fn (array $query) => $query['status'] === self::TRANSACTION_STATUS_ROLLBACK |
||
196 | ) |
||
197 | ), |
||
198 | 'total' => count($this->transactions), |
||
199 | ], |
||
200 | ], |
||
201 | ]; |
||
202 | } |
||
203 | |||
204 | private function reset(): void |
||
0 ignored issues
–
show
|
|||
205 | { |
||
206 | $this->queries = []; |
||
207 | $this->transactions = []; |
||
208 | $this->position = 0; |
||
209 | $this->currentTransactionId = 0; |
||
210 | } |
||
211 | } |
||
212 |
This check looks for private methods that have been defined, but are not used inside the class.