kitpages/cache-control-bundle
Symfony bundle for managing HTTP Cache-Control headers via annotations and configuration, letting you define per-action caching policies and set public/private, max-age, s-maxage, and no-cache directives.
Architecture fit — incompatible as a package, useful as a spec. kitpages/cache-control-bundle is a Symfony2 bundle, not a Laravel package. It depends on the Symfony Bundle class, the DependencyInjection extension contract, and a kernel.response listener registered through the Symfony event dispatcher. Laravel shares HTTP-foundation lineage with Symfony but exposes a different extension model — no registerBundles(), no bundle service-loading convention, and no kernel.response tag. Composer will install it (MIT, PHP-only); it will do nothing. The leverage a TPM can extract is therefore the behavior it encodes, not the code — specifically the literal header set (Cache-Control: no-cache, no-store, must-revalidate, Pragma: no-cache, Expires: 0) and any path-allowlist logic in its listener. Treat the repo as a requirements document.
Integration feasibility — rewrite, not integrate. Making this functional in Laravel requires translating it into a ServiceProvider + middleware pair. At that point every original line has been replaced; the dependency adds audit surface and confusion for zero behavior. The realistic lever is: read the one or two source files that define the header map, then write a ~20-line global (or route-scoped) middleware in app/Http/Middleware/. Registered in bootstrap/app.php (Laravel 11+) or Kernel.php, it wraps $next($request) and sets headers on the response. There is no capability here that justifies a vendor commitment.
Technical risk — low runtime, high lifecycle. As a header-setter, there's no meaningful attack surface or perf cost. The risk is temporal: era-appropriate idioms (FilterResponseEvent / GetResponseEvent, removed in Symfony 4.3+), no test suite, no CI, no maintainer, single author, 3 stars, 0 dependents. Any verbatim port will not typecheck against Laravel 10/11's Symfony 6/7 components. The HTTP semantics of the header strings themselves are wire-stable and port cleanly.
Key questions
Cache-Control?Position for the decision record: reject as a dependency, harvest as a spec. A composite score of 0.015 with 3 stars and 0 dependents is a clear signal. The TPM's deliverable is the extracted header contract plus a first-party middleware, so ownership is unambiguous at the next framework upgrade.
Stack fit — none out of the box; Laravel-native equivalents exist for every concern.
| Bundle concern | Laravel-native replacement |
|---|---|
| Response header injection | Middleware + $response->headers->set() |
| Per-route policy | Named middleware group, or config/cache-control.php |
| Static asset cache-busting | Vite manifest hashing (@vite), asset() versioning |
| ETag / conditional GET | etag middleware or Response::setEtag() |
| CDN invalidation | Deployment pipeline, not application code |
Migration path — rewrite, don't port.
app/Http/Middleware/PreventBrowserCache.php emitting the extracted headers.no-store on assets and API GETs is a defect, not a feature.curl -I on representative routes (HTML, JSON API, static asset) and confirm CDN behavior has not regressed.composer.json. It should never have been added.Compatibility. Direct ports fail: Symfony 4.3 renamed FilterResponseEvent→ResponseEvent and GetResponseEvent→RequestEvent; Laravel 10/11 ship Symfony 6/7. Copied code will not compile. The Cache-Control/Pragma/Expires values are HTTP-spec stable and port cleanly — this is the recoverable artifact.
Sequencing. Sub-day effort, no data migration, no cross-team dependencies. Fold it into whichever ticket already touches HTTP caching or deployment headers; do not allocate a sprint slot. If the driver is stale-after-deploy, schedule it after asset versioning and a CDN purge step in the release pipeline — the middleware is secondary and should be scoped as such.
Maintenance — inverted by adopting the package. The bundle imports 13-year-old code with no upgrade path and will be flagged by dependency scanners. The first-party middleware leaves ~20 lines the owning team can read, test, and modify. Net maintenance burden is strictly lower with the rewrite.
Support — none. Single author, no triage, no security response, no community. Any production incident is 100% on the adopting team whether the code was vendored or rewritten — so own it explicitly and name an owner.
Scaling — neutral per-request, material per-policy. Header emission is O(1) allocation. The scaling risk is the policy: a blanket no-store on every response defeats CDN and browser caching for images, JS, and CSS, which can push origin egress and TTFB up by an order of magnitude. Confirm intent with the CDN owner and scope the middleware before enabling globally — this is the single largest operational risk in the whole ticket, larger than the package choice itself.
Failure modes
no-store silently disables edge caching for static assets. Mitigation: route-scoped middleware, path allowlist.expires, proxy_cache) overwrites the values; local and production diverge. Mitigation: integration test asserting headers on representative routes; document proxy interaction in the PR.composer.json and presumed active while doing nothing — the worst failure mode, invisible until a stale-content incident.Ramp-up. Near zero for a Laravel engineer; HTTP caching and middleware are core territory. The only non-obvious knowledge is the interaction with the CDN layer and the distinction between header-based no-cache and deploy-time cache busting — both worth a short paragraph in the PR so the next reader doesn't re-litigate the decision.
How can I help you explore Laravel packages today?