Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Kv Store Laravel Package

tempest/kv-store

A lightweight key-value storage abstraction for Tempest PHP applications, offering a simple, consistent API for storing, retrieving, and managing persisted values while keeping storage code clean and framework-friendly.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a read-only subsplit of the KV-store component that lives in the tempestphp/tempest-framework monorepo. That single fact shapes everything about how you work with it.

  1. Install. If you already use Tempest, the component ships with the framework — don't add it twice. Standalone:

    composer require tempest/kv-store
    

    Check composer.json first for the PHP constraint (Tempest currently targets a modern PHP, 8.3/8.4-era) and for its tempest/container / tempest/core dependencies. A component subsplit is not a framework; you'll need the container and discovery packages to use it outside Tempest.

  2. Read the interface before anything else. Open src/ and find the contract — this is the only file that matters for day-to-day work. Look for the interface (e.g. KeyValueStore) and the concrete implementations beside it (in-memory, file, and possibly a Redis/array adapter). Note the exact signatures for get/set/delete/has and whether a TTL argument exists. Every pattern below hinges on those signatures, so verify them rather than assuming Laravel Cache parity.

  3. Find the binding. Because Tempest uses attribute-driven discovery, the interface is bound to a default implementation somewhere — a config class, an initializer, or a #[Singleton] attribute on the implementation. That binding is your extension point for swapping stores per environment.

  4. First use case: cache-aside an expensive read. Inject the store and guard a costly computation:

    use Tempest\KeyValue\KeyValueStore;
    
    final readonly class StatsController
    {
        public function __construct(private KeyValueStore $store) {}
    
        #[Get('/stats')]
        public function __invoke(): array
        {
            $key = 'app:stats:v1';
    
            if (($cached = $this->store->get($key)) !== null) {
                return $cached;
            }
    
            $stats = $this->recompute();      // expensive
            $this->store->set($key, $stats);
    
            return $stats;
        }
    }
    

    Confirm the actual method names/signatures in the interface; adjust the null-check accordingly if the contract uses a default-value parameter.

Implementation Patterns

Wrap the contract in a typed service. Raw string keys scattered across controllers is how KV stores rot. Create one small class per domain concern that owns the keys, the serialization shape, and the TTL:

final readonly class StatsCache
{
    public function __construct(private KeyValueStore $store) {}

    public function get(): ?array { /* key + envelope logic */ }
    public function put(array $stats): void { /* ... */ }
    public function flush(): void { /* ... */ }
}

Inject that, not the store, into application code. Swapping the backing store later then touches one file.

Namespace every key. Treat the store as one flat, shared namespace: app:{domain}:{version}:{id}. The version segment is your poor-man's cache-tag invalidation — bump it to invalidate a whole domain without enumerating keys (KV stores rarely offer flushByPrefix, let alone Laravel-style tags).

Roll your own remember() and TTL if absent. Laravel's Cache::remember has no direct equivalent here at the contract level. Either the adapter supports per-key expiry, or you store an envelope:

['value' => $value, 'expiresAt' => time() + 300]

and treat expiresAt as authoritative on read. Pick one approach and centralize it in the wrapper service — mixing both is a debugging nightmare.

Swap to in-memory for tests. Bind the in-memory implementation in your test bootstrap so unit tests never touch the filesystem or a network store. This is the single highest-value integration; it's also the reason to keep the interface as the only thing you type-hint.

High-leverage integration points in a Tempest app:

  • Webhook idempotency — set('webhook:{eventId}', true) before processing; skip on replay.
  • Console commands and scheduled tasks — cache computed reports, store last-run cursors for incremental syncs.
  • Middleware — fixed-window rate limiting, feature-flag lookups, short-lived lock tokens.
  • Event listeners — dedupe repeated events in a burst.

Laravel mental mapping. Cache::get/put/forget → the store's get/set/delete; Cache::remember → your wrapper; cache tags → versioned key prefixes; Cache::lock → not available unless the adapter documents atomicity (see below).

Gotchas and Tips

  • Contribute upstream, not here. The repo is [READ ONLY]. Issues and PRs go to tempestphp/tempest-framework. Don't open a PR against the subsplit — it will be closed.
  • Treat the API as unstable. Zero stars, zero dependents, a pre-1.0 framework component. Pin an exact version in composer.json and keep the store behind your wrapper interface so a signature change is a one-file fix.
  • Serialization is a hidden contract. File/Redis adapters almost always serialize values. Don't store closures, resources, or stream handles. More subtly: if you store objects and later rename or move the class, deserialization breaks on old entries with a confusing error. Prefer plain arrays and scalars at the boundary.
  • Read-modify-write is not atomic. For a file-backed store, concurrent requests can interleave and lose writes. Never build counters, locks, or "get then increment" logic on it unless the implementation explicitly documents locking or atomic ops. Use the database for anything that must be correct under concurrency.
  • Key hygiene matters for file adapters. Keys may become filenames or path segments. Colons, slashes, and very long keys can be sanitized, collide, or create unexpected directories. Test with your real key format, and keep keys short (hash long components).
  • Unbounded growth without TTL. If expiry isn't native, nothing evicts old entries. Add a sweep command (#[ConsoleCommand]) that walks the backing directory or scans keys and deletes expired envelopes — and schedule it.
  • Debugging: inspect the backing store directly (the storage directory, or KEYS app:* in Redis) rather than adding logging inside your service. A dumped raw value immediately tells you whether the problem is serialization, key naming, or expiry.
  • Extension points worth knowing: implement the KeyValueStore interface yourself and rebind it — that's the clean way to add encryption, metrics, prefixing, or locking without forking. If you're outside Tempest's discovery, instantiate the implementation manually and pass it in; don't assume the container exists.
  • Missing features to plan around: no cache tags, no remember, no guaranteed atomic increments, and likely no bulk read. If your design needs any of those, budget for building them in the wrapper on day one.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names