Make CssImportFilter hashable so the asset cache can key it - #52
Merged
Conversation
AssetCache builds its cache key from an asset's filters, hashing those that implement HashableInterface and falling back to serialize() for the rest. Since v3.2.1 CssImportFilter can hold an import validator, which is normally a closure, and serializing a closure throws — so any asset filtered by a configured CssImportFilter fataled with "Serialization of 'Closure' is not allowed" as soon as it passed through the asset cache. Implement HashableInterface so the filter is never serialized. The hash covers the inner import filter and the validator, preferring serialization of each, which captures configuration. A closure cannot be serialized, so it is identified by its declaration site plus the variables bound into it — which is what carries a validator's configuration, so two validators confining imports to different roots cannot be served each other's cached output. Object identity is deliberately never used: it is not stable between requests and would give the cache a fresh key every time. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The changelog stopped at 3.1.1; 3.1.2, 3.1.3, 3.1.4, 3.1.5, 3.1.6, 3.2.0 and 3.2.1 shipped without entries. Reconstructed from the commits between each tag, dated from the published release rather than the local tag. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
Any asset filtered by a configured
CssImportFilterfatals as soon as it passes throughAssetCache:AssetCache::getCacheKey()builds its key from the asset's filters, hashing those that implementHashableInterfaceand falling back toserialize()for the rest (AssetCache.php#L151-L157). Since #51,CssImportFiltercan hold an import validator — normally a closure — and serializing a closure throws.This reached consumers: Winter CMS wires an import validator into its asset combiner, so every combined bundle containing a plain
.cssfile 500s with that message in place of the stylesheet..less/.scss/.jsbundles are unaffected, sinceCssImportFilteris only registered forcss.The fix
Implement
HashableInterfaceso the filter is hashed rather than serialized. The hash covers the inner import filter and the validator, preferring serialization of each since that captures their configuration.A closure can't be serialized, so it is identified by its declaration site plus the variables bound into it (
ReflectionFunction::getStaticVariables()). That second half matters: the bound variables are where a validator's configuration lives — the set of paths it authorises — so two validators sharing a declaration but confining imports differently hash differently and cannot be served each other's cached output. Returning a constant for every closure would have let a permissive-validator build populate the cache and a restrictive-validator build reuse that output, undermining the confinement the validator exists to provide.Object identity is deliberately never used as a fallback:
spl_object_hash()and friends aren't stable between requests and would hand the cache a fresh key every time.Tests
Five cases added to
CssImportFilterTest, each verified to fail before the change:AssetCachedumps an asset filtered by a validator-configured filter — the regression itself, which errors atAssetCache.php:155without the fixFull suite passes: 417 tests, 0 failures.
Note for maintainers
Cache keys for assets filtered by
CssImportFilterchange with this fix, so those assets rebuild once on upgrade.The second commit backfills the changelog, which stopped at 3.1.1 — 3.1.2 through 3.2.1 all shipped without entries. Reconstructed from the commits between each tag and dated from each published release. Happy to drop that commit if you'd rather it landed separately. The 3.2.2 heading is dated on the assumption of an imminent release; adjust as needed.
🤖 Generated with Claude Code