Lines 100.00% 23 / 23
Methods 100.00% 6 / 6
Classes 100.00% 1 / 1
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 of 100.00% 1 / 1 100.00% 1 / 1 1
 defaultMessage 100.00% 3 / 3 100.00% 1 / 1 2
 validate 100.00% 10 / 10 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
19final class None extends Constraint
20{
21    /**
22     * @param array<int, Constraint> $constraints The constraints that must all fail.
23     */
24    private function __construct(private readonly array $constraints) {}
25
26    /**
27     * Create a "none" combinator from one or more constraints.
28     *
29     * @param Constraint ...$constraints The constraints that must all fail.
30     * @return self A new None instance.
31     */
32    public static function of(Constraint ...$constraints): self
33    {
34        return new self($constraints);
35    }
36
37    /**
38     * @return string|\Closure(FieldContext): ?string|null The default error message.
39     */
40    #[Override]
41    protected function defaultMessage(): string|\Closure|null
42    {
43        return fn(FieldContext $ctx) => $ctx->childFailed
44            ? null
45            : "The {$ctx->field} must not match any of the given rules.";
46    }
47
48    /**
49     * Validate that none of the wrapped constraints pass.
50     *
51     * Each constraint is validated in isolation. A failing constraint is the
52     * desired outcome, so it is simply skipped. If a constraint passes, the
53     * field fails: the generic "must not match" message is recorded first,
54     * followed by the matched constraint's message, so the user sees which
55     * rule the value matched (and therefore must not match).
56     *
57     * @param FieldContext $ctx The context of the field being validated.
58     * @return bool True if none of the constraints pass, false otherwise.
59     */
60    #[Override]
61    public function validate(FieldContext $ctx): bool
62    {
63        $ctx->childFailed = false;
64
65        foreach ($this->constraints as $constraint) {
66            if ($constraint->validate($ctx)) {
67                // A constraint matched — the field is invalid. Record the
68                // generic framing message first, then the matched
69                // constraint's message so the user sees which rule the value
70                // matched (and therefore must not match).
71                $message = $constraint->message($ctx);
72                if ($message !== null) {
73                    $ctx->result->addError($ctx->field, "The {$ctx->field} must not match any of the given rules.");
74                    $ctx->result->addError($ctx->field, $message);
75                }
76                $ctx->childFailed = true;
77                return false;
78            }
79        }
80
81        return true;
82    }
83}

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    }