Skip to content

Commit

Permalink
[6.x] Fix nullable values for required_if (#37128)
Browse files Browse the repository at this point in the history
* Fix nullable values for required_if

* Reword null value
  • Loading branch information
driesvints committed Apr 27, 2021
1 parent 8c61f6c commit 5b604e1
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 18 deletions.
4 changes: 4 additions & 0 deletions src/Illuminate/Validation/Concerns/FormatsMessages.php
Expand Up @@ -336,6 +336,10 @@ public function getDisplayableValue($attribute, $value)
return $value ? 'true' : 'false';
}

if (is_null($value)) {
return 'empty';
}

return $value;
}

Expand Down
82 changes: 65 additions & 17 deletions src/Illuminate/Validation/Concerns/ValidatesAttributes.php
Expand Up @@ -1420,9 +1420,13 @@ public function validateRequiredIf($attribute, $value, $parameters)
{
$this->requireParameterCount(2, $parameters, 'required_if');

if (! Arr::has($this->data, $parameters[0])) {
return true;
}

[$values, $other] = $this->prepareValuesAndOther($parameters);

if (in_array($other, $values, is_bool($other))) {
if (in_array($other, $values, is_bool($other) || is_null($other))) {
return $this->validateRequired($attribute, $value);
}

Expand All @@ -1441,9 +1445,13 @@ public function validateExcludeIf($attribute, $value, $parameters)
{
$this->requireParameterCount(2, $parameters, 'exclude_if');

if (! Arr::has($this->data, $parameters[0])) {
return true;
}

[$values, $other] = $this->prepareValuesAndOther($parameters);

return ! in_array($other, $values, is_bool($other));
return ! in_array($other, $values, is_bool($other) || is_null($other));
}

/**
Expand All @@ -1458,9 +1466,38 @@ public function validateExcludeUnless($attribute, $value, $parameters)
{
$this->requireParameterCount(2, $parameters, 'exclude_unless');

if (! Arr::has($this->data, $parameters[0])) {
return true;
}

[$values, $other] = $this->prepareValuesAndOther($parameters);

return in_array($other, $values, is_bool($other));
return in_array($other, $values, is_bool($other) || is_null($other));
}

/**
* Validate that an attribute exists when another attribute does not have a given value.
*
* @param string $attribute
* @param mixed $value
* @param mixed $parameters
* @return bool
*/
public function validateRequiredUnless($attribute, $value, $parameters)
{
$this->requireParameterCount(2, $parameters, 'required_unless');

if (! Arr::has($this->data, $parameters[0])) {
return true;
}

[$values, $other] = $this->prepareValuesAndOther($parameters);

if (! in_array($other, $values, is_bool($other) || is_null($other))) {
return $this->validateRequired($attribute, $value);
}

return true;
}

/**
Expand All @@ -1479,6 +1516,10 @@ protected function prepareValuesAndOther($parameters)
$values = $this->convertValuesToBoolean($values);
}

if ($this->shouldConvertToNull($parameters[0]) || is_null($other)) {
$values = $this->convertValuesToNull($values);
}

return [$values, $other];
}

Expand All @@ -1493,6 +1534,17 @@ protected function shouldConvertToBoolean($parameter)
return in_array('boolean', Arr::get($this->rules, $parameter, []));
}

/**
* Check if parameter should be converted to null.
*
* @param string $parameter
* @return bool
*/
protected function shouldConvertToNull($parameter)
{
return in_array('nullable', Arr::get($this->rules, $parameter, []));
}

/**
* Convert the given values to boolean if they are string "true" / "false".
*
Expand All @@ -1513,24 +1565,20 @@ protected function convertValuesToBoolean($values)
}

/**
* Validate that an attribute exists when another attribute does not have a given value.
* Convert the given values to null if they are string "null".
*
* @param string $attribute
* @param mixed $value
* @param mixed $parameters
* @return bool
* @param array $values
* @return array
*/
public function validateRequiredUnless($attribute, $value, $parameters)
protected function convertValuesToNull($values)
{
$this->requireParameterCount(2, $parameters, 'required_unless');

[$values, $other] = $this->prepareValuesAndOther($parameters);

if (! in_array($other, $values, is_bool($other))) {
return $this->validateRequired($attribute, $value);
}
return array_map(function ($value) {
if ($value === 'null') {
return null;
}

return true;
return $value;
}, $values);
}

/**
Expand Down
33 changes: 32 additions & 1 deletion tests/Validation/ValidationValidatorTest.php
Expand Up @@ -1094,13 +1094,44 @@ public function testRequiredIf()
$trans = $this->getIlluminateArrayTranslator();
$trans->addLines(['validation.required_if' => 'The :attribute field is required when :other is :value.'], 'en');
$v = new Validator($trans, ['foo' => 0], [
'foo' => 'required|boolean',
'foo' => 'nullable|required|boolean',
'bar' => 'required_if:foo,true',
'baz' => 'required_if:foo,false',
]);
$this->assertTrue($v->fails());
$this->assertCount(1, $v->messages());
$this->assertSame('The baz field is required when foo is 0.', $v->messages()->first('baz'));

$trans = $this->getIlluminateArrayTranslator();
$v = new Validator($trans, [], [
'foo' => 'nullable|boolean',
'baz' => 'nullable|required_if:foo,false',
]);
$this->assertTrue($v->passes());

$trans = $this->getIlluminateArrayTranslator();
$v = new Validator($trans, ['foo' => null], [
'foo' => 'nullable|boolean',
'baz' => 'nullable|required_if:foo,false',
]);
$this->assertTrue($v->passes());

$trans = $this->getIlluminateArrayTranslator();
$v = new Validator($trans, [], [
'foo' => 'nullable|boolean',
'baz' => 'nullable|required_if:foo,null',
]);
$this->assertTrue($v->passes());

$trans = $this->getIlluminateArrayTranslator();
$trans->addLines(['validation.required_if' => 'The :attribute field is required when :other is :value.'], 'en');
$v = new Validator($trans, ['foo' => null], [
'foo' => 'nullable|boolean',
'baz' => 'nullable|required_if:foo,null',
]);
$this->assertTrue($v->fails());
$this->assertCount(1, $v->messages());
$this->assertSame('The baz field is required when foo is empty.', $v->messages()->first('baz'));
}

public function testRequiredUnless()
Expand Down

0 comments on commit 5b604e1

Please sign in to comment.