@@ -41,7 +41,35 @@ public function validate( array $fieldDefs, array $values ): array
4141
4242 $ label = $ field ['label ' ] ?? $ name ;
4343 $ required = (bool ) ( $ field ['required ' ] ?? false );
44+ $ type = $ field ['type ' ] ?? 'text ' ;
4445 $ raw = $ values [ $ name ] ?? null ;
46+
47+ if ( $ type === 'checkboxes ' || $ type === 'multiselect ' )
48+ {
49+ $ selected = is_array ( $ raw )
50+ ? $ raw
51+ : ( ( $ raw === null || $ raw === '' ) ? [] : [ $ raw ] );
52+
53+ if ( empty ( $ selected ) )
54+ {
55+ if ( $ required )
56+ {
57+ $ errors [ $ name ] = "{$ label } is required. " ;
58+ }
59+
60+ continue ;
61+ }
62+
63+ $ error = $ this ->validateMultiple ( $ field , $ label , $ selected );
64+
65+ if ( $ error !== null )
66+ {
67+ $ errors [ $ name ] = $ error ;
68+ }
69+
70+ continue ;
71+ }
72+
4573 $ value = is_string ( $ raw ) ? trim ( $ raw ) : $ raw ;
4674 $ isEmpty = ( $ value === null || $ value === '' || $ value === [] );
4775
@@ -90,11 +118,11 @@ private function validateField( array $field, string $label, string $value ): ?s
90118 return "{$ label } must be a valid phone number. " ;
91119 }
92120
93- if ( $ type === 'select ' )
121+ if ( $ type === 'select ' || $ type === ' radio ' )
94122 {
95- $ options = $ field[ ' options ' ] ?? [] ;
123+ $ allowed = FieldOptions:: allowedValues ( $ field ) ;
96124
97- if ( !empty ( $ options ) && !new IsInSet ( $ options )->isValid ( $ value ) )
125+ if ( !empty ( $ allowed ) && !new IsInSet ( $ allowed )->isValid ( $ value ) )
98126 {
99127 return "{$ label } is not a valid selection. " ;
100128 }
@@ -119,6 +147,45 @@ private function validateField( array $field, string $label, string $value ): ?s
119147 return null ;
120148 }
121149
150+ /**
151+ * Validate the selected values of a multi-select (checkboxes/multiselect)
152+ * field: every selection must belong to the configured option set, and an
153+ * optional count rule (rules.count.min/max) is enforced.
154+ *
155+ * @param array $field Field definition
156+ * @param string $label Display label
157+ * @param array $selected Selected values
158+ * @return string|null Error message, or null when valid
159+ */
160+ private function validateMultiple ( array $ field , string $ label , array $ selected ): ?string
161+ {
162+ $ allowed = FieldOptions::allowedValues ( $ field );
163+
164+ foreach ( $ selected as $ value )
165+ {
166+ if ( !is_scalar ( $ value ) || !in_array ( (string ) $ value , $ allowed , true ) )
167+ {
168+ return "{$ label } contains an invalid selection. " ;
169+ }
170+ }
171+
172+ $ rules = $ field ['rules ' ] ?? [];
173+
174+ if ( isset ( $ rules ['count ' ] ) )
175+ {
176+ $ min = (int ) ( $ rules ['count ' ]['min ' ] ?? 0 );
177+ $ max = (int ) ( $ rules ['count ' ]['max ' ] ?? PHP_INT_MAX );
178+ $ count = count ( $ selected );
179+
180+ if ( $ count < $ min || $ count > $ max )
181+ {
182+ return "Please select between {$ min } and {$ max } options for {$ label }. " ;
183+ }
184+ }
185+
186+ return null ;
187+ }
188+
122189 /**
123190 * Lenient phone validation suitable for a public contact form.
124191 *
0 commit comments