From 40ba0d4ea6e177256acb8b98b4c1b19a07dbf4b6 Mon Sep 17 00:00:00 2001 From: CorvusSharp <90767809+CorvusSharp@users.noreply.github.com> Date: Fri, 11 Sep 2026 07:57:08 +0300 Subject: [PATCH 1/2] Fix UniqueIterable comparing the whole iterable instead of its items --- src/Rule/UniqueIterableHandler.php | 18 ++++----- tests/Rule/UniqueIterableTest.php | 61 ++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/Rule/UniqueIterableHandler.php b/src/Rule/UniqueIterableHandler.php index a06cb7a32..31f1ecf05 100644 --- a/src/Rule/UniqueIterableHandler.php +++ b/src/Rule/UniqueIterableHandler.php @@ -57,20 +57,20 @@ public function validate(mixed $value, RuleInterface $rule, ValidationContext $c $previousItem = $item; - if (!empty($stack) && count($stack) !== count(array_unique($stack, flags: SORT_REGULAR))) { + if ($item instanceof DateTimeInterface) { + $stack[] = $item->getTimestamp(); + } elseif ($item instanceof Stringable) { + $stack[] = (string) $item; + } else { + $stack[] = $item; + } + + if (count($stack) !== count(array_unique($stack, flags: SORT_REGULAR))) { return (new Result())->addError($rule->getMessage(), [ 'property' => $context->getTranslatedProperty(), 'Property' => $context->getCapitalizedTranslatedProperty(), ]); } - - if ($value instanceof Stringable) { - $stack[] = (string) $value; - } elseif ($value instanceof DateTimeInterface) { - $stack[] = $value->getTimestamp(); - } else { - $stack[] = $value; - } } return new Result(); diff --git a/tests/Rule/UniqueIterableTest.php b/tests/Rule/UniqueIterableTest.php index d2f835c0e..e35aa33f8 100644 --- a/tests/Rule/UniqueIterableTest.php +++ b/tests/Rule/UniqueIterableTest.php @@ -120,6 +120,40 @@ public function __toString() [new DateTime('2024-04-10 14:05:01'), new DateTime('2024-04-10 14:05:02')], new UniqueIterable(), ], + 'more than two unique strings' => [['a', 'b', 'c'], new UniqueIterable()], + 'more than two unique integers' => [[1, 2, 3, 4], new UniqueIterable()], + 'more than two unique floats' => [[1.5, 2.5, 3.5], new UniqueIterable()], + 'more than two unique stringable values' => [ + [ + new class implements Stringable { + public function __toString() + { + return 'a'; + } + }, + new class implements Stringable { + public function __toString() + { + return 'b'; + } + }, + new class implements Stringable { + public function __toString() + { + return 'c'; + } + }, + ], + new UniqueIterable(), + ], + 'more than two unique datetime values' => [ + [ + new DateTime('2024-04-10 14:05:01'), + new DateTime('2024-04-10 14:05:02'), + new DateTime('2024-04-10 14:05:03'), + ], + new UniqueIterable(), + ], 'using as attribute' => [ new class { #[UniqueIterable] @@ -213,6 +247,33 @@ public function getRules(): array null, ['data' => ['"Данные" - в списке есть недопустимое значение.']], ], + 'two equal strings' => [['a', 'a'], new UniqueIterable(), ['' => [$message]]], + 'two equal integers' => [[1, 1], new UniqueIterable(), ['' => [$message]]], + 'two equal floats' => [[1.5, 1.5], new UniqueIterable(), ['' => [$message]]], + 'two equal boolean values' => [[true, true], new UniqueIterable(), ['' => [$message]]], + 'two equal stringable values' => [ + [ + new class implements Stringable { + public function __toString() + { + return 'a'; + } + }, + new class implements Stringable { + public function __toString() + { + return 'a'; + } + }, + ], + new UniqueIterable(), + ['' => [$message]], + ], + 'two equal datetime values' => [ + [new DateTime('2024-04-10 14:05:01'), new DateTime('2024-04-10 14:05:01')], + new UniqueIterable(), + ['' => [$message]], + ], 'strings' => [['a', 'b', 'a', 'c'], new UniqueIterable(), ['' => [$message]]], 'integers' => [[1, 2, 1, 3], new UniqueIterable(), ['' => [$message]]], 'floats' => [[1.5, 2.5, 1.5, 3.5], new UniqueIterable(), ['' => [$message]]], From 27e48fcdf14e3cdf472b3af5c90dde82f4337d07 Mon Sep 17 00:00:00 2001 From: CorvusSharp <90767809+CorvusSharp@users.noreply.github.com> Date: Fri, 11 Sep 2026 07:57:42 +0300 Subject: [PATCH 2/2] Add changelog entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d91eca83..e180762aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 2.6.1 under development -- no changes in this release. +- Bug #816: Fix `UniqueIterable` comparing the whole iterable instead of its items (@CorvusSharp) ## 2.6.0 June 02, 2026