PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.0-beta3
Elementor Website Builder – more than just a page builder v4.3.0-beta3
4.3.1 4.3.0 4.3.0-beta3 4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 All 454 releases
elementor / vendor / wordpress / php-mcp-schema / src / Common / Traits / ValidatesRequiredFields.php

ValidatesRequiredFields.php in Elementor Website Builder – more than just a page builder 4.3.0-beta3, at vendor/wordpress/php-mcp-schema/src/Common/Traits/ValidatesRequiredFields.php

413 lines 11.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace WP\McpSchema\Common\Traits;
6
7 /**
8 * Trait for validating required fields in fromArray() methods.
9 *
10 * Use this trait in DTOs that need to validate required fields from input arrays.
11 * Reports ALL missing fields at once for better developer experience.
12 *
13 * @mcp-version 2025-11-25
14 */
15 trait ValidatesRequiredFields
16 {
17 /**
18 * Validates that all required fields are present in the data array.
19 *
20 * @param array<string, mixed> $data The input data array
21 * @param string[] $requiredFields List of required field names
22 * @return void
23 * @throws \InvalidArgumentException If any required fields are missing
24 */
25 protected static function assertRequired(array $data, array $requiredFields): void
26 {
27 $missing = array_filter(
28 $requiredFields,
29 static fn(string $field): bool => !array_key_exists($field, $data)
30 );
31
32 if (count($missing) > 0) {
33 throw new \InvalidArgumentException(sprintf(
34 '%s: missing required field(s): %s',
35 static::class,
36 implode(', ', $missing)
37 ));
38 }
39 }
40
41 /**
42 * Asserts a value is a string and returns it.
43 *
44 * @param mixed $value
45 * @return string
46 * @phpstan-assert string $value
47 */
48 protected static function asString($value): string
49 {
50 if (!is_string($value)) {
51 throw new \InvalidArgumentException(sprintf(
52 'Expected string, got %s',
53 gettype($value)
54 ));
55 }
56 return $value;
57 }
58
59 /**
60 * Asserts a value is an int and returns it.
61 *
62 * @param mixed $value
63 * @return int
64 * @phpstan-assert int $value
65 */
66 protected static function asInt($value): int
67 {
68 if (!is_int($value)) {
69 throw new \InvalidArgumentException(sprintf(
70 'Expected int, got %s',
71 gettype($value)
72 ));
73 }
74 return $value;
75 }
76
77 /**
78 * Asserts a value is a float and returns it.
79 *
80 * @param mixed $value
81 * @return float
82 * @phpstan-assert float $value
83 */
84 protected static function asFloat($value): float
85 {
86 if (!is_float($value) && !is_int($value)) {
87 throw new \InvalidArgumentException(sprintf(
88 'Expected float, got %s',
89 gettype($value)
90 ));
91 }
92 return (float) $value;
93 }
94
95 /**
96 * Asserts a value is a bool and returns it.
97 *
98 * @param mixed $value
99 * @return bool
100 * @phpstan-assert bool $value
101 */
102 protected static function asBool($value): bool
103 {
104 if (!is_bool($value)) {
105 throw new \InvalidArgumentException(sprintf(
106 'Expected bool, got %s',
107 gettype($value)
108 ));
109 }
110 return $value;
111 }
112
113 /**
114 * Asserts a value is an array and returns it.
115 *
116 * @param mixed $value
117 * @return array<string, mixed>
118 * @phpstan-assert array<string, mixed> $value
119 */
120 protected static function asArray($value): array
121 {
122 if (!is_array($value)) {
123 throw new \InvalidArgumentException(sprintf(
124 'Expected array, got %s',
125 gettype($value)
126 ));
127 }
128 /** @var array<string, mixed> */
129 return $value;
130 }
131
132 /**
133 * Returns a value as string or null.
134 *
135 * @param mixed $value
136 * @return string|null
137 */
138 protected static function asStringOrNull($value): ?string
139 {
140 return $value === null ? null : self::asString($value);
141 }
142
143 /**
144 * Returns a value as int or null.
145 *
146 * @param mixed $value
147 * @return int|null
148 */
149 protected static function asIntOrNull($value): ?int
150 {
151 return $value === null ? null : self::asInt($value);
152 }
153
154 /**
155 * Returns a value as float or null.
156 *
157 * @param mixed $value
158 * @return float|null
159 */
160 protected static function asFloatOrNull($value): ?float
161 {
162 return $value === null ? null : self::asFloat($value);
163 }
164
165 /**
166 * Returns a value as bool or null.
167 *
168 * @param mixed $value
169 * @return bool|null
170 */
171 protected static function asBoolOrNull($value): ?bool
172 {
173 return $value === null ? null : self::asBool($value);
174 }
175
176 /**
177 * Returns a value as array or null.
178 *
179 * @param mixed $value
180 * @return array<string, mixed>|null
181 */
182 protected static function asArrayOrNull($value): ?array
183 {
184 return $value === null ? null : self::asArray($value);
185 }
186
187 /**
188 * Returns the entries of $data whose keys the caller does not model.
189 *
190 * Used by types the MCP schema declares open (`[key: string]: unknown`),
191 * so that unrecognized fields survive a fromArray()/toArray() round trip
192 * instead of being silently discarded.
193 *
194 * @param array<string, mixed> $data
195 * @param array<int, string> $known
196 * @return array<string, mixed>|null
197 */
198 protected static function additionalFields(array $data, array $known): ?array
199 {
200 $additional = array_diff_key($data, array_flip($known));
201
202 return $additional === [] ? null : $additional;
203 }
204
205 /**
206 * Asserts a value is an object and returns it.
207 *
208 * Accepts both PHP arrays and objects, auto-converting arrays to objects.
209 * This aligns with MCP spec where JSON objects can be PHP arrays or objects.
210 *
211 * @param mixed $value
212 * @return object
213 * @phpstan-assert object $value
214 */
215 protected static function asObject($value): object
216 {
217 if (is_array($value)) {
218 return (object) $value;
219 }
220 if (!is_object($value)) {
221 throw new \InvalidArgumentException(sprintf(
222 'Expected array or object, got %s',
223 gettype($value)
224 ));
225 }
226 return $value;
227 }
228
229 /**
230 * Returns a value as object or null.
231 *
232 * @param mixed $value
233 * @return object|null
234 */
235 protected static function asObjectOrNull($value): ?object
236 {
237 return $value === null ? null : self::asObject($value);
238 }
239
240 /**
241 * Asserts a value is an array of strings and returns it.
242 *
243 * @param mixed $value
244 * @return array<int, string>
245 */
246 protected static function asStringArray($value): array
247 {
248 if (!is_array($value)) {
249 throw new \InvalidArgumentException(sprintf(
250 'Expected array, got %s',
251 gettype($value)
252 ));
253 }
254 /** @var array<int, string> */
255 return array_values(array_map(static fn($item): string => (string) $item, $value));
256 }
257
258 /**
259 * Returns a value as array of strings or null.
260 *
261 * @param mixed $value
262 * @return array<int, string>|null
263 */
264 protected static function asStringArrayOrNull($value): ?array
265 {
266 return $value === null ? null : self::asStringArray($value);
267 }
268
269 /**
270 * Asserts a value is an associative array with string values only.
271 *
272 * Used for MCP types like { [key: string]: string } index signatures.
273 *
274 * @param mixed $value
275 * @return array<string, string>
276 * @phpstan-assert array<string, string> $value
277 */
278 protected static function asStringMap($value): array
279 {
280 if (!is_array($value)) {
281 throw new \InvalidArgumentException(sprintf(
282 'Expected array, got %s',
283 gettype($value)
284 ));
285 }
286 foreach ($value as $key => $v) {
287 if (!is_string($v)) {
288 throw new \InvalidArgumentException(sprintf(
289 'Expected string value for key "%s", got %s',
290 (string) $key,
291 gettype($v)
292 ));
293 }
294 }
295 /** @var array<string, string> */
296 return $value;
297 }
298
299 /**
300 * Returns a value as string map or null.
301 *
302 * Used for optional MCP types like { [key: string]: string } | null.
303 *
304 * @param mixed $value
305 * @return array<string, string>|null
306 */
307 protected static function asStringMapOrNull($value): ?array
308 {
309 return $value === null ? null : self::asStringMap($value);
310 }
311
312 /**
313 * Asserts a value is an associative array with object values only.
314 *
315 * Used for MCP types like { [key: string]: object } index signatures.
316 * Accepts both PHP arrays and objects as values, auto-converting arrays to objects.
317 * This aligns with MCP spec where JSON objects can be PHP arrays or objects.
318 *
319 * @param mixed $value
320 * @return array<string, object>
321 * @phpstan-assert array<string, object> $value
322 */
323 protected static function asObjectMap($value): array
324 {
325 if (!is_array($value)) {
326 throw new \InvalidArgumentException(sprintf(
327 'Expected array, got %s',
328 gettype($value)
329 ));
330 }
331
332 $result = [];
333 foreach ($value as $key => $v) {
334 if (is_array($v)) {
335 $result[$key] = (object) $v;
336 } elseif (is_object($v)) {
337 $result[$key] = $v;
338 } else {
339 throw new \InvalidArgumentException(sprintf(
340 'Expected array or object for key "%s", got %s',
341 (string) $key,
342 gettype($v)
343 ));
344 }
345 }
346
347 /** @var array<string, object> */
348 return $result;
349 }
350
351 /**
352 * Returns a value as object map or null.
353 *
354 * Used for optional MCP types like { [key: string]: object } | null.
355 *
356 * @param mixed $value
357 * @return array<string, object>|null
358 */
359 protected static function asObjectMapOrNull($value): ?array
360 {
361 return $value === null ? null : self::asObjectMap($value);
362 }
363
364 /**
365 * Asserts a value is a scalar (string, int, float, or bool) for sprintf.
366 *
367 * @param mixed $value
368 * @return string|int|float|bool
369 */
370 protected static function asScalar($value)
371 {
372 if (!is_scalar($value)) {
373 throw new \InvalidArgumentException(sprintf(
374 'Expected scalar value, got %s',
375 gettype($value)
376 ));
377 }
378 return $value;
379 }
380
381 /**
382 * Asserts a value is a string or number (int/float) and returns it.
383 *
384 * Used for MCP types like ProgressToken that accept string | number.
385 *
386 * @param mixed $value
387 * @return string|int|float
388 */
389 protected static function asStringOrNumber($value)
390 {
391 if (!is_string($value) && !is_int($value) && !is_float($value)) {
392 throw new \InvalidArgumentException(sprintf(
393 'Expected string or number, got %s',
394 gettype($value)
395 ));
396 }
397 return $value;
398 }
399
400 /**
401 * Returns a value as string or number (int/float), or null.
402 *
403 * Used for optional MCP types like ProgressToken that accept string | number | null.
404 *
405 * @param mixed $value
406 * @return string|int|float|null
407 */
408 protected static function asStringOrNumberOrNull($value)
409 {
410 return $value === null ? null : self::asStringOrNumber($value);
411 }
412 }
413