Skip to content
This repository has been archived by the owner on Jul 16, 2021. It is now read-only.

The validations related to null, empty, present, optional and required are extremely confusing. #524

Open
miklcct opened this issue Apr 11, 2017 · 1 comment

Comments

@miklcct
Copy link

miklcct commented Apr 11, 2017

The validations related to presence / null / etc. are extremely confusing such that multiple bug reports are submitted and even the documentation is even wrong:

laravel/framework#17663
#472
laravel/framework#18376
https://github.com/laravel/docs/issues/3266

We can categorise the strength of existence to the following levels in order to better clarify the situation:

  1. The field does not exist in the input array.
  2. The field exists in the input array with the value null.
  3. The field exists in the input array with other empty values, such as empty strings, empty collections and empty arrays.
  4. The field exists and is not empty.

The present rule passes everything starting from level 1, and the required rule passes only level 3 fields.

According to the documentation:

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.

This suggests that normal validation rules will validate null fields. However, the documentation related to implicit extension says otherwise:

By default, when an attribute being validated is not present or contains an empty value as defined by the required rule, normal validation rules, including custom extensions, are not run.

I have submitted on bug report on this issue ( https://github.com/laravel/docs/issues/3266 ), however, as there are multiple rules related to existence, the behaviour is still very confusing, including:

  • Are non-implicit rules run if the field does not exist in the input array?
  • Are non-implicit rules run if the value is null?
  • Are non-implicit rules run on empty strings and empty collections?

I can find the answer only by looking at the implementation, and it is completely out of my expectation:
They are run if the field is present, with an exception that they are skipped if the value is a string with only blanks! This is mentioned nowhere in the documentation.

If the field is mixed with rules like nullable and sometimes, the situation is complicated further:

  • Are implicit / non-implicit rules run if the field does not exist / exists with the value null / exists with other empty values in the input array and marked nullable / sometimes?

After further reading the code, I still cannot understand what specifically these "marker" rules does. (Marker rules are used to modify the behaviour of validator but always returns true)

For nullable rule, originally it makes fields with existence level 0 or 1 (i.e. null or undefined) skips all checks, including implicit rules like required. Therefore, If I marked nullable on a field, I could null the field to pass the check or omit it together even it was required. Therefore I used required|nullable to invalidate empty strings, but allowed users to skip the fields.

However, laravel/framework#18173 modified the behaviour such that null but not undefined skips the checks, and laravel/framework#18376 further modified the behaviour such that only non-implicit rules but not implicit rules are skipped (i.e. we can no longer use nullable to skip required check, therefore, my use of required|nullable to invalidate empty strings now also invalidates null values as well, which is counter-intuitive).

Another related rule is sometimes, according to the code, it is used to skip all checks (including implicit and non-implicit) only if the field is not present (i.e. sometimes|present always validates, but sometimes|required invalidates null and empty), just like the use of nullable after pull request 18173 and before 18376, but with undefined instead of null.

Is it possible to rework these rules and implicit check and make the documentation more clear?

@Dylan-DPC-zz
Copy link

@miklcct to make the docs clearer, submit a PR on the laravel/docs repo.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants