fm/keystone-bundle
fm/keystone-bundle is a Composer-installable PHP bundle that packages Keystone integration into reusable configuration, service wiring, and framework-friendly defaults. It helps Symfony-style applications add core Keystone functionality with less boilerplate and a cleaner setup.
First, the framing: fm/keystone-bundle is not a Laravel package. It is a Symfony bundle (FM\KeystoneBundle) from Financial Media, last released 2014-03-18, archived, and explicitly superseded by treehouselabs/keystone-bundle. There is no service provider, no config/keystone.php, no facade. Assess it as a design reference, not a dependency.
Minimal steps if you still need to evaluate it:
composer require it in a modern Laravel app. It targets Symfony 2.x / PHP ~5.3–5.5 era constraints. Composer will refuse to resolve it alongside illuminate/* 9/10/11 (which pull Symfony 6/7 components and PHP 8.x). Attempting an install is the fastest way to confirm this.DependencyInjection/Configuration.php — the actual config schema (option names, which are required, defaults)DependencyInjection/*Extension.php and Resources/config/*.xml — service IDs you'd inject, and how adapters are wiredtreehouselabs/keystone-bundle (and the underlying treehouselabs/keystone) is where this code went. Its docs are the closest thing to documentation this package has.Storage::disk() and Cache::store().Bottom line for a Laravel developer: read it for the adapter-seam idea, then implement that idea with Laravel's own filesystem/cache abstractions.
The patterns below are what the bundle does conceptually, and the Laravel-shaped equivalent you'd actually ship.
1. Config-driven adapter selection (Symfony side).
The bundle's whole value is that the adapter is chosen in YAML and the consuming code injects one service. A typical call site is: inject the keystone service/manager, then get/set/has/delete with a string key. Verify the exact method names in the source — the public API is small and undocumented, so don't trust blog posts from 2014.
2. Key namespacing.
Because keys are flat strings, real usage prefixes by domain: avatars/42.png, exports/2024/report.csv. Keep the prefix convention in a single class/constant so a later migration is a straight copy of the backing store rather than a mapping exercise.
3. Laravel port: wrap, don't import. If you want Keystone semantics (or you're reusing an existing Keystone-backed bucket), define your own interface and bind it:
// App\Contracts\BlobStore
interface BlobStore {
public function put(string $key, $contents): void;
public function get(string $key): ?string;
public function has(string $key): bool;
public function delete(string $key): void;
}
Then implement it over Storage::disk(...) — or, if you genuinely must talk to legacy Keystone storage, over a thin client class that is the only place Keystone types appear.
4. Registering it as a native Laravel driver.
If the goal is Storage::disk('keystone') so legacy code paths keep working, use the extension seam instead of a wrapper:
Storage::extend('keystone', fn ($app, $config) => new KeystoneAdapter($config));
Same idea via Cache::extend('keystone', ...) if it's being used as a cache rather than a blob store. This keeps the rest of the app on vanilla Laravel APIs.
5. Migration workflow.
The safe sequence for a legacy app moving off Keystone: dual-write → copy-on-read → backfill → cut reads → drop the old adapter. Because Keystone adapters are just a filesystem path or a DB table underneath, the backfill is usually rsync or a single INSERT ... SELECT, not a per-key API crawl.
6. Isolation for legacy runs.
If you must execute the 2014 code at all (e.g. to inspect a live store), do it in a pinned php:5.6-cli container with an old Symfony skeleton. Never let it into the app's composer.json.
AppKernel registration, XML service definitions, %parameters%, and old kernel path semantics (kernel.root_dir). Symfony renamed/removed all of this, and none of it maps to Laravel's container. Copy-pasted fixes from 2014-era docs will not apply.Configuration.php. Older bundles frequently mark options required even when a sensible default exists, and use cannotBeEmpty(). If instantiation fails with an opaque container error, the schema — not your YAML — is the first place to look.Storage/Cache/league/flysystem and never add this package. If you inherited a Symfony 2 app on it, migrate to treehouselabs/keystone-bundle only as an intermediate step, then off the concept entirely.How can I help you explore Laravel packages today?