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

codeigniter4 / CodeIgniter4 / 25410067699

06 May 2026 12:34AM UTC coverage: 88.279% (+0.005%) from 88.274%
25410067699

Pull #10158

github

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

64 of 71 new or added lines in 3 files covered. (90.14%)

28 existing lines in 4 files now uncovered.

23551 of 26678 relevant lines covered (88.28%)

218.05 hits per line

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

89.86
/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 CodeIgniter\Exceptions\InvalidArgumentException;
17
use CodeIgniter\I18n\Time;
18
use DateTimeZone;
19
use Exception;
20
use ReflectionEnum;
21
use UnitEnum;
22

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

213
        if ($backingType === 'string') {
3✔
214
            $value = (string) $value;
2✔
215
        }
216

217
        $enum = $enumClass::tryFrom($value);
3✔
218

219
        if ($enum === null) {
3✔
220
            throw $this->invalidType($key, $enumClass);
1✔
221
        }
222

223
        return $enum;
2✔
224
    }
225

226
    private function invalidType(string $key, string $type): InvalidArgumentException
227
    {
228
        return new InvalidArgumentException(
5✔
229
            sprintf('The validated "%s" value cannot be read as %s.', $key, $type),
5✔
230
        );
5✔
231
    }
232
}
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