Repository navigation
Conversation
Two ways the decoration could silently drop behaviour: Rebuilding the two VAT aware filters discarded whatever options the originals carried. The Sylius filters currently declare none, so nothing was lost yet, but escaping and argument passing would have been silently altered the moment they did. copyOptions() now carries them over. is_safe is forwarded through an is_safe_callback that defers to the original getSafe(), which is the only way to preserve both is_safe and is_safe_callback, since neither can be read back. __call() suggested the remaining extension methods were forwarded to the decorated extension. It never fires for them: AbstractExtension declares getFunctions(), getTests(), getTokenParsers() and getNodeVisitors(), so they returned the empty parent values and any function the base extension grew would have vanished. They are now delegated explicitly and __call() is gone. Wrapping the filter also assumed the price context is the second argument, which stops being true if a filter asks for the environment or the template context. The index is now derived from the filter. Adds PriceExtensionTest, which drives the filters through a real base extension and asserts the calculator sees vat_context_aware. Claude-Session: https://claude.ai/code/session_01P9NzuVPQGvaVR97HZFq98a
15 tasks
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.
Three ways the decoration could silently drop or corrupt behaviour. None of them misbehave against Sylius 1.12 today — they are all "the moment X changes, this breaks quietly", which is the worst way for a price calculation to break.
1. Rebuilt filters lost their options.
new TwigFilter($name, $closure)discarded whatever options the original carried. The three Sylius filters declare none, so nothing is lost right now, but escaping (is_safe,pre_escape,preserves_safety) and argument passing (needs_environment,needs_context,is_variadic) would have silently changed the moment one of them did.copyOptions()now carries them across.is_safeis the interesting one: it cannot be read back directly, andgetSafe()needs the argumentNode, which only exists at compile time. Forwarding anis_safe_callbackthat defers to the originalgetSafe()preserves bothis_safeandis_safe_callbackcorrectly and at the right moment.Two options are deliberately not copied, both commented in the code:
node_class(a filter compiled through a custom node would not route through our callable at all, so copying it would produce a filter that silently ignores the VAT context) and the deprecation version/alternative detail (only readable via methods Twig has itself deprecated — the notice survives, the detail does not).2.
__callwas decorative. It looked like the remaining extension methods were forwarded to the decorated extension. It never fires for any of them:AbstractExtensiondeclaresgetFunctions(),getTests(),getTokenParsers()andgetNodeVisitors(), so the parent's empty values won and anything the base extension grew would have vanished. They are delegated explicitly now and__callis gone.getOperators()is the one exception and it has a comment saying why — Twig 3.21 annotates it with classes it has since removed, which any override inherits, and psalm rejects the result. The decorated extension registers no operators, so inheritingAbstractExtension's[[], []]is identical in behaviour.3. The price context was assumed to be argument 2. That stops being true the moment a filter asks for the environment or the template context, since Twig prepends those — the wrapper would then have written
vat_context_awareinto the variant argument. The index is now derived from the filter itself.Also adds
PriceExtensionTest, which the decorator previously had none of. It drives the filters through a realBasePriceExtension/PriceHelperand asserts the calculator actually receivesvat_context_aware, thatsylius_has_discountis passed through un-rebuilt, and that the remaining methods delegate.Addresses the third architecture item in #5.
https://claude.ai/code/session_01P9NzuVPQGvaVR97HZFq98a