Skip to content

Commit 7f4b3b3

Browse files
Do not use array_unique() in the Unique rule
The default value of the second argument of `array_unique()` is `SORT_STRING`. This means that it converts all values to strings. That was the reason we were using `SORT_REGULAR`, but when using `SORT_REGULAR`, the strings `14.1` and `14.10` are considered the same, even though they're different. This commit will change the `Unique` rule to implement its own way of detecting uniqueness. This was necessary because `array_unique() 's limitation is handling different types in the same array. Co-authored-by: Henrique Moody <henriquemoody@gmail.com>
1 parent 8fd915c commit 7f4b3b3

2 files changed

Lines changed: 64 additions & 20 deletions

File tree

library/Rules/Unique.php

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@
99

1010
namespace Respect\Validation\Rules;
1111

12-
use function array_unique;
12+
use function array_is_list;
13+
use function in_array;
1314
use function is_array;
1415

15-
use const SORT_REGULAR;
16-
1716
/**
1817
* Validates whether the input array contains only unique values.
1918
*
@@ -32,6 +31,34 @@ public function validate($input): bool
3231
return false;
3332
}
3433

35-
return $input == array_unique($input, SORT_REGULAR);
34+
return $input == $this->unique($input);
35+
}
36+
37+
/**
38+
* @param array<mixed, mixed> $input
39+
*
40+
* @return array<mixed, mixed>
41+
*/
42+
private function unique(array $input): array
43+
{
44+
if (!array_is_list($input)) {
45+
return $input;
46+
}
47+
48+
$unique = [];
49+
foreach ($input as $value) {
50+
$comparedValue = $value;
51+
if (is_array($comparedValue)) {
52+
$comparedValue = $this->unique($comparedValue);
53+
}
54+
55+
if (in_array($comparedValue, $unique, true)) {
56+
continue;
57+
}
58+
59+
$unique[] = $comparedValue;
60+
}
61+
62+
return $unique;
3663
}
3764
}

tests/unit/Rules/UniqueTest.php

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,24 @@ public static function providerForValidInput(): array
3030
$rule = new Unique();
3131

3232
return [
33-
[$rule, []],
34-
[$rule, [1, 2, 3]],
35-
[$rule, [true, false]],
36-
[$rule, ['alpha', 'beta', 'gamma', 'delta']],
37-
[$rule, [0, 2.71, 3.14]],
38-
[$rule, [[], ['str'], [1]]],
39-
[$rule, [(object) ['key' => 'value'], (object) ['other_key' => 'value']]],
33+
'empty' => [$rule, []],
34+
'integers' => [$rule, [1, 2, 3]],
35+
'booleans' => [$rule, [true, false]],
36+
'strings' => [$rule, ['alpha', 'beta', 'gamma', 'delta']],
37+
'floats' => [$rule, [2.71, 1.3, 3.14]],
38+
'numeric strings' => [$rule, ['14.0', '14.1', '14.10']],
39+
'integers + booleans' => [$rule, [1, true]],
40+
'integers + floats' => [$rule, [2.0, 2, 3.14]],
41+
'integers + floats + strings' => [$rule, [14.0, '14', '14.0']],
42+
'arrays' => [$rule, [[], ['str'], [1]]],
43+
'arrays (multidimensional)' => [
44+
$rule, [
45+
['key' => ['id' => 123, 'name' => 'Something']],
46+
['key' => ['id' => 122, 'name' => 'Something else']],
47+
],
48+
],
49+
'objects' => [$rule, [(object) ['key' => 'value'], (object) ['other_key' => 'value']]],
50+
'objects (same properties)' => [$rule, [(object) ['key' => 'value'], (object) ['key' => 'value']]],
4051
];
4152
}
4253

@@ -46,17 +57,23 @@ public static function providerForValidInput(): array
4657
public static function providerForInvalidInput(): array
4758
{
4859
$rule = new Unique();
60+
$object = (object) ['key' => 'value'];
4961

5062
return [
51-
[$rule, 'test'],
52-
[$rule, [1, 2, 2, 3]],
53-
[$rule, [1, 2, 3, 1]],
54-
[$rule, [true, false, false]],
55-
[$rule, ['alpha', 'beta', 'gamma', 'delta', 'beta']],
56-
[$rule, [0, 3.14, 2.71, 3.14]],
57-
[$rule, [[], [1], [1]]],
58-
[$rule, [(object) ['key' => 'value'], (object) ['key' => 'value']]],
59-
[$rule, [1, true, 'test']], // PHP's array_unique treats 1 and true as equal
63+
'string' => [$rule, 'test'],
64+
'integers (2nd & 3rd)' => [$rule, [1, 2, 2, 3]],
65+
'integers (2nd & 4th)' => [$rule, [1, 2, 3, 1]],
66+
'booleans' => [$rule, [true, false, false]],
67+
'strings' => [$rule, ['alpha', 'beta', 'gamma', 'delta', 'beta']],
68+
'integers + floats' => [$rule, [0, 3.14, 2.71, 3.14]],
69+
'arrays' => [$rule, [[], [1], [1]]],
70+
'objects (single instance)' => [$rule, [$object, $object]],
71+
'arrays (multidimensional)' => [
72+
$rule, [
73+
['key' => ['id' => 123, 'name' => 'Something']],
74+
['key' => ['id' => 123, 'name' => 'Something']],
75+
],
76+
],
6077
];
6178
}
6279
}

0 commit comments

Comments
 (0)