Skip to content

Commit 6c5280a

Browse files
committed
feat: add cache dependency validation in pdodb init wizard
- Validate cache dependencies after user selects cache type - Show warning with required dependencies for each cache type: - filesystem: symfony/cache package - apcu: ext-apcu extension + symfony/cache package - redis: ext-redis extension + symfony/cache package - memcached: ext-memcached extension + symfony/cache package - Offer fallback to array cache if dependencies are missing - Allow user to disable cache if dependencies are unavailable - Fix PHPStan type issues in InitWizard::testConnection() and askCaching() This prevents silent cache failures when users select cache types without installing required dependencies.
1 parent 65db39a commit 6c5280a

File tree

1 file changed

+64
-5
lines changed

1 file changed

+64
-5
lines changed

src/cli/InitWizard.php

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace tommyknocker\pdodb\cli;
66

7+
use tommyknocker\pdodb\cache\CacheFactory;
78
use tommyknocker\pdodb\cli\commands\InitCommand;
89
use tommyknocker\pdodb\connection\DialectRegistry;
910
use tommyknocker\pdodb\PdoDb;
@@ -296,13 +297,14 @@ protected function testConnection(): void
296297
// Normalize database -> dbname for all dialects (except SQLite which uses 'path')
297298
// All dialects require 'dbname' parameter for buildDsn()
298299
$testConfig = $this->config;
299-
if (($testConfig['driver'] ?? '') !== 'sqlite') {
300+
$driver = isset($testConfig['driver']) && is_string($testConfig['driver']) ? $testConfig['driver'] : null;
301+
if ($driver !== 'sqlite') {
300302
if (isset($testConfig['database']) && !isset($testConfig['dbname'])) {
301303
$testConfig['dbname'] = $testConfig['database'];
302304
}
303305
}
304306

305-
$db = new PdoDb($testConfig['driver'], $testConfig);
307+
$db = new PdoDb($driver, $testConfig);
306308
// Try a simple query
307309
$db->rawQuery('SELECT 1');
308310
static::success('Connection successful!');
@@ -437,7 +439,6 @@ protected function askCaching(): void
437439
if (!in_array($cacheType, $cacheTypes, true)) {
438440
$cacheType = 'filesystem';
439441
}
440-
$this->config['cache']['type'] = $cacheType;
441442

442443
switch ($cacheType) {
443444
case 'filesystem':
@@ -473,11 +474,69 @@ protected function askCaching(): void
473474
break;
474475
}
475476

477+
// Validate cache dependencies
478+
if ($cacheType !== 'array') {
479+
// $this->config['cache'] is always an array after line 432
480+
$cacheSection = $this->config['cache'];
481+
$testCacheConfig = [
482+
'type' => $cacheType,
483+
'directory' => isset($cacheSection['directory']) && is_string($cacheSection['directory']) ? $cacheSection['directory'] : null,
484+
'host' => isset($cacheSection['host']) && is_string($cacheSection['host']) ? $cacheSection['host'] : null,
485+
'port' => isset($cacheSection['port']) && is_int($cacheSection['port']) ? $cacheSection['port'] : null,
486+
'database' => isset($cacheSection['database']) && is_int($cacheSection['database']) ? $cacheSection['database'] : null,
487+
'password' => isset($cacheSection['password']) && is_string($cacheSection['password']) ? $cacheSection['password'] : null,
488+
'servers' => isset($cacheSection['servers']) && is_array($cacheSection['servers']) ? $cacheSection['servers'] : null,
489+
];
490+
$testCache = CacheFactory::create($testCacheConfig);
491+
492+
if ($testCache === null) {
493+
echo "\n";
494+
static::warning("Warning: Cannot create {$cacheType} cache. Required dependencies may be missing:");
495+
switch ($cacheType) {
496+
case 'filesystem':
497+
static::warning(' - symfony/cache package');
498+
break;
499+
case 'apcu':
500+
static::warning(' - ext-apcu extension');
501+
static::warning(' - symfony/cache package');
502+
break;
503+
case 'redis':
504+
static::warning(' - ext-redis extension');
505+
static::warning(' - symfony/cache package');
506+
break;
507+
case 'memcached':
508+
static::warning(' - ext-memcached extension');
509+
static::warning(' - symfony/cache package');
510+
break;
511+
}
512+
echo "\n";
513+
514+
$continue = static::readConfirmation(' Continue anyway? (cache will be disabled)', false);
515+
if (!$continue) {
516+
$this->config['cache'] = ['enabled' => false];
517+
return;
518+
}
519+
// Fallback to array cache
520+
$cacheType = 'array';
521+
static::info(' Falling back to array cache (in-memory only)');
522+
}
523+
}
524+
525+
// Ensure cache config is an array (it should be after line 432, but PHPStan needs this)
526+
if (!is_array($this->config['cache'])) {
527+
$this->config['cache'] = [];
528+
}
529+
/** @var array<string, mixed> $cacheConfig */
530+
$cacheConfig = $this->config['cache'];
531+
$cacheConfig['type'] = $cacheType;
532+
476533
$ttl = static::readInput(' Default cache TTL (seconds)', '3600');
477-
$this->config['cache']['default_lifetime'] = (int)$ttl;
534+
$cacheConfig['default_lifetime'] = (int)$ttl;
478535

479536
$prefix = static::readInput(' Cache key prefix', 'pdodb_');
480-
$this->config['cache']['prefix'] = $prefix !== '' ? $prefix : 'pdodb_';
537+
$cacheConfig['prefix'] = $prefix !== '' ? $prefix : 'pdodb_';
538+
539+
$this->config['cache'] = $cacheConfig;
481540
}
482541

483542
/**

0 commit comments

Comments
 (0)