Skip to content

Commit d7067f3

Browse files
committed
refactor(validation): move typed access to ValidatedInput
- add ValidatedInput for typed access to validated data - expose ValidatedInput from Validation and FormRequest - keep FormRequest focused on request validation flow - update docs and tests for the new typed input API Signed-off-by: memleakd <121398829+memleakd@users.noreply.github.com>
1 parent ed9d8b6 commit d7067f3

12 files changed

Lines changed: 600 additions & 472 deletions

File tree

system/HTTP/FormRequest.php

Lines changed: 8 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,9 @@
1313

1414
namespace CodeIgniter\HTTP;
1515

16-
use BackedEnum;
17-
use CodeIgniter\Exceptions\InvalidArgumentException;
1816
use CodeIgniter\Exceptions\RuntimeException;
19-
use CodeIgniter\I18n\Time;
20-
use DateTimeZone;
21-
use Exception;
22-
use ReflectionEnum;
2317
use ReflectionNamedType;
2418
use ReflectionParameter;
25-
use UnitEnum;
2619

2720
/**
2821
* @see \CodeIgniter\HTTP\FormRequestTest
@@ -189,6 +182,14 @@ public function validated(): array
189182
return $this->validatedData;
190183
}
191184

185+
/**
186+
* Returns the validated data as a typed input object.
187+
*/
188+
public function validatedInput(): ValidatedInput
189+
{
190+
return new ValidatedInput($this->validatedData);
191+
}
192+
192193
/**
193194
* Returns a single validated field value by name, or the default value
194195
* if the field is not present in the validated data.
@@ -206,134 +207,6 @@ public function getValidated(string $key, mixed $default = null): mixed
206207
return dot_array_search($key, $this->validatedData);
207208
}
208209

209-
/**
210-
* Returns a validated field as an integer.
211-
*
212-
* Supports dot-array syntax for nested validated data.
213-
*/
214-
public function integer(string $key, ?int $default = null): ?int
215-
{
216-
$value = $this->getValidated($key, $default);
217-
218-
if ($value === null || is_int($value)) {
219-
return $value;
220-
}
221-
222-
if (is_string($value)) {
223-
$integer = filter_var($value, FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
224-
225-
if ($integer !== null) {
226-
return $integer;
227-
}
228-
}
229-
230-
throw $this->invalidValidatedType($key, 'integer');
231-
}
232-
233-
/**
234-
* Returns a validated field as a boolean.
235-
*
236-
* Supports dot-array syntax for nested validated data.
237-
*/
238-
public function boolean(string $key, ?bool $default = null): ?bool
239-
{
240-
$value = $this->getValidated($key, $default);
241-
242-
if ($value === null || is_bool($value)) {
243-
return $value;
244-
}
245-
246-
if (is_int($value) || is_string($value)) {
247-
$boolean = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
248-
249-
if ($boolean !== null) {
250-
return $boolean;
251-
}
252-
}
253-
254-
throw $this->invalidValidatedType($key, 'boolean');
255-
}
256-
257-
/**
258-
* Returns a validated field as a Time instance.
259-
*
260-
* Supports dot-array syntax for nested validated data.
261-
*/
262-
public function date(
263-
string $key,
264-
?string $format = null,
265-
DateTimeZone|string|null $timezone = null,
266-
): ?Time {
267-
$value = $this->getValidated($key);
268-
269-
if ($value === null) {
270-
return null;
271-
}
272-
273-
if (! is_string($value) || $value === '') {
274-
throw $this->invalidValidatedType($key, 'date');
275-
}
276-
277-
try {
278-
if ($format === null) {
279-
return Time::parse($value, $timezone);
280-
}
281-
282-
return Time::createFromFormat($format, $value, $timezone);
283-
} catch (Exception) {
284-
throw $this->invalidValidatedType($key, 'date');
285-
}
286-
}
287-
288-
/**
289-
* Returns a validated field as an enum instance.
290-
*
291-
* Supports dot-array syntax for nested validated data.
292-
*
293-
* @template TEnum of UnitEnum
294-
*
295-
* @param class-string<TEnum> $enumClass
296-
* @param TEnum|null $default
297-
*
298-
* @return TEnum|null
299-
*/
300-
public function enum(string $key, string $enumClass, ?UnitEnum $default = null): ?UnitEnum
301-
{
302-
if (! enum_exists($enumClass)) {
303-
throw new InvalidArgumentException('The "' . $enumClass . '" class is not a valid enum.');
304-
}
305-
306-
$value = $this->getValidated($key, $default);
307-
308-
if ($value === null) {
309-
return null;
310-
}
311-
312-
if ($value instanceof UnitEnum) {
313-
if ($value instanceof $enumClass) {
314-
return $value;
315-
}
316-
317-
throw $this->invalidValidatedType($key, $enumClass);
318-
}
319-
320-
$reflection = new ReflectionEnum($enumClass);
321-
322-
if ($reflection->isBacked()) {
323-
return $this->backedEnum($key, $enumClass, $reflection, $value);
324-
}
325-
326-
if (is_string($value)) {
327-
foreach ($enumClass::cases() as $case) {
328-
if ($case->name === $value) {
329-
return $case;
330-
}
331-
}
332-
}
333-
334-
throw $this->invalidValidatedType($key, $enumClass);
335-
}
336-
337210
/**
338211
* Returns true when the named field exists in the validated data, even if
339212
* its value is null.
@@ -347,46 +220,6 @@ public function hasValidated(string $key): bool
347220
return dot_array_has($key, $this->validatedData);
348221
}
349222

350-
private function backedEnum(string $key, string $enumClass, ReflectionEnum $reflection, mixed $value): UnitEnum
351-
{
352-
$backingType = $reflection->getBackingType()?->getName();
353-
354-
if ($backingType === 'int') {
355-
if (is_string($value)) {
356-
$value = filter_var($value, FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
357-
}
358-
359-
if (! is_int($value)) {
360-
throw $this->invalidValidatedType($key, $enumClass);
361-
}
362-
} elseif (! is_int($value) && ! is_string($value)) {
363-
throw $this->invalidValidatedType($key, $enumClass);
364-
}
365-
366-
if (! is_subclass_of($enumClass, BackedEnum::class)) {
367-
throw $this->invalidValidatedType($key, $enumClass);
368-
}
369-
370-
if ($backingType === 'string') {
371-
$value = (string) $value;
372-
}
373-
374-
$enum = $enumClass::tryFrom($value);
375-
376-
if ($enum === null) {
377-
throw $this->invalidValidatedType($key, $enumClass);
378-
}
379-
380-
return $enum;
381-
}
382-
383-
private function invalidValidatedType(string $key, string $type): InvalidArgumentException
384-
{
385-
return new InvalidArgumentException(
386-
sprintf('The validated "%s" value cannot be read as %s.', $key, $type),
387-
);
388-
}
389-
390223
/**
391224
* Returns the data to be validated.
392225
*

0 commit comments

Comments
 (0)