guhemama/http-precondition-bundle
Symfony bundle for handling HTTP precondition headers such as If-Match, If-None-Match, If-Modified-Since, and If-Unmodified-Since. Helps controllers return correct 304 or 412 responses and enforce optimistic concurrency without repetitive header logic.
Delta since the prior assessment — 1.0.1 is a packaging release, not a capability release. The notes describe "improve configuration" and "use standard bundle naming (now it includes the vendor name)." That is a rename to Symfony's conventional <Vendor><Name>Bundle form plus configuration cleanup. It does not touch the condition matcher, the expression evaluator, the response factory, listener priority, or the 412 semantics. The evaluation below is unchanged in substance; only the recency and governance observations are revised.
Architecture fit — still poor at the package level, sound at the concept level. This remains a Symfony Bundle: it registers via BundleInterface and hooks the kernel.request event of Symfony's event-driven HttpKernel. Laravel has no bundle registry, and its HTTP kernel (Illuminate\Foundation\Http\Kernel) is a different class; Laravel pulls symfony/http-kernel only transitively for HttpKernelInterface / HttpExceptionInterface, not for the dispatch pipeline this bundle extends. There is no drop-in surface. 1.0.1 does not change this — a rename makes the bundle more conventionally Symfony, not more portable. What remains transferable is the idea: declarative, per-route preconditions evaluated before the controller, returning 412 Precondition Failed. That concept maps cleanly onto Laravel middleware, FormRequest::authorize(), or a Route::macro.
Integration feasibility — port, don't install. The reusable logic is likely small: a request matcher, an expression evaluator, a listener, and a response factory. symfony/expression-language is a standalone component that works inside Laravel, so the condition-evaluation half survives intact; only the kernel wiring has to be rewritten as middleware. Estimate unchanged: 1–2 engineer-days for a spike plus a tested port.
Technical risk — high, and mostly supply-chain rather than technical.
config/bundles.php entries, service/parameter naming conventions) yet shipped as a patch bump. Loose versioning discipline upstream reinforces the "vendor nothing" conclusion. It costs us nothing only because we already recommend against installing the package.412 for conditional requests (If-Match, If-None-Match, If-Unmodified-Since). Repurposing it for arbitrary route preconditions (authz, feature flags, state checks) invites misbehavior from HTTP caches, CDNs, and client retry logic. 403, 409, or 422 are usually the correct codes.Key questions for the maintainer/repo before any investment (all still open):
symfony/http-kernel constraint, and is the core logic separable from the bundle wiring?symfony/expression-language used, and is it sandboxed? What variables are in scope?412 fixed or configurable per precondition?access_control?Stack fit. Laravel 10/11 ship symfony/http-kernel ^6.2/^7.0; a bundle with 2023-era wiring may cap at ^5.4/^6.0, producing a Composer conflict even if we wanted to autoload pieces. 1.0.1 gives no new constraint information, so treat compatibility as still unverified. That is moot under the recommended path because we consume source, not the package. symfony/expression-language ^6 is Laravel-compatible and can be required directly if the DSL is worth keeping.
Recommended migration path:
app/Http/Middleware/PreconditionMiddleware.php, or expose it as a Route::precondition() macro on Illuminate\Routing\Route for declarative per-route syntax.Build-vs-buy alternative. For most stated needs, Laravel primitives already cover the use case: FormRequest::authorize(), can: route middleware, signed, throttle, route-model binding, and custom validation. Only port the DSL if you specifically need declarative per-route expressions plus a uniform response code — still the only capability here that Laravel lacks out of the box.
Compatibility. PHP 8.1+ is fine; no service-container bindings, facades, or config publishing are needed in the ported form. The bundle-naming change is invisible to a source-level port.
Sequencing.
expression-language if the DSL is retained.412s before enforcing.Maintenance. You own the fork permanently. Upstream is best described as barely alive rather than dormant: one patch release in two-plus years, configuration and naming only. Assume no patches arrive for anything you actually care about. Budget ~2–4 hours/quarter for dependency bumps plus occasional breakage on expression-language majors. Assign a named owning team before adoption — this remains the gating operational decision.
Support. No vendor, no SLA, GitHub issues only. Internal runbook and example library required; treat the package as documentation, not as a supplier.
Scaling. Per-request cost is negligible relative to typical middleware — a string or expression match. Two things to watch: (a) ensure expression compilation is cached, not re-parsed per request in a naive port; (b) order the middleware after auth so expensive condition evaluation never runs for anonymous traffic.
Failure modes.
If-Match at the edge) blocks all traffic at once.500s rather than controlled denials.auth, throttle, and route-model binding produce inconsistent behavior that is hard to reproduce.412 as a conditional-request signal rather than an application denial.Ramp-up. Low for Laravel engineers — middleware is familiar territory, roughly half a day per engineer including the DSL and status-code conventions. The real onboarding cost is the internal doc explaining when a precondition is appropriate versus a FormRequest, Gate, or can: middleware.
Bottom line for the portfolio: unchanged. The dependency is worth approximately zero — 1.0.1 is a rename and a config tidy, not a revival. The design reference is worth roughly one engineer-day. Fund a thin native Laravel middleware, cite this package (pinned at 1.0.1) in the design doc, and move on.
How can I help you explore Laravel packages today?