ethical-jobs/laravel-storage
A Laravel package from Ethical Jobs that provides storage helpers and configuration for managing file uploads and media across local and cloud disks, simplifying consistent storage setup in Laravel applications.
Start by pulling the package in and inspecting what it actually registers, because at zero stars and zero dependents the fastest path to understanding is reading the service provider rather than the README:
composer require ethical-jobs/laravel-storage
php artisan vendor:publish --provider="EthicalJobs\Storage\StorageServiceProvider"
Look at three things first:
composer.json in the package — check the Laravel version constraint and whether it leans on illuminate/cache, illuminate/database, or a custom driver contract. That tells you what it is really wrapping.register()/boot() — note any singleton bindings, config merges, and auto-discovered aliases.config/storage.php (or whatever gets published) — this is where the backing store, TTLs, and key prefixes live.The first use case to try is the one the name implies: putting a repository behind a storage/cache layer so repeated reads don't hit the database. In a controller or service, resolve the repository out of the container rather than new-ing it, then call a read method twice and confirm the second call is served from cache (log the query or watch Redis/database cache hits). If that round trip works, you understand the core contract and can build from there.
Repository-per-aggregate with a shared base. The typical shape is a base repository class from the package that you extend per model, overriding the model class, cache key, and TTL. Keep one repository per aggregate root and inject the interface into your services — that keeps the storage layer swappable and testable.
Read-through caching on query methods. The day-to-day value is wrapping find, paginated listings, and count/summary queries so they read-through to the configured store and write back on miss. Put the cache concern in the repository, not the controller, and make sure update/delete in the same repository bust the keys it owns. If the package doesn't do this for you, wire it in boot() via model events:
User::saved(fn ($user) => $repo->forget($user->getKey()));
User::deleted(fn ($user) => $repo->forget($user->getKey()));
Key namespacing. Build cache keys from a stable prefix plus a hash of the query parameters. Include the tenant/account ID if you are multi-tenant, and include a schema or serialization version so a deploy that changes the shape doesn't serve stale structures.
Service-layer injection. Bind repository interfaces to implementations in a dedicated RepositoryServiceProvider, then type-hint the interface in your services and jobs. This makes swapping a storage implementation (array store in tests, Redis in production) a config change rather than a code change.
Use it in queued jobs and console commands too. Because the repository is container-resolved, the same cached reads protect expensive nightly reports and background syncs — not just HTTP requests.
__PHP_Incomplete_Class and broken relations are the usual symptoms.Cache::lock) around cold reads if the package doesn't guard this.insertOrIgnore, direct DB imports — because those bypass observable events and will leave stale entries.null TTL means "forever" or "no cache," and whether the key prefix is applied at the driver level. Set a distinct prefix per environment so local and CI runs don't share entries.CACHE_STORE=array locally to isolate whether a bug is storage-related. cache:clear only clears the store defined by the package's config key, not every store you have configured.composer.json, and keep a thin abstraction of your own so you can replace it if it goes unmaintained.How can I help you explore Laravel packages today?