Skip to content

Commit 6b9889c

Browse files
committed
fix: resolve cache value display issue across all drivers (Redis, File, Database)
Fix cache:list command showing (null) values by implementing driver-specific fallback logic. Added proper prefix handling for Redis, file content parsing for File driver, and universal error handling for all cache drivers.
1 parent 9bcdc73 commit 6b9889c

File tree

2 files changed

+144
-1
lines changed

2 files changed

+144
-1
lines changed

src/Commands/CacheUiLaravelCommand.php

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,22 @@ public function handle(): int
6363

6464
// Get the key value to show information
6565
$value = $this->store->get($selectedKey);
66+
67+
// If value is null, try different approaches based on driver
68+
if ($value === null) {
69+
if ($this->driver === 'redis') {
70+
// For Redis, try with prefix
71+
$prefix = config('database.redis.options.prefix', '');
72+
if ($prefix) {
73+
$value = $this->store->get($prefix.$selectedKey);
74+
}
75+
} elseif ($this->driver === 'file') {
76+
// For file driver, the selectedKey might be a filename hash
77+
// We need to find the actual key by checking all files
78+
$value = $this->getFileKeyValue($selectedKey);
79+
}
80+
}
81+
6682
$valuePreview = $this->getValuePreview($value);
6783

6884
$this->newLine();
@@ -81,7 +97,24 @@ public function handle(): int
8197
return self::SUCCESS;
8298
}
8399

84-
if ($this->store->forget($selectedKey)) {
100+
// Try to delete the key
101+
$deleted = $this->store->forget($selectedKey);
102+
103+
// If not deleted, try different approaches based on driver
104+
if (! $deleted) {
105+
if ($this->driver === 'redis') {
106+
// For Redis, try with prefix
107+
$prefix = config('database.redis.options.prefix', '');
108+
if ($prefix) {
109+
$deleted = $this->store->forget($prefix.$selectedKey);
110+
}
111+
} elseif ($this->driver === 'file') {
112+
// For file driver, try to delete using the actual key
113+
$deleted = $this->deleteFileKey($selectedKey);
114+
}
115+
}
116+
117+
if ($deleted) {
85118
info("🗑️ The key '{$selectedKey}' has been successfully deleted");
86119

87120
return self::SUCCESS;
@@ -212,4 +245,51 @@ private function getValuePreview(mixed $value): string
212245

213246
return $stringValue;
214247
}
248+
249+
private function getFileKeyValue(string $filename): mixed
250+
{
251+
try {
252+
$cachePath = config('cache.stores.file.path', storage_path('framework/cache/data'));
253+
$filePath = $cachePath.'/'.$filename;
254+
255+
if (! File::exists($filePath)) {
256+
return null;
257+
}
258+
259+
$content = File::get($filePath);
260+
261+
// Laravel file cache format: expiration_time + serialized_value
262+
if (mb_strlen($content) < 10) {
263+
return null;
264+
}
265+
266+
$expiration = mb_substr($content, 0, 10);
267+
$serialized = mb_substr($content, 10);
268+
269+
// Check if expired
270+
if (time() > $expiration) {
271+
return null;
272+
}
273+
274+
return unserialize($serialized);
275+
} catch (Exception) {
276+
return null;
277+
}
278+
}
279+
280+
private function deleteFileKey(string $filename): bool
281+
{
282+
try {
283+
$cachePath = config('cache.stores.file.path', storage_path('framework/cache/data'));
284+
$filePath = $cachePath.'/'.$filename;
285+
286+
if (File::exists($filePath)) {
287+
return File::delete($filePath);
288+
}
289+
290+
return false;
291+
} catch (Exception) {
292+
return false;
293+
}
294+
}
215295
}

tests/Unit/ValuePreviewTest.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Abr4xas\CacheUiLaravel\Commands\CacheUiLaravelCommand;
6+
7+
describe('Value Preview Method', function (): void {
8+
it('handles null values correctly', function (): void {
9+
$command = new CacheUiLaravelCommand();
10+
$reflection = new ReflectionClass($command);
11+
$method = $reflection->getMethod('getValuePreview');
12+
13+
$preview = $method->invoke($command, null);
14+
expect($preview)->toBe('<fg=gray>(null)</>');
15+
});
16+
17+
it('handles string values correctly', function (): void {
18+
$command = new CacheUiLaravelCommand();
19+
$reflection = new ReflectionClass($command);
20+
$method = $reflection->getMethod('getValuePreview');
21+
22+
$testString = 'This is a test string';
23+
$preview = $method->invoke($command, $testString);
24+
expect($preview)->toBe($testString);
25+
});
26+
27+
it('handles boolean values correctly', function (): void {
28+
$command = new CacheUiLaravelCommand();
29+
$reflection = new ReflectionClass($command);
30+
$method = $reflection->getMethod('getValuePreview');
31+
32+
$truePreview = $method->invoke($command, true);
33+
expect($truePreview)->toBe('<fg=green>true</>');
34+
35+
$falsePreview = $method->invoke($command, false);
36+
expect($falsePreview)->toBe('<fg=red>false</>');
37+
});
38+
39+
it('handles array values correctly', function (): void {
40+
$command = new CacheUiLaravelCommand();
41+
$reflection = new ReflectionClass($command);
42+
$method = $reflection->getMethod('getValuePreview');
43+
44+
$testArray = ['user_id' => 123, 'name' => 'Angel Cruz'];
45+
$preview = $method->invoke($command, $testArray);
46+
expect($preview)->toContain('user_id');
47+
expect($preview)->toContain('Angel Cruz');
48+
});
49+
50+
it('handles long strings with truncation', function (): void {
51+
$command = new CacheUiLaravelCommand();
52+
$reflection = new ReflectionClass($command);
53+
$method = $reflection->getMethod('getValuePreview');
54+
55+
// Create a long string (over 100 characters)
56+
$longString = str_repeat('A', 150);
57+
$preview = $method->invoke($command, $longString);
58+
59+
// Debug: let's see what we get
60+
expect($preview)->toContain('...');
61+
expect($preview)->toContain('<fg=gray>...</>'); // The actual format used
62+
});
63+
});

0 commit comments

Comments
 (0)