Repository navigation
Conversation
721f18f to
0b4fb79
Compare
96e7c30 to
96cee7e
Compare
96cee7e to
3db5fc2
Compare
Setting `value` before `checkedValue` or `uncheckedValue` left the element in a state derived from the defaults `y` and `n`: a checkbox whose value matched its checked value rendered unchecked, and a boolean value got resolved to `y` or `n` instead of the custom values. What an element rendered and reported as its value therefore depended on the order of the attributes passed to it, which callers have no reason to expect. The value is now the only state a checkbox keeps. Booleans are resolved when the value is read and the checked state is derived from it. As a consequence `setChecked()` sets the element's value. A checkbox that is checked without having been submitted hence has a value now, which lets it pass validation if it is also required.
3db5fc2 to
e87c2f1
Compare
|
|
||
| if (is_bool($value)) { | ||
| $value = $value ? $this->getCheckedValue() : $this->getUncheckedValue(); | ||
| return $value ? $this->getCheckedValue() : $this->getUncheckedValue(); |
There was a problem hiding this comment.
Please clear $this->valid in setCheckedValue() and setUncheckedValue(). These setters can now change the effective value without invalidating its cached validation result.
I reproduced this with value => true and a callback validator that accepts only 'y'. Initial validation passes. Calling setCheckedValue('a') changes the value to 'a'. isValid() still returns true. An explicit validate() call correctly rejects the new value. Before this change, the same sequence retained the validated value 'y'.
Add regression tests that validate the checkbox before changing a mapping. The next isValid() call should validate the new value automatically. Test that a valid checkbox becomes invalid after the mapping changes. Also test that an invalid checkbox becomes valid.
There was a problem hiding this comment.
$this->valid is now set to null in both methods. I've added three tests about it.
Because `getValue()` now resolves boolean values lazily, changing a value mapping changes the effective value without the cached `$this->valid` knowing about it. A subsequent `isValid()` call returns the stale result rather than re-validating the new effective value. Clear `$this->valid` in both setters so the next `isValid()` triggers a fresh `validate()` run.
379a91e to
0ef8da1
Compare
CheckboxElementderived two things eagerly insetValue(): it resolved a boolean value into a string, and it computed thecheckedflag. Both depend oncheckedValue/uncheckedValue, which may not be set yet.Attributes::set()invokes setter callbacks immediately, in the order the attributes are given. So whichever attribute came first won:The case reported in #140 is not the only one. With
'checkedValue' => 'a'and'uncheckedValue' => 'b':'value' => trueset beforecheckedValuestores the default'y'instead of'a'. It renders as checked either way, so the mismatch only surfaces ingetValue()and inhasValue(), which then reportsfalsefor a visibly checked box.'value' => falseset beforeuncheckedValuestores'n'instead of'b', the same silent mismatch.'value' => 'b'is order-independent by accident:'b'matches neither the default'y'nor'a', so the stale comparison happens to yield the correct unchecked state.'checked' => truenever consulted the checked value at all, which left the element checked whilegetValue()returnednull.The boolean cases corrupt
getValue()andhasValue()even where the checkbox happens to render correctly, so guardingsetCheckedValue()alone would not have been enough.Changes
The value is now the only state a checkbox keeps, and everything else is derived from it on read:
getValue()resolves a boolean value to the checked or unchecked valueisChecked()comparesgetValue()withgetCheckedValue()setChecked()sets the value instead of a separate flaghasValue()delegates toisChecked()checkedproperty is goneAfter the change, all five scenarios above yield a single outcome across every attribute ordering.
Changes in behavior
setChecked()and thecheckedattribute now set the element's value. A checkbox that is checked without having been submitted therefore has a value:getValue()returns the checked value instead ofnull, and a checkbox that is both required and checked passes validation instead of failing with "This field is required."fix #140