mjkruszewski/plumbok-bundle
A Symfony bundle integrating Plumbok, the PHP library that auto-generates boilerplate for DTOs and value objects—typed properties, getters, setters, constructors, and immutable builders—so you can declare lean classes and let annotations do the rest.
composer require vendor/package then php artisan vendor:publish --tag=...config. The published config is the single most important file — it controls the cache store/path, TTL, and which directories get scanned.php artisan serve
curl -s -o /dev/null -w "%{time_total}\n" http://localhost:8000/your-page # cold
curl -s -o /dev/null -w "%{time_total}\n" http://localhost:8000/your-page # warm
Then locate the generated artifact (check config('...cache.path'), defaulting to something under storage/framework/cache) and confirm its mtime updates only when it should. That single loop — cold request, warm request, inspect file — is the fastest way to validate the whole package.
Warm the cache during deploy, not from user traffic. The lazy build is a safety net, not a strategy. Add a step to your deploy pipeline that hits one route or runs a one-off request so real users never pay the cold-start cost:
// routes/console.php (Laravel 11+) or a deploy hook
Artisan::command('files-cache:warm', function () {
// Trigger the same code path the first request would use.
app(\Vendor\Package\CacheBuilder::class)->build();
$this->info('Files cache warmed.');
});
If the package exposes no public builder API, a trivial internal route that touches the feature and is called via curl from the deploy script is fine — just protect it with a token or bind it to localhost.
Bust the cache on content change, not on a timer. File-backed caches go stale the moment someone uploads a file or a deploy ships new assets. Wire invalidation into the same place your content changes:
// A model observer or an upload handler
public function saved(UploadedFileModel $file): void
{
app(\Vendor\Package\CacheBuilder::class)->flush(); // or Cache::forget($key)
}
If the package has no flush method, delete the cache file / forget the configured cache key directly — but wrap it in a small app-level service so you have one place to change when the package's internals move.
Treat the cache store choice as a deployment decision. The config typically allows file or a Laravel cache store. On a multi-node setup, a per-node file cache means every node builds its own on its own first request — cold starts multiply. Prefer Redis if the package supports it, or run the warm command on each node during rollout.
Keep tests deterministic. Set the package to a cheap/in-memory store in phpunit.xml so tests don't inherit a stale on-disk artifact:
<env name="FILES_CACHE_STORE" value="array"/>
<env name="FILES_CACHE_ENABLED" value="false"/> <!-- if supported -->
Add at least one test that explicitly enables the cache and exercises the lazy-build path; otherwise CI never covers the code 1.0.1 touched.
Octane and long-running workers. Because the cache may be hydrated once per application boot, verify behaviour under php artisan octane:start. A reload is required after content changes; a naive ->flush() may not reach every worker.
Queue workers inherit the same semantics. A job dispatched before the cache exists will build it inside the worker on first execution — which is fine, but it means the warm-up cost lands on a queue worker instead of a web request, and each worker process may pay it separately.
storage_path() or switch to a cache store.try/catch, a broken build looks identical to a cache miss: every request regenerates, nothing errors. Add a temporary Log::info / Cache::has assertion when you first wire this up, and keep an eye on cold-request latency in your APM after deploys.php artisan cache:clear plus a manual delete of the packaged path) — otherwise you'll debug a stale file that the new code no longer reads.config:cache and route:cache interplay. If your deploy caches config, ensure any environment-driven settings for the package are read after the config cache is built. A common mistake is setting the cache path via env() in the package config and having it resolve to null under config:cache.FilesCacheBuilt is worth subscribing to if it exists — it gives you a legitimate hook for warming related caches or emitting a metric without touching vendor code..1 that changes when work happens is a behavioural change, not just a bugfix; treat the upgrade like a small feature release and re-time your cold requests after deploying.How can I help you explore Laravel packages today?