spatie/laravel-valuestore
Store and retrieve loose key/value data in a JSON file with a simple API. Supports put/get with defaults, has/all, forget/flush, increment, and helpers like ArrayAccess and Countable—handy for app settings or small persistent state.
Installation:
composer require spatie/laravel-valuestore
Publish the config (optional):
php artisan vendor:publish --provider="Spatie\Valuestore\ValuestoreServiceProvider"
First Use Case: Store and retrieve a simple configuration value:
use Spatie\Valuestore\Valuestore;
$valuestore = Valuestore::make(storage_path('app/feature_flags.json'));
$valuestore->put('new_feature_enabled', false);
$isEnabled = $valuestore->get('new_feature_enabled', false); // Returns `false`
Where to Look First:
config/valuestore.php (default storage path: storage/valuestore.json).Valuestore::make() for custom paths or Valuestore::get() for the default store.put(), get(), has(), forget(), and flush() methods.Configuration Management:
// Store app settings (e.g., API keys, feature toggles)
Valuestore::put('api.key', env('API_KEY'));
Valuestore::put('features.new_ui', false);
// Retrieve with defaults
$apiKey = Valuestore::get('api.key', '');
Feature Flags:
// Toggle features dynamically
if (Valuestore::get('features.dark_mode', false)) {
// Enable dark mode logic
}
Caching Transient Data:
// Cache computed results (e.g., expensive API calls)
$result = Valuestore::get('expensive_result');
if (!$result) {
$result = computeExpensiveOperation();
Valuestore::put('expensive_result', $result, now()->addHours(1)); // TTL
}
Bulk Operations:
// Initialize default values
Valuestore::put([
'user_preferences.theme' => 'light',
'user_preferences.notifications' => true,
]);
// Update multiple keys atomically
Valuestore::put([
'user_preferences.theme' => 'dark',
'user_preferences.language' => 'en',
]);
Scoped Stores:
// Use separate stores for different contexts (e.g., per-tenant)
$tenantStore = Valuestore::make(storage_path("app/tenants/{$tenantId}/config.json"));
$tenantStore->put('max_connections', 100);
Service Providers:
Bind the default store in register():
$this->app->singleton('valuestore', function () {
return Valuestore::make(config('valuestore.path'));
});
Then inject via constructor:
public function __construct(private Valuestore $valuestore) {}
Artisan Commands: Use the store to persist command state or config:
$this->valuestore->put('last_run', now());
Events/Listeners: Update the store in response to events (e.g., user preferences):
event(new UserPreferenceUpdated($user, 'theme', 'dark'));
// Listener:
Valuestore::put("user_{$user->id}_theme", 'dark');
Testing:
Use Valuestore::flush() in setUp() to ensure clean state:
public function setUp(): void {
parent::setUp();
Valuestore::flush();
}
File Permissions:
storage/valuestore.json by default) is writable.chmod -R 755 storage/.JSON Serialization:
__toString() or JsonSerializable).json_encode()/json_decode() for complex objects:
$data = ['user' => $user->toArray()];
Valuestore::put('user_data', json_encode($data));
$decoded = json_decode(Valuestore::get('user_data'), true);
Race Conditions:
Default Store Overrides:
path, ensure the directory exists:
if (!file_exists(config('valuestore.path'))) {
file_put_contents(config('valuestore.path'), '{}');
}
TTL (Time-to-Live) Quirks:
put() method accepts a TTL (3rd argument), but no automatic cleanup occurs. Implement a cron job or use Laravel's schedule:
// In App\Console\Kernel.php
$schedule->command('valuestore:cleanup')->hourly();
Then create a command to delete expired keys.Inspect the File:
storage/valuestore.json (or your custom path) for stored data.Logging:
try-catch to log serialization errors:
try {
Valuestore::put('complex_data', $object);
} catch (\Throwable $e) {
Log::error("Valuestore error: " . $e->getMessage());
}
Validation:
$key = 'features.new_ui';
if (!preg_match('/^[a-z0-9_\.]+$/i', $key)) {
throw new \InvalidArgumentException("Invalid key format");
}
Custom Storage Backends:
Spatie\Valuestore\Valuestore to support databases or cache:
class DatabaseValuestore extends Valuestore {
public function put($key, $value, $ttl = null) {
DB::table('valuestore')->updateOrInsert(
['key' => $key],
['value' => $value, 'expires_at' => $ttl ? now()->addSeconds($ttl) : null]
);
}
// Implement other methods...
}
Encryption:
use Illuminate\Support\Facades\Crypt;
$valuestore->put('api.key', Crypt::encrypt($apiKey));
$decrypted = Crypt::decrypt($valuestore->get('api.key'));
Event Dispatching:
put/forget:
Valuestore::put('key', 'value', now()->addHours(1));
event(new ValueStored('key', 'value'));
Validation Rules:
$validator = Validator::make(['key' => 'features.x'], [
'key' => 'required|regex:/^features\.[a-z_]+$/i',
]);
Fallback Mechanisms:
$value = Cache::remember('valuestore:key', now()->addMinutes(5), function () {
return Valuestore::get('key');
});
How can I help you explore Laravel packages today?