fix(checkout): handle partial entities in the express checkout listing subscriber - #796
Merged
Max Stegmeyer (mstegmeyer) merged 3 commits intoAug 31, 2026
Merged
Conversation
Daniel Vien (daniel3010)
approved these changes
Aug 28, 2026
Michel (cyl3x)
approved these changes
Aug 31, 2026
Max Stegmeyer (mstegmeyer)
deleted the
fix/ecs-listing-partial-entities
branch
August 31, 2026 14:49
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.
1. Why is this change necessary?
ExpressCheckoutSubscriber::addExcludedProductsToSearchResult()listens tosales_channel.product.search.result.loaded, which is dispatched for every sales-channel productsearch — including those that narrow the loaded fields with
Criteria::addFields(). Such reads hydratePartialEntityinstances, which carry no typed getters, so$product->getParentId()is a fatal error.The
@param …<ProductCollection>docblock is what kept this hidden: the runtime collection is never aProductCollection.Third-party plugins are not the only trigger — core's
store-api.product.purchase-limitroute, used bythe storefront quantity selector on closeout products, reads products with
addFields()and withoutparentId.2. What does this change do, exactly?
The handler no longer assumes a typed product entity: ids are read through
Entity::has()/Entity::get(), the way core'sProductSubscriberhandles possibly-partial products, and the event'sgeneric becomes
EntityCollection<Entity>so static analysis stops offering getters that may not exist.One consequence is deliberate. When a partial read does not request
parentId, an exclusion inheritedfrom the parent product can no longer be detected and the product is not tagged; resolving that would
mean an extra query on every partial product read, defeating the reason callers use
addFields().Exclusions by a product's own id keep working, because the primary key is always loaded.
The two existing tests labelled "related to the ExpressCheckoutSubscriber" never reached the handler —
no credentials, no active payment method, listing disabled — and their assertion compared a UUID against
an ids-collection name. Repairing them is what makes the new regression tests bite.
3. Describe each step to reproduce the issue or behaviour.
Criteria::addFields()— for instance change thequantity on the detail page of a closeout product, which calls the purchase-limit route.
Call to undefined method PartialEntity::getParentId().The new tests in
ExcludedProductValidatorTestreproduce this through a plainsales_channel.product.repositorysearch.4. Please link to the relevant issues (if any).
closes #554
5. Checklist