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 $ multiple = 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+ 'multipleMessage ' => 'The "{{ name }}" value has one or more invalid choices, "{{ value }}" given. Accepted values are: "{{ constraints }}". ' ,
26+ 'maxMessage ' => 'The "{{ name }}" value must have at most {{ maxConstraint }} choices, {{ numValues }} choices given. ' ,
27+ 'minMessage ' => 'The "{{ name }}" value must have at least {{ minConstraint }} choices, {{ numValues }} choices given. '
28+ ]);
29+
30+ $ resolver ->setAllowedTypes ('message ' , 'string ' );
31+ $ resolver ->setAllowedTypes ('multipleMessage ' , 'string ' );
32+ $ resolver ->setAllowedTypes ('maxMessage ' , 'string ' );
33+ $ resolver ->setAllowedTypes ('minMessage ' , 'string ' );
34+
35+ $ this ->options = $ resolver ->resolve ($ options );
36+ }
37+
38+ public function assert (mixed $ value , string $ name ): void
39+ {
40+ if ($ this ->multiple && !\is_array ($ value )) {
41+ throw new UnexpectedValueException (
42+ \sprintf ('Expected value of type "array" when multiple, "%s" given ' , get_debug_type ($ value ))
43+ );
44+ }
45+
46+ if ($ this ->multiple ) {
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+ }
0 commit comments