Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 2dc872e

Browse files
committed
feat: added Choice rule
1 parent 7d4cab3 commit 2dc872e

5 files changed

Lines changed: 115 additions & 0 deletions

File tree

src/ChainedValidatorInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ public function notBlank(array $options = []): ChainedValidatorInterface;
2020
public function greaterThan(mixed $constraint, array $options = []): ChainedValidatorInterface;
2121

2222
public function lessThan(mixed $constraint, array $options = []): ChainedValidatorInterface;
23+
24+
public function choice(array $constraints, bool $isMultiple = false, ?int $minConstraint = null, ?int $maxConstraint = null, array $options = []): ChainedValidatorInterface;
2325
}

src/Exception/ChoiceException.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\YetAnotherPhpValidator\Exception;
4+
5+
class ChoiceException extends ValidationException {}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\YetAnotherPhpValidator\Exception;
4+
5+
class UnexpectedValueException extends \UnexpectedValueException {}

src/Rule/Choice.php

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
namespace ProgrammatorDev\YetAnotherPhpValidator\Rule;
4+
5+
use ProgrammatorDev\YetAnotherPhpValidator\Exception\ChoiceException;
6+
use ProgrammatorDev\YetAnotherPhpValidator\Exception\UnexpectedValueException;
7+
use Symfony\Component\OptionsResolver\OptionsResolver;
8+
9+
class Choice extends AbstractRule implements RuleInterface
10+
{
11+
private array $options;
12+
13+
public function __construct(
14+
private readonly array $constraints,
15+
private readonly bool $isMultiple = false,
16+
private readonly ?int $minConstraint = null,
17+
private readonly ?int $maxConstraint = null,
18+
array $options = []
19+
)
20+
{
21+
$resolver = new OptionsResolver();
22+
23+
$resolver->setDefaults([
24+
'message' => 'The "{{ name }}" value is not a valid choice, "{{ value }}" given. Accepted values are: "{{ constraints }}".',
25+
'maxMessage' => 'The "{{ name }}" value must have at most {{ maxConstraint }} choices, {{ numValues }} choices given.',
26+
'minMessage' => 'The "{{ name }}" value must have at least {{ minConstraint }} choices, {{ numValues }} choices given.',
27+
'multipleMessage' => 'The "{{ name }}" value has one or more invalid choices, "{{ value }}" given. Accepted values are: "{{ constraints }}".'
28+
]);
29+
30+
$resolver->setAllowedTypes('message', 'string');
31+
$resolver->setAllowedTypes('maxMessage', 'string');
32+
$resolver->setAllowedTypes('minMessage', 'string');
33+
$resolver->setAllowedTypes('multipleMessage', 'string');
34+
35+
$this->options = $resolver->resolve($options);
36+
}
37+
38+
public function assert(mixed $value, string $name): void
39+
{
40+
if ($this->isMultiple && !\is_array($value)) {
41+
throw new UnexpectedValueException(
42+
\sprintf('Expected value of type "array", "%s" given', get_debug_type($value))
43+
);
44+
}
45+
46+
if ($this->isMultiple) {
47+
foreach ($value as $input) {
48+
if (!\in_array($input, $this->constraints, true)) {
49+
throw new ChoiceException(
50+
message: $this->options['multipleMessage'],
51+
parameters: [
52+
'value' => $value,
53+
'name' => $name,
54+
'constraints' => $this->constraints
55+
]
56+
);
57+
}
58+
}
59+
60+
$numValues = \count($value);
61+
62+
if ($this->minConstraint !== null && $numValues < $this->minConstraint) {
63+
throw new ChoiceException(
64+
message: $this->options['minMessage'],
65+
parameters: [
66+
'value' => $value,
67+
'numValues' => $numValues,
68+
'name' => $name,
69+
'constraints' => $this->constraints,
70+
'minConstraint' => $this->minConstraint,
71+
'maxConstraint' => $this->maxConstraint
72+
]
73+
);
74+
}
75+
76+
if ($this->maxConstraint !== null && $numValues > $this->maxConstraint) {
77+
throw new ChoiceException(
78+
message: $this->options['maxMessage'],
79+
parameters: [
80+
'value' => $value,
81+
'numValues' => $numValues,
82+
'name' => $name,
83+
'constraints' => $this->constraints,
84+
'minConstraint' => $this->minConstraint,
85+
'maxConstraint' => $this->maxConstraint
86+
]
87+
);
88+
}
89+
}
90+
else if (!\in_array($value, $this->constraints, true)) {
91+
throw new ChoiceException(
92+
message: $this->options['message'],
93+
parameters: [
94+
'value' => $value,
95+
'name' => $name,
96+
'constraints' => $this->constraints
97+
]
98+
);
99+
}
100+
}
101+
}

src/StaticValidatorInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@ public static function notBlank(array $options = []): ChainedValidatorInterface;
99
public static function greaterThan(mixed $constraint, array $options = []): ChainedValidatorInterface;
1010

1111
public static function lessThan(mixed $constraint, array $options = []): ChainedValidatorInterface;
12+
13+
public static function choice(array $constraints, bool $isMultiple = false, ?int $minConstraint = null, ?int $maxConstraint = null, array $options = []): ChainedValidatorInterface;
1214
}

0 commit comments

Comments
 (0)