fix: evaluate multi-choice visibility conditions as exact option membership#177
Merged
ManukMinasyan merged 1 commit intoJul 1, 2026
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR aligns client-side conditional visibility rendering (visibleJs) and server-side validation gating for multi-choice, option-backed fields by treating contains / does not contain as exact option membership (rather than substring matching). This resolves cases where dependent fields were incorrectly required while hidden, and eliminates client/server disagreement for overlapping option ids/names.
Changes:
- Updated frontend visibility JS generation so option-backed choice-field
containsuses the same option-id membership logic asequals. - Extended server-side visibility evaluation to optionally treat
contains/not_containsas exact, case-insensitive membership for specified option-backed choice field codes, and wired this into the validation gate. - Expanded integration coverage to include multi-select + checkbox-list membership behavior and an overlapping-name exactness regression (
DovsDog).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Feature/Integration/ConditionalVisibilityValidationTest.php | Adds multi-choice membership + overlapping-name regression tests for conditional visibility validation gating. |
| src/Services/Visibility/FrontendVisibilityService.php | Routes option-backed choice contains to option-id membership JS (same semantics as equals). |
| src/Services/Visibility/CoreVisibilityLogicService.php | Plumbs optional “membership field codes” through to VisibilityData::evaluate() for server evaluation when requested. |
| src/Filament/Integration/Base/AbstractFormComponent.php | Expands safe operators to include contains/not_contains and passes option-backed choice field codes into the gate’s visibility evaluation. |
| src/Data/VisibilityData.php | Implements exact, case-insensitive membership evaluation for contains/not_contains when the field code is flagged as option-backed. |
| CHANGELOG.md | Documents the v3.5.2 fix and the prior divergence failure modes. |
…ership Conditional-visibility "contains"/"does not contain" on option-backed choice fields (multi-select, checkbox-list) diverged between client and server: the client compared option ids while the server substring-matched option names. A dependent field required only when visible could stay required while hidden, and for substring-overlapping option names (e.g. "Do" vs "Dog") the server could skip validation on a field the user can still see. Both the client visibility expression and the server validation gate now treat contains/not-contains on option-backed choice fields as exact option membership (the selected options include any of the condition's options). Text fields and option-less multi-value fields (email, tags, ...) keep substring matching, identical on both sides. Adds regression coverage for multi-select and checkbox-list, including overlapping option names.
5c3dfe9 to
0ef6d56
Compare
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.
Problem
Follow-up to #176 (v3.5.1), which fixed conditional-
requiredvalidation for single-choice triggers but left multi-choice ones broken.Conditional visibility
contains/does not containon option-backed choice fields (multi-select, checkbox-list) diverged between client and server:visibleJs) resolved the condition to option ids and substring-matched id strings.Two failure modes:
requiredrule while hidden — the reported bug (dependent detail fields blocking submit on Abode's forms).DovsDog) or overlapping ids (1vs11), the two sides disagreed, so the gate could skip validation on a field the user can still see — silent data loss. The v3.5.1 gate avoided this only by deferring (never skipping) for these operators, which is what left mode (1) broken.Fix
Both the client visibility expression and the server validation gate now treat
contains/does not containon option-backed choice fields as exact option membership — the selected options include (any of) the condition's options — matching howequalsalready works for choice fields.buildContainsExpressionroutes option-backed choice fields through the same option-membership expression asequals(conditionIds.some(id => selectedIds.includes(id))).VisibilityData::evaluateaccepts the codes of option-backed choice fields and evaluates theircontains/not_containsconditions as exact, case-insensitive membership. The form validation gate passes those codes.contains/not_containsare added toCHOICE_SAFE_OPERATORSso the gate reproduces them instead of deferring.Text fields and option-less multi-value fields (email, phone, link, record, tags-input) keep substring matching — client and server already agree there, so they are intentionally excluded.
Scope
This covers the form validation gate and the client visibility rendering (the reported bug). The server-side rendering fallback used by infolists/exports (
BackendVisibilityService::isFieldVisible→ cascading) is a separate surface with its own value extraction and is left unchanged.Coverage — every field type as a condition trigger
Tests
Extended
ConditionalVisibilityValidationTestwith multi-select and checkbox-list cases (hidden → not required, visible → required, not-contains both ways) and an overlapping-name exactness test (Do/Dog) that fails under both the old defer behaviour and a naive substring whitelist.