From 5b604e19f2b8bd95b72cd8e6a82e7164d9b05537 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 27 Apr 2021 15:40:27 +0200 Subject: [PATCH] [6.x] Fix nullable values for required_if (#37128) * Fix nullable values for required_if * Reword null value --- .../Validation/Concerns/FormatsMessages.php | 4 + .../Concerns/ValidatesAttributes.php | 82 +++++++++++++++---- tests/Validation/ValidationValidatorTest.php | 33 +++++++- 3 files changed, 101 insertions(+), 18 deletions(-) diff --git a/src/Illuminate/Validation/Concerns/FormatsMessages.php b/src/Illuminate/Validation/Concerns/FormatsMessages.php index 9d011892aaf7..737d4173d174 100644 --- a/src/Illuminate/Validation/Concerns/FormatsMessages.php +++ b/src/Illuminate/Validation/Concerns/FormatsMessages.php @@ -336,6 +336,10 @@ public function getDisplayableValue($attribute, $value) return $value ? 'true' : 'false'; } + if (is_null($value)) { + return 'empty'; + } + return $value; } diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 68b38aa8491c..034e7db049a6 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -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); } @@ -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)); } /** @@ -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; } /** @@ -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]; } @@ -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". * @@ -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); } /** diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 2938f18e92b0..b90b7cfdb373 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -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()