1

I have to validate an input field of my API where the value has to be an integer between 1 and 100 or null or it is not even set (not required).

Thereby, my validation rule is: 'privacy_status' => "nullable|integer|min:1|max:100",

This works fine until I get an empty string as value. Since Laravel validation on a empty string validates only if field is implicit, all my other rules integer, nullable or min, max are ignored.

protected function isValidatable($rule, $attribute, $value)
{
    return $this->presentOrRuleIsImplicit($rule, $attribute, $value) &&
       $this->passesOptionalCheck($attribute) &&
       $this->isNotNullIfMarkedAsNullable($attribute, $value) &&
       $this->hasNotFailedPreviousRuleIfPresenceRule($rule, $attribute);
}

protected function presentOrRuleIsImplicit($rule, $attribute, $value)
{
    if (is_string($value) && trim($value) === '') {
        return $this->isImplicit($rule);
    }

    return $this->validatePresent($attribute, $value) || $this->isImplicit($rule);
}

Is there a way to validate this properly?

2 Answers 2

1

EDIT

You can always create a custom validation rule.

Validator::extendImplicit('fail_on_empty_string', function($attribute, $value, $parameters)
{
    return $value === "" ? false : $value;
});

You can use the new rule like this:

'privacy_status' => "fail_on_empty_string|nullable|integer|min:1|max:100",

Old answer

This is described in the Laravel documentation and is a bug you introduced yourself (though probably unconsciously): https://laravel.com/docs/5.6/validation#a-note-on-optional-fields:

By default, Laravel includes the TrimStrings and ConvertEmptyStringsToNull middleware in your application's global middleware stack. These middleware are listed in the stack by the App\Http\Kernel class. Because of this, you will often need to mark your "optional" request fields as nullable if you do not want the validator to consider null values as invalid.

Empty string are automatically cast to null, which by your validation is perfectly fine. Either disable the middleware, change it or alter your validation rules.

Sign up to request clarification or add additional context in comments.

4 Comments

my Laravel is not using those middleware, since i need to get empty strings as value of my JSON API in other occasions (if i need to get a string, not an integer), so the middleware is disabled. so the only option is to alter my validations rules, but no combination of validation rules fits my needs, at least not the one i tried till now
Oof, that's nasty. Updated my answer, couldn't think of a way to do this without custom code.
too bad there is no "normal" way to achieve this, but like this it works perfectly thank you very much
had to change to return $value !== ""; since validation of null failed otherwise
0

You can simply pass it the filled rule. This will allow the field to be nullable, and if it's present in the request; it cannot be empty.

'privacy_policy' => 'filled|integer|min:1|max:100'

If you want to allow the empty string when it's present, change to present rule instead.

'privacy_policy' => 'present|nullable|integer|min:1|max:100'

Update

I've added an unit test to prove that this is working properly.

public function index()
{
    request()->validate([
        'privacy_policy' => 'filled|integer|min:1|max:100'
    ]);

    return response();
}

Then in the test:

$this->get(route('test'))->assertStatus(200); // True
$this->get(route('test'), ['privacy_policy' => ''])->assertStatus(200); // False
$this->get(route('test'), ['privacy_policy' => 5])->assertStatus(200); // True

7 Comments

filled and nullable don't work with each other (worked till laravel 5.4 i think) get: The privacy status field is required
@braun_lukas Then why don't you simply use the required rule?
since i have implementations of the API out there, that do not send me the new attribute.
@braun_lukas Okay then I think the filled one is perfect for you. It's either not in the request, or if it's in the request, it has to have a value.
like i allready stated filled and nullable do not work with each other, since filled requires the attribute not to be null
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.