Lines 100.00% 18 / 18
Methods 100.00% 4 / 4
Classes 100.00% 1 / 1
Name Lines Methods CRAP
 defaultMessage 100.00% 1 / 1 100.00% 1 / 1 1
 validate 100.00% 9 / 9 100.00% 1 / 1 4
 [Lucent\Validation\Constraint] withMessage 100.00% 2 / 2 100.00% 1 / 1 1
 [Lucent\Validation\Constraint] message 100.00% 6 / 6 100.00% 1 / 1 3
18final class Distinct extends Constraint
19{
20    /**
21     * @return string|Closure(FieldContext): string The default error message.
22     */
23    #[Override]
24    protected function defaultMessage(): string|Closure|null
25    {
26        return fn(FieldContext $ctx) => "The {$ctx->field} must not contain duplicate values.";
27    }
28
29    /**
30     * Validate that all array elements are unique.
31     *
32     * Non-array values always fail. Elements are compared strictly, so
33     * `1` and `'1'` are considered distinct.
34     *
35     * @param FieldContext $ctx The context of the field being validated.
36     * @return bool True if the value is an array with unique elements, false otherwise.
37     */
38    #[Override]
39    public function validate(FieldContext $ctx): bool
40    {
41        if (!is_array($ctx->value)) {
42            return false;
43        }
44
45        $seen = [];
46
47        foreach ($ctx->value as $element) {
48            // Serialize each element so strict identity is preserved: `1` and
49            // `'1'` serialize differently and are treated as distinct, while
50            // two identical values collide on the same key.
51            $key = serialize($element);
52
53            if (isset($seen[$key])) {
54                return false;
55            }
56
57            $seen[$key] = true;
58        }
59
60        return true;
61    }
62}

Inherited from Lucent\Validation\Constraint

38    final public function withMessage(string|\Closure $message): static
39    {
40        $this->customMessage = $message;
41        return $this;
42    }
56    final public function message(FieldContext $ctx): ?string
57    {
58        $message = $this->customMessage ?? $this->defaultMessage();
59
60        if ($message === null) {
61            return null;
62        }
63
64        if ($message instanceof \Closure) {
65            return call_user_func($message, $ctx);
66        }
67
68        return $message;
69    }