ruwork/object-store
A lightweight object storage abstraction for Laravel and PHP applications. Store, retrieve, and manage objects through a clean, consistent API with pluggable storage backends. Integrates with Laravel's container and configuration, keeping persistence logic decoupled from your domain code.
The package is archived, so treat it as a vendored dependency rather than an actively maintained library — pin an exact version in composer.json and commit the lock file.
composer require ruwork/object-store
Where to look first, in this order:
vendor/ruwork/object-store/composer.json — confirm the PHP constraint and whether it pulls in Symfony, Doctrine, or PSR dependencies. This tells you more about the intended runtime than the README will.src/ — look for the primary contract (typically ObjectStoreInterface or similar) and its concrete implementations. The interface is the only thing you should depend on.tests/ — for an archived package, the tests are the real documentation. They will show you the canonical construction path and edge-case behavior (missing keys, duplicate keys, deletion semantics).README.md — usually thin for Ruwork packages; use it only to confirm the intended integration point.Minimal first use case: store a domain object under an identifier and retrieve it later in the same request or process.
use Ruwork\ObjectStore\ObjectStoreInterface; // verify actual FQCN in vendor/
$store->set('user:42', $user);
$user = $store->get('user:42');
Wire it once. In a Laravel app, bind the interface in a service provider so nothing in your codebase references a concrete class:
// app/Providers/ObjectStoreServiceProvider.php
public function register(): void
{
$this->app->singleton(ObjectStoreInterface::class, function () {
return new ArrayObjectStore(); // or whatever concrete the package ships
});
}
Do this before writing any consumer code. If the concrete store is singleton-scoped and holds mutable state, you will want to decide early whether that scope is correct for your use case (see Gotchas).
Repository wrapper. Do not let controllers or jobs talk to the store directly. Wrap it in a domain-specific repository so key conventions live in one place:
final class UserStore
{
public function __construct(private ObjectStoreInterface $store) {}
public function put(User $user): void
{
$this->store->set($this->key($user->id), $user);
}
public function find(int $id): ?User
{
return $this->store->has($this->key($id))
? $this->store->get($this->key($id))
: null;
}
private function key(int $id): string
{
return "user:{$id}";
}
}
Key namespacing. If the store is shared across features (or across tenants in a multi-tenant app), always prefix keys — tenant:{id}:user:{id} — so that a single cleanup or listing operation cannot collide with unrelated data.
Request-scoped caching. The most reliable day-to-day pattern is to use the object store as a per-request or per-job in-memory registry: load a model once, pass it around by key, avoid duplicate queries within the same unit of work. This sidesteps the serialization questions below entirely.
DTOs over entities. If the underlying implementation persists objects (serialization, file, database), store small DTOs or arrays rather than Eloquent models or Doctrine entities. Models carry connection references, event dispatchers, and resolved relations that do not survive a round-trip cleanly.
Testing seam. Because you depend on the interface, tests can swap in an in-memory implementation or a fake. Write a small InMemoryObjectStore test double in tests/Support/ rather than mocking the interface method-by-method — it reads better and survives interface changes.
Lifecycle cleanup. Pair every put with a clear deletion strategy. In jobs, wrap the store usage in a try/finally that deletes keys at the end, or schedule a sweep. Without this, long-lived singleton stores leak memory across requests in queue workers.
BadMethodCallException for methods the interface declares.scoped/bind (Laravel) or explicitly clear it at the request/job boundary.serialize() on an object containing a closure throws Serialization of 'Closure' is not allowed; on objects with resources it produces broken output. If retrieval returns something unexpected, check whether the concrete store serializes at all — inspect the implementation before debugging your own code.__sleep / __wakeup / __serialize on domain objects. If your objects implement these, ensure they do not depend on container-bound state that is unavailable at hydration time.42 and '42' are the same key and encode consistently. PHP array casting means an implementation can surprise you here.get() throws or returns null and standardize on one in your wrapper; do not let both conventions leak into callers.dd() the concrete store's internal array or backing resource) rather than assuming your wrapper is wrong. Key-formatting bugs are the most common cause.How can I help you explore Laravel packages today?