pompdelux/phpredis-bundle
A Symfony bundle that integrates the phpredis PHP extension with configurable Redis client services, connection management, and dependency injection, making it easy to use Redis for caching, sessions, queues, and pub/sub in Symfony applications.
phpredis C extension; nothing works without it. Verify first: php -m | grep -i redis, then php --ri redis for the version and available options. If that fails, install via pecl install redis (or your distro package) and restart PHP-FPM/CLI — the bundle itself cannot install it for you.composer require pompdelux/phpredis-bundle:^1.0 will almost certainly conflict with modern PHP/Laravel constraints. Run composer show pompdelux/phpredis-bundle --all first to inspect require (PHP and symfony/* constraints), then composer require --dry-run to see the exact conflict. If it refuses, do not force it with --ignore-platform-reqs — harvest the config shape instead (see next point) and wire phpredis yourself.artisan vendor:publish and no Laravel auto-discovery):
DependencyInjection/Configuration.php — the authoritative list of connection/client options (host, port, timeout, database, password, persistent, read_write_timeout, serializer…). This is what you actually want to copy.Resources/config/services.* — the service IDs and how clients are constructed (singleton vs. factory, \Redis vs RedisArray/RedisCluster).README.md — intended YAML usage.// .env: REDIS_CLIENT=phpredis
// config/redis.php: 'client' => env('REDIS_CLIENT', 'phpredis')
Redis::connection('cache')->ping(); // PONG
Redis::connection('cache')->setex('smoke', 60, '1');
Redis::connection('cache')->get('smoke'); // "1"
Once ping() succeeds from CLI and FPM, move on to cache/session/queue drivers.connections/clients options 1:1 into config/redis.php (host, port, database, password, timeout, read_write_timeout, persistent, prefix, serializer). Laravel's Redis manager already produces the same \Redis objects the bundle would have injected — you get the day-to-day benefit (fast C client, YAML-equivalent config) without a 2014 Symfony kernel dependency.AppKernel/bundles.php, define connections and clients in config.yml, then inject the configured service ID into your services. Mirror the same host/db/prefix in Laravel's config/redis.php so both apps agree on keyspace.\Redis (or RedisManager) directly into forty classes makes serializer/prefix changes a repo-wide grep. Bind an interface:
$this->app->singleton(CacheStore::class, fn ($app) =>
new RedisCacheStore($app['redis']->connection('cache')));
This is your seam for tests and for swapping phpredis↔predis if the extension is unavailable on a build agent.'cache' => ['host'=>…, 'database'=>1, 'prefix'=>'app:cache:'],
'session' => ['host'=>…, 'database'=>2, 'prefix'=>'app:sess:'],
'queue' => ['host'=>…, 'database'=>3, 'prefix'=>'app:queue:'],
Then CACHE_STORE=redis, SESSION_DRIVER=redis, SESSION_CONNECTION=session, QUEUE_CONNECTION=redis.Cache::lock("job:{$id}", 30)->get(...) and RateLimiter::for('api', fn ($r) => Limit::perMinute(60)->by($r->ip())) with the cache store pointed at Redis.BLPOP, large SCAN sweeps, or FLUSHDB in a request will pin a PHP-FPM worker. Set $tries, $backoff, $timeout explicitly and log the Redis key/pattern in failed(), not just getMessage().database => 15), flushdb() in setUp, and assert through your wrapper interface, not raw \Redis. Where you can't run the extension in CI, bind a fake CacheStore implementation — never let unit tests require a live Redis.config/redis.php reading env(). No hardcoded hosts, no new \Redis() scattered in app code.catch, instanceof, @throws, dontReport entry, or alert rule referencing the old FQCN is now dead code or silently non-matching. Grep for the previous class name and verify against the actual class in vendor/pompdelux/phpredis-bundle/. Better: catch a shared marker interface so a future rename is a no-op.\Redis::get() returns false on a miss, not null. Classic Laravel bug: if ($value === null) never fires against phpredis. Use === false or Redis::exists(). Same for keys()/scan(), which return false on error. set() + get() under a Laravel cache layer hides this until you drop to the raw client.serialize(); a Python/Node writer reading the same key gets garbage. Pin the serializer explicitly in config/redis.php ('serializer' => Redis::SERIALIZER_NONE for plain strings) and document it — the bundle's option key for this is worth copying verbatim.\Redis singleton persists across requests/jobs, including any SELECTed database and any half-read SCAN iterator. Reset or Redis::purge() in an Octane listener / job teardown, and never assume DB 0.timeout (connect) and read_write_timeout explicitly, plus retry_interval; add a circuit-breaker or fail-fast path in your wrapper so a Redis outage degrades to DB/array cache rather than hanging every FPM worker.php artisan config:clear locally and re-run config:cache on deploy after any config/redis.php change. Symptom: works in tinker, ignores your env in the app. Also composer dump-autoload and restart queue:work after upgrades — workers keep the old class map in memory.KEYS * in production. It is O(N) and blocks the single-threaded server. Use SCAN with a COUNT hint and a cursor iterator, or maintain a key index.RedisCluster has no SELECT (no database option), different multi-key semantics, and requires key hash tags for transactions. Confirm which class the bundle's clients config constructs before copying that config into an environment where you actually run a cluster.options.prefix gives you namespacing that the bundle may not provide. Turning it on after data exists orphans every key — decide before first deploy, or write a migration that RENAMEs.php --ri redis (extension version), redis-cli MONITOR (watch actual commands during a request), SLOWLOG GET 25 (find the blocking command), and Redis::connection()->client()->info(). Check app()->bound() and resolve order before adding Log::debug spray — most "works in test, fails in prod" reports are a cached config or a purged/renamed connection.catch (\Throwable $e) around Redis calls swallows connection failures you now want typed and reported. Catch the connection exception, let programming errors surface.^1.0 and read CHANGELOG.md before every minor — but weigh honestly whether you need the bundle at all. A 1.0.x line from 2014 that has already shipped a class-name correction is still stabilising its public surface, and Laravel's framework ships first-class phpredis support that gives you the same performance with a maintained integration path.How can I help you explore Laravel packages today?