Issue #3609619: Match order constraints by pluggable order attributes (OrderContext + OrderAttributeMatcher)

Implements pluggable order-attribute matching for order constraint policies (issue #3609619).

What

Order constraints no longer hardcode the customer email as the dimension a limit counts by. Each policy now carries a match_by setting naming one or more order attribute matchers, the dimensions two orders must share to count together. The default is the customer email, so existing behavior is unchanged.

New building blocks

  • OrderContext: the assembled runtime picture of an order (the order plus what tagged builders resolve from it).
  • OrderContextBuilderInterface + OrderContextFactory: tagged yoyaku_order.order_context_builder services enrich the context per source module, keeping the core decoupled.
  • OrderAttributeMatcher plugin type (attribute, interface, base, manager): value(OrderContext): ?string reports the order's value on a dimension (null skips an incomplete identity); match(QueryInterface, OrderContext): void narrows the count query.
  • Shipped matchers: email (yoyaku_order) and card_token (yoyaku_payment, resolved from the stored payment token so a fresh email cannot slip past a per-customer limit).

Composing several matchers counts two orders together only when they match on all of them (AND); "same email or same card" is two separate policies.

Tests

Kernel coverage for the email default, explicit match_by, incomplete-identity skip, unknown-matcher fail-open (yoyaku_order), and the card-token dimension (yoyaku_payment). Docs and the French translation are updated.

Merge request reports

Loading