Lines 77.27% 17 / 22
Methods 50.00% 3 / 6
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 __construct 50.00% 1 / 2 0.00% 0 / 1 4.12
 defaultMessage 66.66% 2 / 3 0.00% 0 / 1 7.33
 validate 62.50% 5 / 8 0.00% 0 / 1 15.27
 unit 100.00% 1 / 1 100.00% 1 / 1 2
 [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
17final class Length extends Constraint
18{
19    /**
20     * Create a length constraint.
21     *
22     * @param int|null $min The minimum length, or null for no minimum.
23     * @param int|null $max The maximum length, or null for no maximum.
24     * @throws \InvalidArgumentException If both $min and $max are null.
25     */
26    public function __construct(private readonly int|null $min = null, private readonly int|null $max = null)
27    {
28        if ($min === null && $max === null) {
29            throw new \InvalidArgumentException('Length constraint requires at least one of $min or $max.');
30        }
31    }
32
33    /**
34     * @return string|Closure(FieldContext): string The default error message.
35     */
36    #[Override]
37    protected function defaultMessage(): string|Closure|null
38    {
39        return fn(FieldContext $ctx) => match (true) {
40            $this->min !== null && $this->max === null => "The {$ctx->field} field must be at least {$this->min} {$this->unit($ctx)} long.",
41            $this->min === null && $this->max !== null => "The {$ctx->field} field must not exceed {$this->max} {$this->unit($ctx)} long.",
42            default => "The {$ctx->field} field must be between {$this->min} and {$this->max} {$this->unit($ctx)} long."
43        };
44    }
45
46    /**
47     * Validate the length of a string or array value.
48     *
49     * Strings are measured in characters (via `mb_strlen`), arrays in item
50     * count. Non-string, non-array values always fail.
51     *
52     * @param FieldContext $ctx The context of the field being validated.
53     * @return bool True if the value is within the allowed length, false otherwise.
54     */
55    #[Override]
56    public function validate(FieldContext $ctx): bool
57    {
58        $length = match (true) {
59            is_string($ctx->value) => mb_strlen($ctx->value),
60            is_array($ctx->value)  => count($ctx->value),
61            default                => null,
62        };
63
64        if ($length === null) {
65            return false;
66        }
67
68        return match (true) {
69            $this->min !== null && $length < $this->min => false,
70            $this->max !== null && $length > $this->max => false,
71            default => true
72        };
73    }
74
75    /**
76     * Describe the unit of measurement for the current value.
77     *
78     * @param FieldContext $ctx The context of the field being validated.
79     * @return string Either `items` for arrays or `characters` for strings.
80     */
81    private function unit(FieldContext $ctx): string
82    {
83        return is_array($ctx->value) ? 'items' : 'characters';
84    }
85}

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    }