Skip to content

fix: validation rule matches and differs #8122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions system/Validation/Rules.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ class Rules
/**
* The value does not match another field in $data.
*
* @param array $data Other field/value pairs
* @param string|null $str
* @param array $data Other field/value pairs
*/
public function differs(?string $str, string $field, array $data): bool
public function differs($str, string $field, array $data): bool
{
if (strpos($field, '.') !== false) {
return $str !== dot_array_search($field, $data);
Expand Down Expand Up @@ -177,15 +178,16 @@ public function less_than_equal_to(?string $str, string $max): bool
/**
* Matches the value of another field in $data.
*
* @param array $data Other field/value pairs
* @param string|null $str
* @param array $data Other field/value pairs
*/
public function matches(?string $str, string $field, array $data): bool
public function matches($str, string $field, array $data): bool
{
if (strpos($field, '.') !== false) {
return $str === dot_array_search($field, $data);
}

return array_key_exists($field, $data) && $str === $data[$field];
return isset($data[$field]) && $str === $data[$field];
}

/**
Expand Down
44 changes: 37 additions & 7 deletions system/Validation/StrictRules/Rules.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,26 @@ public function __construct()
* @param array|bool|float|int|object|string|null $str
* @param array $data Other field/value pairs
*/
public function differs($str, string $field, array $data): bool
{
if (! is_string($str)) {
public function differs(
$str,
string $otherField,
array $data,
?string $error = null,
?string $field = null
): bool {
if (strpos($otherField, '.') !== false) {
return $str !== dot_array_search($otherField, $data);
}

if (! array_key_exists($field, $data)) {
return false;
}

return $this->nonStrictRules->differs($str, $field, $data);
if (! array_key_exists($otherField, $data)) {
return false;
}

return $str !== ($data[$otherField] ?? null);
}

/**
Expand Down Expand Up @@ -254,9 +267,26 @@ public function less_than_equal_to($str, string $max): bool
* @param array|bool|float|int|object|string|null $str
* @param array $data Other field/value pairs
*/
public function matches($str, string $field, array $data): bool
{
return $this->nonStrictRules->matches($str, $field, $data);
public function matches(
$str,
string $otherField,
array $data,
?string $error = null,
?string $field = null
): bool {
if (strpos($otherField, '.') !== false) {
return $str === dot_array_search($otherField, $data);
}

if (! array_key_exists($field, $data)) {
return false;
}

if (! array_key_exists($otherField, $data)) {
return false;
}

return $str === ($data[$otherField] ?? null);
}

/**
Expand Down
35 changes: 28 additions & 7 deletions tests/system/Validation/RulesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -290,20 +290,26 @@ public static function providePermitEmpty(): iterable
}

/**
* @dataProvider provideMatchesCases
* @dataProvider provideMatches
*/
public function testMatches(array $data, bool $expected): void
{
$this->validation->setRules(['foo' => 'matches[bar]']);
$this->assertSame($expected, $this->validation->run($data));
}

public static function provideMatchesCases(): iterable
public static function provideMatches(): iterable
{
yield from [
[['foo' => null, 'bar' => null], true],
[['foo' => 'match', 'bar' => 'match'], true],
[['foo' => 'match', 'bar' => 'nope'], false],
'foo bar not exist' => [[], false],
'bar not exist' => [['foo' => null], false],
'foo not exist' => [['bar' => null], false],
'foo bar null' => [['foo' => null, 'bar' => null], false], // Strict Rule: true
'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], true],
'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], false],
'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], true],
'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], false],
'foo bar bool match' => [['foo' => true, 'bar' => true], true],
];
}

Expand All @@ -325,12 +331,27 @@ public static function provideMatchesNestedCases(): iterable
}

/**
* @dataProvider provideMatchesCases
* @dataProvider provideDiffers
*/
public function testDiffers(array $data, bool $expected): void
{
$this->validation->setRules(['foo' => 'differs[bar]']);
$this->assertSame(! $expected, $this->validation->run($data));
$this->assertSame($expected, $this->validation->run($data));
}

public static function provideDiffers(): iterable
{
yield from [
'foo bar not exist' => [[], false],
'bar not exist' => [['foo' => null], false],
'foo not exist' => [['bar' => null], false],
'foo bar null' => [['foo' => null, 'bar' => null], false],
'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], false],
'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], true],
'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], false],
'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], true],
'foo bar bool match' => [['foo' => true, 'bar' => true], false],
];
}

/**
Expand Down
48 changes: 48 additions & 0 deletions tests/system/Validation/StrictRules/RulesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,52 @@ public static function provideLessEqualThanStrict(): iterable
[true, '0', false],
];
}

/**
* @dataProvider provideMatches
*/
public function testMatches(array $data, bool $expected): void
{
$this->validation->setRules(['foo' => 'matches[bar]']);
$this->assertSame($expected, $this->validation->run($data));
}

public static function provideMatches(): iterable
{
yield from [
'foo bar not exist' => [[], false],
'bar not exist' => [['foo' => null], false],
'foo not exist' => [['bar' => null], false],
'foo bar null' => [['foo' => null, 'bar' => null], true],
'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], true],
'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], false],
'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], true],
'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], false],
'foo bar bool match' => [['foo' => true, 'bar' => true], true],
];
}

/**
* @dataProvider provideDiffers
*/
public function testDiffers(array $data, bool $expected): void
{
$this->validation->setRules(['foo' => 'differs[bar]']);
$this->assertSame($expected, $this->validation->run($data));
}

public static function provideDiffers(): iterable
{
yield from [
'foo bar not exist' => [[], false],
'bar not exist' => [['foo' => null], false],
'foo not exist' => [['bar' => null], false],
'foo bar null' => [['foo' => null, 'bar' => null], false],
'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], false],
'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], true],
'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], false],
'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], true],
'foo bar bool match' => [['foo' => true, 'bar' => true], false],
];
}
}
6 changes: 6 additions & 0 deletions user_guide_src/source/changelogs/v4.4.4.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ A validation rule with the wildcard ``*`` now validates only data in correct
dimensions as "dot array syntax".
See :ref:`Upgrading <upgrade-444-validation-with-dot-array-syntax>` for details.

Validation rules matches and differs
====================================

Bugs have been fixed in the case where ``matches`` and ``differs`` in the Strict
and Traditional rules validate data of non-string types.

***************
Message Changes
***************
Expand Down
11 changes: 11 additions & 0 deletions user_guide_src/source/installation/upgrade_444.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ The following code explains details:

If you have code that depends on the bug, fix the the rule key.

Validation rules matches and differs
====================================

Because bugs have been fixed in the case where ``matches`` and ``differs`` in
the Strict and Traditional rules validate data of non-string types, if you are
using these rules and validate non-string data, the validation results might be
changed (fixed).

Note that Traditional Rules should not be used to validate data that is not a
string.

*********************
Breaking Enhancements
*********************
Expand Down