Skip to content

Commit a63fe58

Browse files
committed
Add tree view to memcached & apcu
1 parent 1fccd35 commit a63fe58

File tree

6 files changed

+187
-31
lines changed

6 files changed

+187
-31
lines changed

config.dist.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@
5252
'host' => '127.0.0.1', // Optional when a path is specified.
5353
'port' => 11211, // Optional when the default port is used.
5454
//'path' => '/var/run/memcached/memcached.sock', // Unix domain socket (optional).
55+
//'separator' => ':', // Separator for tree view (optional)
5556
],
5657
],
58+
//'apcu-separator' => ':', // Separator for tree view (optional)
5759
// Example of authentication with http auth.
5860
/*'auth' => static function (): void {
5961
$username = 'admin';

src/Dashboards/APCu/APCuTrait.php

Lines changed: 94 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -181,35 +181,115 @@ private function form(): string {
181181
* @return array<int, array<string, string|int>>
182182
*/
183183
private function getAllKeys(): array {
184-
static $keys = [];
185184
$search = Http::get('s', '');
186-
187185
$this->template->addGlobal('search_value', $search);
188186

189187
$info = apcu_cache_info();
188+
$keys = [];
189+
$time = time();
190190

191191
foreach ($info['cache_list'] as $key_data) {
192192
$key = $key_data['info'];
193193

194194
if (stripos($key, $search) !== false) {
195195
$keys[] = [
196-
'key' => $key,
197-
'base64' => true,
198-
'info' => [
199-
'link_title' => $key,
200-
'bytes_size' => $key_data['mem_size'],
201-
'number_hits' => $key_data['num_hits'],
202-
'timediff_last_used' => $key_data['access_time'],
203-
'time_created' => $key_data['creation_time'],
204-
'ttl' => $key_data['ttl'] === 0 ? 'Doesn\'t expire' : $key_data['creation_time'] + $key_data['ttl'] - time(),
205-
],
196+
'key' => $key,
197+
'mem_size' => $key_data['mem_size'],
198+
'num_hits' => $key_data['num_hits'],
199+
'access_time' => $key_data['access_time'],
200+
'creation_time' => $key_data['creation_time'],
201+
'ttl' => $key_data['ttl'] === 0 ? 'Doesn\'t expire' : $key_data['creation_time'] + $key_data['ttl'] - $time,
206202
];
207203
}
208204
}
209205

210-
$keys = Helpers::sortKeys($this->template, $keys);
206+
if (Http::get('view', 'table') === 'tree') {
207+
return $this->keysTreeView($keys);
208+
}
209+
210+
return $this->keysTableView($keys);
211+
}
212+
213+
/**
214+
* @param array<int|string, mixed> $keys
215+
*
216+
* @return array<int, array<string, string|int>>
217+
*/
218+
private function keysTableView(array $keys): array {
219+
$formatted_keys = [];
220+
221+
foreach ($keys as $key_data) {
222+
$formatted_keys[] = [
223+
'key' => $key_data['key'],
224+
'base64' => true,
225+
'info' => [
226+
'link_title' => $key_data['key'],
227+
'bytes_size' => $key_data['mem_size'],
228+
'number_hits' => $key_data['num_hits'],
229+
'timediff_last_used' => $key_data['access_time'],
230+
'time_created' => $key_data['creation_time'],
231+
'ttl' => $key_data['ttl'],
232+
],
233+
];
234+
}
235+
236+
return Helpers::sortKeys($this->template, $formatted_keys);
237+
}
238+
239+
/**
240+
* @param array<int|string, mixed> $keys
241+
*
242+
* @return array<int, array<string, string|int>>
243+
*/
244+
private function keysTreeView(array $keys): array {
245+
$separator = Config::get('apcu-separator', ':');
246+
$this->template->addGlobal('separator', $separator);
247+
248+
$tree = [];
249+
250+
foreach ($keys as $key_data) {
251+
$key = $key_data['key'];
252+
$parts = explode($separator, $key);
253+
254+
/** @var array<int|string, mixed> $current */
255+
$current = &$tree;
256+
$path = '';
257+
258+
foreach ($parts as $i => $part) {
259+
$path = $path ? $path.$separator.$part : $part;
260+
261+
if ($i === count($parts) - 1) { // check last part
262+
$current[] = [
263+
'type' => 'key',
264+
'name' => $part,
265+
'key' => $key,
266+
'base64' => true,
267+
'info' => [
268+
'bytes_size' => $key_data['mem_size'],
269+
'number_hits' => $key_data['num_hits'],
270+
'timediff_last_used' => $key_data['access_time'],
271+
'time_created' => $key_data['creation_time'],
272+
'ttl' => $key_data['ttl'],
273+
],
274+
];
275+
} else {
276+
if (!isset($current[$part])) {
277+
$current[$part] = [
278+
'type' => 'folder',
279+
'name' => $part,
280+
'path' => $path,
281+
'children' => [],
282+
'expanded' => false,
283+
];
284+
}
285+
$current = &$current[$part]['children'];
286+
}
287+
}
288+
}
289+
290+
Helpers::countChildren($tree);
211291

212-
return $keys;
292+
return $tree;
213293
}
214294

215295
private function mainDashboard(): string {

src/Dashboards/Memcached/MemcachedTrait.php

Lines changed: 88 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -198,40 +198,111 @@ private function form(): string {
198198

199199
/**
200200
* @return array<int, array<string, string|int>>
201+
*
201202
* @throws MemcachedException
202203
*/
203204
private function getAllKeys(): array {
204-
static $keys = [];
205205
$search = Http::get('s', '');
206-
207206
$this->template->addGlobal('search_value', $search);
208207

209-
$time = time();
210-
211208
$all_keys = $this->memcached->getKeys();
209+
$keys = [];
210+
$time = time();
212211

213212
foreach ($all_keys as $key_data) {
214213
$key_data = $this->memcached->parseLine($key_data);
215-
$key = $key_data['key'];
216-
217-
if (stripos($key, $search) !== false) {
218-
$ttl = $key_data['exp'] ?? null;
214+
$ttl = $key_data['exp'] ?? null;
219215

216+
if (stripos($key_data['key'], $search) !== false) {
220217
$keys[] = [
221-
'key' => $key,
222-
'info' => [
223-
'link_title' => urldecode($key),
224-
'bytes_size' => $key_data['size'],
225-
'timediff_last_access' => $key_data['la'],
226-
'ttl' => $ttl === -1 ? 'Doesn\'t expire' : $ttl - $time,
227-
],
218+
'key' => $key_data['key'],
219+
'size' => $key_data['size'],
220+
'la' => $key_data['la'] ?? 0,
221+
'ttl' => $ttl === -1 ? 'Doesn\'t expire' : $ttl - $time,
228222
];
229223
}
230224
}
231225

232-
$keys = Helpers::sortKeys($this->template, $keys);
226+
if (Http::get('view', 'table') === 'tree') {
227+
return $this->keysTreeView($keys);
228+
}
229+
230+
return $this->keysTableView($keys);
231+
}
232+
233+
/**
234+
* @param array<int|string, mixed> $keys
235+
*
236+
* @return array<int, array<string, string|int>>
237+
*/
238+
private function keysTableView(array $keys): array {
239+
$formatted_keys = [];
240+
241+
foreach ($keys as $key_data) {
242+
$formatted_keys[] = [
243+
'key' => $key_data['key'],
244+
'info' => [
245+
'link_title' => urldecode($key_data['key']),
246+
'bytes_size' => $key_data['size'],
247+
'timediff_last_access' => $key_data['la'],
248+
'ttl' => $key_data['ttl'],
249+
],
250+
];
251+
}
252+
253+
return Helpers::sortKeys($this->template, $formatted_keys);
254+
}
255+
256+
/**
257+
* @param array<int|string, mixed> $keys
258+
*
259+
* @return array<int, array<string, string|int>>
260+
*/
261+
private function keysTreeView(array $keys): array {
262+
$separator = urlencode($this->servers[$this->current_server]['separator'] ?? ':');
263+
$this->template->addGlobal('separator', urldecode($separator));
264+
265+
$tree = [];
266+
267+
foreach ($keys as $key_data) {
268+
$parts = explode($separator, $key_data['key']);
269+
270+
/** @var array<int|string, mixed> $current */
271+
$current = &$tree;
272+
$path = '';
273+
274+
foreach ($parts as $i => $part) {
275+
$path = $path ? $path.$separator.$part : $part;
276+
277+
if ($i === count($parts) - 1) { // check last part
278+
$current[] = [
279+
'type' => 'key',
280+
'name' => urldecode($part),
281+
'key' => $key_data['key'],
282+
'info' => [
283+
'bytes_size' => $key_data['size'],
284+
'timediff_last_access' => $key_data['la'],
285+
'ttl' => $key_data['ttl'],
286+
],
287+
];
288+
} else {
289+
if (!isset($current[$part])) {
290+
$current[$part] = [
291+
'type' => 'folder',
292+
'name' => $part,
293+
'path' => $path,
294+
'children' => [],
295+
'expanded' => false,
296+
];
297+
}
298+
$current = &$current[$part]['children'];
299+
}
300+
}
301+
}
302+
303+
Helpers::countChildren($tree);
233304

234-
return $keys;
305+
return $tree;
235306
}
236307

237308
private function commandsStats(): string {

src/Dashboards/Memcached/PHPMem.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ public function getKey(string $key): string|false {
158158
* Get key meta-data.
159159
*
160160
* @return array<string, string|int>
161+
*
161162
* @throws MemcachedException
162163
*/
163164
public function getKeyMeta(string $key): array {

templates/dashboards/apcu.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{{ include('partials/keys_list.twig', {
2+
treeview: true,
23
buttons: {
34
import_btn: true,
45
export_btn: true,

templates/dashboards/memcached.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
{% if get('tab', 'keys') == 'keys' %}
99
{{ include('partials/keys_list.twig', {
10+
treeview: true,
1011
buttons: {
1112
import_btn: true,
1213
export_btn: true,

0 commit comments

Comments
 (0)