• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

codeigniter4 / CodeIgniter4 / 25399569005

05 May 2026 08:08PM UTC coverage: 88.276% (+0.002%) from 88.274%
25399569005

Pull #10158

github

web-flow
Merge d7067f3ce into 3cdb4c5e1
Pull Request #10158: feat: add typed FormRequest accessors

65 of 73 new or added lines in 3 files covered. (89.04%)

28 existing lines in 4 files now uncovered.

23552 of 26680 relevant lines covered (88.28%)

218.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.73
/system/HTTP/ValidatedInput.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of CodeIgniter 4 framework.
7
 *
8
 * (c) CodeIgniter Foundation <admin@codeigniter.com>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace CodeIgniter\HTTP;
15

16
use BackedEnum;
17
use CodeIgniter\Exceptions\InvalidArgumentException;
18
use CodeIgniter\I18n\Time;
19
use DateTimeZone;
20
use Exception;
21
use ReflectionEnum;
22
use UnitEnum;
23

24
/**
25
 * @see \CodeIgniter\HTTP\ValidatedInputTest
26
 */
27
class ValidatedInput
28
{
29
    /**
30
     * @param array<string, mixed> $data
31
     */
32
    public function __construct(private readonly array $data)
33
    {
34
    }
25✔
35

36
    /**
37
     * Returns a single validated field value by name, or the default value
38
     * if the field is not present in the validated data.
39
     *
40
     * Supports dot-array syntax for nested validated data.
41
     */
42
    public function get(string $key, mixed $default = null): mixed
43
    {
44
        helper('array');
24✔
45

46
        if (! dot_array_has($key, $this->data)) {
24✔
47
            return $default;
4✔
48
        }
49

50
        return dot_array_search($key, $this->data);
20✔
51
    }
52

53
    /**
54
     * Returns true when the named field exists in the validated data, even if
55
     * its value is null.
56
     *
57
     * Supports dot-array syntax for nested validated data.
58
     */
59
    public function has(string $key): bool
60
    {
61
        helper('array');
2✔
62

63
        return dot_array_has($key, $this->data);
2✔
64
    }
65

66
    /**
67
     * Returns a validated field as an integer.
68
     *
69
     * Supports dot-array syntax for nested validated data.
70
     */
71
    public function integer(string $key, ?int $default = null): ?int
72
    {
73
        $value = $this->get($key, $default);
5✔
74

75
        if ($value === null || is_int($value)) {
5✔
76
            return $value;
2✔
77
        }
78

79
        if (is_string($value)) {
3✔
80
            $integer = filter_var($value, FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
3✔
81

82
            if ($integer !== null) {
3✔
83
                return $integer;
2✔
84
            }
85
        }
86

87
        throw $this->invalidType($key, 'integer');
1✔
88
    }
89

90
    /**
91
     * Returns a validated field as a boolean.
92
     *
93
     * Supports dot-array syntax for nested validated data.
94
     */
95
    public function boolean(string $key, ?bool $default = null): ?bool
96
    {
97
        $value = $this->get($key, $default);
5✔
98

99
        if ($value === null || is_bool($value)) {
5✔
100
            return $value;
2✔
101
        }
102

103
        if (is_int($value) || is_string($value)) {
3✔
104
            $boolean = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
3✔
105

106
            if ($boolean !== null) {
3✔
107
                return $boolean;
2✔
108
            }
109
        }
110

111
        throw $this->invalidType($key, 'boolean');
1✔
112
    }
113

114
    /**
115
     * Returns a validated field as a Time instance.
116
     *
117
     * Supports dot-array syntax for nested validated data.
118
     */
119
    public function date(
120
        string $key,
121
        ?string $format = null,
122
        DateTimeZone|string|null $timezone = null,
123
    ): ?Time {
124
        $value = $this->get($key);
4✔
125

126
        if ($value === null) {
4✔
127
            return null;
1✔
128
        }
129

130
        if (! is_string($value) || $value === '') {
3✔
131
            throw $this->invalidType($key, 'date');
1✔
132
        }
133

134
        try {
135
            if ($format === null) {
2✔
136
                return Time::parse($value, $timezone);
1✔
137
            }
138

139
            return Time::createFromFormat($format, $value, $timezone);
1✔
NEW
140
        } catch (Exception) {
×
NEW
141
            throw $this->invalidType($key, 'date');
×
142
        }
143
    }
144

145
    /**
146
     * Returns a validated field as an enum instance.
147
     *
148
     * Supports dot-array syntax for nested validated data.
149
     *
150
     * @template TEnum of UnitEnum
151
     *
152
     * @param class-string<TEnum> $enumClass
153
     * @param TEnum|null          $default
154
     *
155
     * @return TEnum|null
156
     */
157
    public function enum(string $key, string $enumClass, ?UnitEnum $default = null): ?UnitEnum
158
    {
159
        if (! enum_exists($enumClass)) {
7✔
NEW
160
            throw new InvalidArgumentException('The "' . $enumClass . '" class is not a valid enum.');
×
161
        }
162

163
        if ($default instanceof UnitEnum && ! $default instanceof $enumClass) {
7✔
164
            throw $this->invalidType($key, $enumClass);
1✔
165
        }
166

167
        $value = $this->get($key, $default);
6✔
168

169
        if ($value === null) {
6✔
170
            return null;
1✔
171
        }
172

173
        if ($value instanceof UnitEnum) {
5✔
174
            if ($value instanceof $enumClass) {
1✔
175
                return $value;
1✔
176
            }
177

NEW
178
            throw $this->invalidType($key, $enumClass);
×
179
        }
180

181
        $reflection = new ReflectionEnum($enumClass);
4✔
182

183
        if ($reflection->isBacked()) {
4✔
184
            return $this->backedEnum($key, $enumClass, $reflection, $value);
3✔
185
        }
186

187
        if (is_string($value)) {
1✔
188
            foreach ($enumClass::cases() as $case) {
1✔
189
                if ($case->name === $value) {
1✔
190
                    return $case;
1✔
191
                }
192
            }
193
        }
194

NEW
195
        throw $this->invalidType($key, $enumClass);
×
196
    }
197

198
    private function backedEnum(string $key, string $enumClass, ReflectionEnum $reflection, mixed $value): UnitEnum
199
    {
200
        $backingType = $reflection->getBackingType()?->getName();
3✔
201

202
        if ($backingType === 'int') {
3✔
203
            if (is_string($value)) {
1✔
204
                $value = filter_var($value, FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
1✔
205
            }
206

207
            if (! is_int($value)) {
1✔
NEW
208
                throw $this->invalidType($key, $enumClass);
×
209
            }
210
        } elseif (! is_int($value) && ! is_string($value)) {
2✔
NEW
211
            throw $this->invalidType($key, $enumClass);
×
212
        }
213

214
        if (! is_subclass_of($enumClass, BackedEnum::class)) {
3✔
NEW
215
            throw $this->invalidType($key, $enumClass);
×
216
        }
217

218
        if ($backingType === 'string') {
3✔
219
            $value = (string) $value;
2✔
220
        }
221

222
        $enum = $enumClass::tryFrom($value);
3✔
223

224
        if ($enum === null) {
3✔
225
            throw $this->invalidType($key, $enumClass);
1✔
226
        }
227

228
        return $enum;
2✔
229
    }
230

231
    private function invalidType(string $key, string $type): InvalidArgumentException
232
    {
233
        return new InvalidArgumentException(
5✔
234
            sprintf('The validated "%s" value cannot be read as %s.', $key, $type),
5✔
235
        );
5✔
236
    }
237
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc