Skip to content

Conversation

@achrafAa
Copy link
Contributor

@achrafAa achrafAa commented Nov 5, 2025

Problem

When using conditional validation rules like required_if, prohibited_if, accepted_if, etc., the error messages were incorrectly lowercasing the actual submitted values, making error messages confusing and inconsistent.

Example Issues

Issue 1: Case is lost

Validator::make(
    ['status' => 'Active'],
    ['reason' => 'required_if:status,Active']
);

// ❌ Old: "The reason field is required when status is active."
// ✅ New: "The reason field is required when status is Active."

Issue 2: Boolean confusion

Validator::make(
    ['field1' => 'true'],
    ['field2' => 'required_if:field1,true']
);

// The message correctly shows what the user submitted: "true"

Issue 3: Multi-value scenarios

Validator::make(
    ['status' => 'review'],
    ['reason' => 'required_if:status,pending,active,review']
);

// ❌ Old: "The reason field is required when status is pending."
//         (Shows first expected value, not what user submitted)
// ✅ New: "The reason field is required when status is review."
//         (Shows what user actually submitted)

Root Cause

The replaceAcceptedIf method in ReplacesAttributes.php was using replaceWhileKeepingCase for the :value placeholder, which automatically applied case transformations based on the placeholder format (:value → lowercase, :VALUE → uppercase, :Value → ucfirst).

This meant that regardless of what the user submitted, if the translation used :value (which is standard), the value would always be lowercased.

Response to Previous Feedback

Taylor's Test Case

In the previous PR discussion [#57679 ], the following test case was mentioned:

$v = Validator::make([
    'status' => 'active',
], [
    'status' => 'required',
    'reason' => 'required_if:status,inactive',
]);

$v->passes(); // true
dd($v->errors()->all()); // []

Why this doesn't demonstrate the issue: This example shows validation passing (no errors), so no error message is generated. The issue only manifests when validation fails and error messages need to be displayed.

The Actual Problem Occurs Here

// When user submits 'Active' (with uppercase A)
$v = Validator::make([
    'status' => 'Active',
], [
    'status' => 'required',
    'reason' => 'required_if:status,Active',
]);

$v->passes(); // false - reason field is required
$v->errors()->first('reason');

// ❌ Before fix: "The reason field is required when status is active."
//    (Lowercase 'active' - confusing because user submitted 'Active')

// ✅ After fix: "The reason field is required when status is Active."
//    (Preserves the case of what user actually submitted)

The issue is that when validation fails, the error message was lowercasing the submitted value due to replaceWhileKeepingCase applying transformations based on the :value placeholder in the translation string.

Why This Fix is Necessary

  1. User submitted 'AA', error should say "AA" not "aa"
  2. User submitted 'False' (boolean), error should reflect the actual value
  3. Multi-value rules: Should show which specific value matched, not the first expected value

Testing

Comprehensive tests have been added in ValidationConditionalRuleErrorMessagesTest.php:

Breaking Changes

None. This fix only affects error message formatting, not validation logic. The behavior change makes error messages more accurate and user-friendly.

Related Issues

Fixes [#57678]

@shaedrich
Copy link
Contributor

Just change replaceWhileKeepingCase()

@achrafAa
Copy link
Contributor Author

achrafAa commented Nov 5, 2025

@shaedrich No, we cannot just change replaceWhileKeepingCase() because the issue is specific to the :value placeholder, not all placeholders. Other usages need the case transformation to work correctly for attribute names.

replaceWhileKeepingCase() is designed to apply case transformations ( its purpose! ) It transforms:
- :other → lowercase of attribute
- :OTHER → uppercase of attribute
- :Other → ucfirst of attribute

changing it will introduce breaking change risk, as it would affect all these other methods and could break attribute name
formatting across the entire validation system.

@shaedrich
Copy link
Contributor

shaedrich commented Nov 5, 2025

That is not correct. I introduced a breaking change on a patch release in #57564 a week ago and underestimated the consequences. @AndrewMast correctly pointed this out in his comment: #57564 (comment). What I suggested was to partially revert said PR and remove the lowercasing of case since this hadn't been done prior to #57564 before more people upgrade to the latest release and are faced with potentially making manual adjustments. Furthermore, tests should be put into place to prevent my mistake from happening again.

@achrafAa
Copy link
Contributor Author

achrafAa commented Nov 5, 2025

@shaedrich good to know, i will read this history, just to get more informations, thanks 🙏

@shaedrich
Copy link
Contributor

You're welcome. I hope, I didn't come off as snippy when simply replying "Just change replaceWhileKeepingCase()" earlier today.

@achrafAa
Copy link
Contributor Author

achrafAa commented Nov 5, 2025

@shaedrich not at all, we are here to help each other 😁👍♥️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants