Swapping Service Implementations
When you need to change from in-memory cache to Redis, or from file logging to database logging, use the driver system to swap implementations without changing your code.
Setting Which Driver to Use
Section titled “Setting Which Driver to Use”Configure which implementation to use through environment variables:
CACHE_DRIVER=memoryLOG_DRIVER=streamThe service resolves the configured driver automatically:
app()->get('/test', function(Cache $cache, Logger $logger) { $cache->set('key', 'value'); // Uses CACHE_DRIVER $logger->info('Logged'); // Uses LOG_DRIVER
return 'ok';});Registering Your Own Drivers
Section titled “Registering Your Own Drivers”Add custom driver implementations for any service:
use App\Cache\RedisCache;
app()->driver('cache', 'redis', function(App $app) { return new RedisCache($app->env('REDIS_URL'));});Now you can set CACHE_DRIVER=redis to use it.
Getting the Configured Driver
Section titled “Getting the Configured Driver”Resolve the active driver instance directly:
// Reads CACHE_DRIVER env var and returns that driver$cache = app()->driver('cache');The driver system reads the {SERVICE}_DRIVER environment variable (like CACHE_DRIVER), falls back to the default if not set, and returns the driver instance.
Built-in Cache Drivers
Section titled “Built-in Cache Drivers”Verge includes a memory driver that stores cache data for the current request:
CACHE_DRIVER=memoryThis is registered by default:
use Verge\Cache\Drivers\MemoryCacheDriver;
app()->driver('cache', 'memory', fn() => new MemoryCacheDriver());Adding a Redis Cache Driver
Section titled “Adding a Redis Cache Driver”Register a Redis implementation by implementing the CacheInterface:
use Verge\Cache\CacheInterface;
app()->driver('cache', 'redis', function(App $app) { return new class($app->env('REDIS_URL')) implements CacheInterface { public function __construct(private string $url) {}
public function get(string $key, mixed $default = null): mixed { // Redis get implementation }
public function set(string $key, mixed $value, ?int $ttl = null): static { // Redis set implementation return $this; }
// Implement remaining CacheInterface methods... };});Built-in Log Drivers
Section titled “Built-in Log Drivers”The stream driver logs to a file or stream like php://stderr:
LOG_DRIVER=streamLOG_PATH=php://stderrLOG_LEVEL=debuguse Verge\Log\Drivers\StreamLogDriver;use Verge\Log\LogLevel;
app()->driver('log', 'stream', fn(App $app) => new StreamLogDriver( $app->env('LOG_PATH', 'php://stderr'), LogLevel::from($app->env('LOG_LEVEL', 'debug'))));The array driver stores logs in memory, which is perfect for testing:
LOG_DRIVER=arrayuse Verge\Log\Drivers\ArrayLogDriver;
app()->driver('log', 'array', fn() => new ArrayLogDriver());Changing the Default Driver
Section titled “Changing the Default Driver”Override which driver gets used when no environment variable is set:
app()->defaultDriver('cache', 'redis'); // Use redis if CACHE_DRIVER not setapp()->defaultDriver('log', 'array'); // Use array if LOG_DRIVER not setOrganizing Drivers in Providers
Section titled “Organizing Drivers in Providers”Group driver configuration in service providers:
namespace App\Providers;
use App\Cache\RedisCache;use App\Log\DatabaseLogger;
class InfrastructureProvider{ public function __invoke(App $app): void { $app->driver('cache', 'redis', fn(App $app) => new RedisCache( $app->env('REDIS_URL') ));
$app->driver('log', 'database', fn(App $app) => new DatabaseLogger( $app->make(Database::class) ));
$app->defaultDriver('cache', 'redis'); $app->defaultDriver('log', 'database'); }}Load the provider in your bootstrap:
use App\Providers\InfrastructureProvider;
app()->configure(InfrastructureProvider::class);Switching Drivers by Environment
Section titled “Switching Drivers by Environment”Use different .env files for each environment:
CACHE_DRIVER=memoryLOG_DRIVER=streamLOG_PATH=storage/logs/app.log
# .env.productionCACHE_DRIVER=redisLOG_DRIVER=databaseCreating Drivers for Your Services
Section titled “Creating Drivers for Your Services”The driver system works for any service, not just cache and logging:
use App\Queue\SyncQueue;use App\Queue\RedisQueue;
app() ->driver('queue', 'sync', fn() => new SyncQueue()) ->driver('queue', 'redis', fn(App $app) => new RedisQueue( $app->env('REDIS_URL') )) ->defaultDriver('queue', 'sync');
app()->post('/jobs', function() { $queue = app()->driver('queue'); $queue->push('SendEmail', ['to' => 'user@example.com']);
return ['queued' => true];});Testing with Drivers
Section titled “Testing with Drivers”Override which driver gets used in your tests:
use Verge\Log\Drivers\ArrayLogDriver;
it('logs messages', function() { putenv('LOG_DRIVER=array'); $app = new App();
$app->get('/action', function(Logger $logger) { $logger->info('Action performed'); return 'ok'; });
$response = $app->test()->get('/action');
expect($response->body())->toBe('ok'); // Now you can inspect the ArrayLogDriver to verify logs});