Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
87.50% |
105 / 120 |
|
64.29% |
9 / 14 |
CRAP | |
0.00% |
0 / 1 |
Database | |
87.50% |
105 / 120 |
|
64.29% |
9 / 14 |
40.82 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
setDb | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getDb | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getTable | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setTable | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
save | |
74.07% |
20 / 27 |
|
0.00% |
0 / 1 |
3.16 | |||
getById | |
90.91% |
20 / 22 |
|
0.00% |
0 / 1 |
9.06 | |||
getByType | |
86.67% |
13 / 15 |
|
0.00% |
0 / 1 |
4.04 | |||
has | |
83.33% |
10 / 12 |
|
0.00% |
0 / 1 |
4.07 | |||
delete | |
80.00% |
8 / 10 |
|
0.00% |
0 / 1 |
3.07 | |||
clear | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
encodeValue | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
decodeValue | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
createTable | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * Pop PHP Framework (http://www.popphp.org/) |
4 | * |
5 | * @link https://github.com/popphp/popphp-framework |
6 | * @author Nick Sagona, III <dev@nolainteractive.com> |
7 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
8 | * @license http://www.popphp.org/license New BSD License |
9 | */ |
10 | |
11 | /** |
12 | * @namespace |
13 | */ |
14 | namespace Pop\Debug\Storage; |
15 | |
16 | use Pop\Db\Adapter\AbstractAdapter; |
17 | |
18 | /** |
19 | * Debug database storage class |
20 | * |
21 | * @category Pop |
22 | * @package Pop\Debug |
23 | * @author Nick Sagona, III <dev@nolainteractive.com> |
24 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
25 | * @license http://www.popphp.org/license New BSD License |
26 | * @version 2.2.0 |
27 | */ |
28 | class Database extends AbstractStorage |
29 | { |
30 | |
31 | /** |
32 | * DB adapter |
33 | * @var ?AbstractAdapter |
34 | */ |
35 | protected ?AbstractAdapter $db = null; |
36 | |
37 | /** |
38 | * Table |
39 | * @var string |
40 | */ |
41 | protected string $table = 'pop_debug'; |
42 | |
43 | /** |
44 | * Constructor |
45 | * |
46 | * Instantiate the DB writer object |
47 | * |
48 | * The DB table requires the following fields at a minimum: |
49 | |
50 | * id INT |
51 | * value TEXT, VARCHAR, etc. |
52 | * |
53 | * @param AbstractAdapter $db |
54 | * @param string $format |
55 | * @param string $table |
56 | */ |
57 | public function __construct(AbstractAdapter $db, string $format = 'text', string $table = 'pop_debug') |
58 | { |
59 | parent::__construct($format); |
60 | |
61 | $this->setDb($db); |
62 | $this->setTable($table); |
63 | |
64 | if (!$db->hasTable($this->table)) { |
65 | $this->createTable(); |
66 | } |
67 | } |
68 | |
69 | /** |
70 | * Set the current debug db adapter. |
71 | * |
72 | * @param AbstractAdapter $db |
73 | * @return Database |
74 | */ |
75 | public function setDb(AbstractAdapter $db): Database |
76 | { |
77 | $this->db = $db; |
78 | return $this; |
79 | } |
80 | |
81 | /** |
82 | * Get the current debug db adapter. |
83 | * |
84 | * @return ?AbstractAdapter |
85 | */ |
86 | public function getDb(): ?AbstractAdapter |
87 | { |
88 | return $this->db; |
89 | } |
90 | |
91 | /** |
92 | * Get the current debug db table. |
93 | * |
94 | * @return string |
95 | */ |
96 | public function getTable(): string |
97 | { |
98 | return $this->table; |
99 | } |
100 | |
101 | /** |
102 | * Set the debug db table |
103 | * |
104 | * @param string $table |
105 | * @return Database |
106 | */ |
107 | public function setTable(string $table): Database |
108 | { |
109 | $this->table = $table; |
110 | return $this; |
111 | } |
112 | |
113 | /** |
114 | * Save debug data |
115 | * |
116 | * @param string $id |
117 | * @param mixed $value |
118 | * @return void |
119 | */ |
120 | public function save(string $id, mixed $value): void |
121 | { |
122 | $sql = $this->db->createSql(); |
123 | $sql->reset(); |
124 | $placeholder = $sql->getPlaceholder(); |
125 | |
126 | if ($placeholder == ':') { |
127 | $placeholder1 = ':key'; |
128 | $placeholder2 = ':value'; |
129 | $placeholder3 = ':timestamp'; |
130 | } else if ($placeholder == '$') { |
131 | $placeholder1 = '$1'; |
132 | $placeholder2 = '$2'; |
133 | $placeholder3 = '$3'; |
134 | } else { |
135 | $placeholder1 = $placeholder; |
136 | $placeholder2 = $placeholder; |
137 | $placeholder3 = $placeholder; |
138 | } |
139 | |
140 | $sql->insert($this->table)->values([ |
141 | 'key' => $placeholder1, |
142 | 'value' => $placeholder2, |
143 | 'timestamp' => $placeholder3 |
144 | ]); |
145 | $params = [ |
146 | 'key' => $id, |
147 | 'value' => $this->encodeValue($value), |
148 | 'timestamp' => date('Y-m-d H:i:s') |
149 | ]; |
150 | |
151 | // Save value |
152 | $this->db->prepare($sql) |
153 | ->bindParams($params) |
154 | ->execute(); |
155 | } |
156 | |
157 | /** |
158 | * Get debug data by ID |
159 | * |
160 | * @param string $id |
161 | * @return mixed |
162 | */ |
163 | public function getById(string $id): mixed |
164 | { |
165 | $sql = $this->db->createSql(); |
166 | $placeholder = $sql->getPlaceholder(); |
167 | $value = false; |
168 | $isWildcard = false; |
169 | |
170 | if ($placeholder == ':') { |
171 | $placeholder .= 'key'; |
172 | } else if ($placeholder == '$') { |
173 | $placeholder .= '1'; |
174 | } |
175 | |
176 | if (str_ends_with($id, '*') || str_ends_with($id, '%')) { |
177 | $sql->select()->from($this->table)->where('key LIKE ' . $placeholder); |
178 | $id = substr($id, 0, -1) . '%'; |
179 | $isWildcard = true; |
180 | } else { |
181 | $sql->select()->from($this->table)->where('key = ' . $placeholder); |
182 | } |
183 | |
184 | $this->db->prepare($sql) |
185 | ->bindParams(['key' => $id]) |
186 | ->execute(); |
187 | |
188 | $rows = $this->db->fetchAll(); |
189 | |
190 | // If the value is found, return. |
191 | if (($isWildcard) && isset($rows[0])) { |
192 | $value = $rows; |
193 | } else if (isset($rows[0]) && isset($rows[0]['value'])) { |
194 | $value = $this->decodeValue($rows[0]['value']); |
195 | } |
196 | |
197 | return $value; |
198 | } |
199 | |
200 | /** |
201 | * Get debug data by type |
202 | * |
203 | * @param string $type |
204 | * @return mixed |
205 | */ |
206 | public function getByType(string $type): mixed |
207 | { |
208 | $sql = $this->db->createSql(); |
209 | $placeholder = $sql->getPlaceholder(); |
210 | $value = false; |
211 | |
212 | if ($placeholder == ':') { |
213 | $placeholder .= 'key'; |
214 | } else if ($placeholder == '$') { |
215 | $placeholder .= '1'; |
216 | } |
217 | |
218 | $sql->select()->from($this->table)->where('key LIKE ' . $placeholder); |
219 | $this->db->prepare($sql) |
220 | ->bindParams(['key' => '%' . $type]) |
221 | ->execute(); |
222 | |
223 | $rows = $this->db->fetchAll(); |
224 | |
225 | // If the value is found, return. |
226 | if (isset($rows[0])) { |
227 | $value = $rows; |
228 | } |
229 | |
230 | return $value; |
231 | } |
232 | |
233 | /** |
234 | * Determine if debug data exists by ID |
235 | * |
236 | * @param string $id |
237 | * @return bool |
238 | */ |
239 | public function has(string $id): bool |
240 | { |
241 | $sql = $this->db->createSql(); |
242 | $placeholder = $sql->getPlaceholder(); |
243 | |
244 | if ($placeholder == ':') { |
245 | $placeholder .= 'key'; |
246 | } else if ($placeholder == '$') { |
247 | $placeholder .= '1'; |
248 | } |
249 | |
250 | $sql->select()->from($this->table)->where('key = ' . $placeholder); |
251 | |
252 | $this->db->prepare($sql) |
253 | ->bindParams(['key' => $id]) |
254 | ->execute(); |
255 | |
256 | $rows = $this->db->fetchAll(); |
257 | |
258 | return (isset($rows[0]) && isset($rows[0]['value'])); |
259 | } |
260 | |
261 | /** |
262 | * Delete debug data by ID |
263 | * |
264 | * @param string $id |
265 | * @return void |
266 | */ |
267 | public function delete(string $id): void |
268 | { |
269 | $sql = $this->db->createSql(); |
270 | $placeholder = $sql->getPlaceholder(); |
271 | |
272 | if ($placeholder == ':') { |
273 | $placeholder .= 'key'; |
274 | } else if ($placeholder == '$') { |
275 | $placeholder .= '1'; |
276 | } |
277 | |
278 | $sql->delete($this->table)->where('key = ' . $placeholder); |
279 | |
280 | $this->db->prepare($sql) |
281 | ->bindParams(['key' => $id]) |
282 | ->execute(); |
283 | } |
284 | |
285 | /** |
286 | * Clear all debug data |
287 | * |
288 | * @return void |
289 | */ |
290 | public function clear(): void |
291 | { |
292 | $sql = $this->db->createSql(); |
293 | $sql->delete($this->table); |
294 | $this->db->query($sql); |
295 | } |
296 | |
297 | /** |
298 | * Encode the value based on the format |
299 | * |
300 | * @param mixed $value |
301 | * @throws Exception |
302 | * @return string |
303 | */ |
304 | public function encodeValue(mixed $value): string |
305 | { |
306 | if ($this->format == self::JSON) { |
307 | $value = json_encode($value, JSON_PRETTY_PRINT); |
308 | } else if ($this->format == self::PHP) { |
309 | $value = serialize($value); |
310 | } else if (!is_string($value)) { |
311 | throw new Exception('Error: The value must be a string if storing in text format.'); |
312 | } |
313 | |
314 | return $value; |
315 | } |
316 | |
317 | /** |
318 | * Decode the value based on the format |
319 | * |
320 | * @param mixed $value |
321 | * @return mixed |
322 | */ |
323 | public function decodeValue(mixed $value): mixed |
324 | { |
325 | if ($this->format == self::JSON) { |
326 | $value = json_decode($value, true); |
327 | } else if ($this->format == self::PHP) { |
328 | $value = unserialize($value); |
329 | } |
330 | |
331 | return $value; |
332 | } |
333 | |
334 | /** |
335 | * Create table in database |
336 | * |
337 | * @return void |
338 | */ |
339 | protected function createTable(): void |
340 | { |
341 | $schema = $this->db->createSchema(); |
342 | $schema->create($this->table) |
343 | ->int('id')->increment() |
344 | ->varchar('key', 255) |
345 | ->text('value') |
346 | ->datetime('timestamp') |
347 | ->primary('id'); |
348 | |
349 | $this->db->query($schema); |
350 | } |
351 | |
352 | } |