Skip to content

Commit a6350cd

Browse files
committed
refactor(validation): split typed input access by responsibility
- Add generic InputData for typed access to keyed input data - Move validation-specific accessors to ValidatedInput - Return ValidatedInput from Validation and FormRequest APIs - Add non-shared inputdata and validatedinput services - Update docs, tests, changelog, and architecture rules Signed-off-by: memleakd <121398829+memleakd@users.noreply.github.com>
1 parent 06a737a commit a6350cd

17 files changed

Lines changed: 432 additions & 198 deletions

File tree

deptrac.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ deptrac:
7878
- type: classNameRegex
7979
# includes the Filter
8080
value: '/^CodeIgniter\\.*Honeypot.*$/'
81+
- name: Input
82+
collectors:
83+
- type: classNameRegex
84+
value: '/^CodeIgniter\\Input\\.*$/'
8185
- name: HTTP
8286
collectors:
8387
- type: bool
@@ -248,6 +252,8 @@ deptrac:
248252
- I18n
249253
Validation:
250254
- HTTP
255+
- I18n
256+
- Input
251257
- Database
252258
View:
253259
- Cache
@@ -267,6 +273,8 @@ deptrac:
267273
- CodeIgniter\Entity\Entity
268274
CodeIgniter\Entity\Cast\URICast:
269275
- CodeIgniter\HTTP\URI
276+
CodeIgniter\HTTP\FormRequest:
277+
- CodeIgniter\Validation\ValidatedInput
270278
CodeIgniter\Log\Handlers\ChromeLoggerHandler:
271279
- CodeIgniter\HTTP\ResponseInterface
272280
CodeIgniter\Security\CheckPhpIni:

system/Config/BaseService.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
use CodeIgniter\HTTP\SiteURIFactory;
4747
use CodeIgniter\HTTP\URI;
4848
use CodeIgniter\Images\Handlers\BaseHandler;
49+
use CodeIgniter\Input\InputData;
4950
use CodeIgniter\Language\Language;
5051
use CodeIgniter\Lock\LockManager;
5152
use CodeIgniter\Log\Logger;
@@ -58,6 +59,7 @@
5859
use CodeIgniter\Superglobals;
5960
use CodeIgniter\Throttle\Throttler;
6061
use CodeIgniter\Typography\Typography;
62+
use CodeIgniter\Validation\ValidatedInput;
6163
use CodeIgniter\Validation\ValidationInterface;
6264
use CodeIgniter\View\Cell;
6365
use CodeIgniter\View\Parser;
@@ -120,6 +122,7 @@
120122
* @method static Honeypot honeypot(ConfigHoneyPot $config = null, $getShared = true)
121123
* @method static BaseHandler image($handler = null, Images $config = null, $getShared = true)
122124
* @method static IncomingRequest incomingrequest(?App $config = null, bool $getShared = true)
125+
* @method static InputData inputdata(array<string, mixed> $data = [], bool $getShared = false)
123126
* @method static Iterator iterator($getShared = true)
124127
* @method static Language language($locale = null, $getShared = true)
125128
* @method static LockManager locks(?CacheInterface $cache = null, bool $getShared = true)
@@ -144,6 +147,7 @@
144147
* @method static Toolbar toolbar(ConfigToolbar $config = null, $getShared = true)
145148
* @method static Typography typography($getShared = true)
146149
* @method static URI uri($uri = null, $getShared = true)
150+
* @method static ValidatedInput validatedinput(array<string, mixed> $data = [], bool $getShared = false)
147151
* @method static ValidationInterface validation(ConfigValidation $config = null, $getShared = true)
148152
* @method static Cell viewcell($getShared = true)
149153
*/

system/Config/Services.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
use CodeIgniter\HTTP\URI;
4747
use CodeIgniter\HTTP\UserAgent;
4848
use CodeIgniter\Images\Handlers\BaseHandler;
49+
use CodeIgniter\Input\InputData;
4950
use CodeIgniter\Language\Language;
5051
use CodeIgniter\Lock\LockManager;
5152
use CodeIgniter\Log\Logger;
@@ -62,6 +63,7 @@
6263
use CodeIgniter\Superglobals;
6364
use CodeIgniter\Throttle\Throttler;
6465
use CodeIgniter\Typography\Typography;
66+
use CodeIgniter\Validation\ValidatedInput;
6567
use CodeIgniter\Validation\Validation;
6668
use CodeIgniter\Validation\ValidationInterface;
6769
use CodeIgniter\View\Cell;
@@ -387,6 +389,20 @@ public static function image(?string $handler = null, ?Images $config = null, bo
387389
return new $class($config);
388390
}
389391

392+
/**
393+
* Returns a typed input data object.
394+
*
395+
* @param array<string, mixed> $data
396+
*/
397+
public static function inputdata(array $data = [], bool $getShared = false): InputData
398+
{
399+
if ($getShared) {
400+
return static::getSharedInstance('inputdata', $data);
401+
}
402+
403+
return new InputData($data);
404+
}
405+
390406
/**
391407
* The Iterator class provides a simple way of looping over a function
392408
* and timing the results and memory usage. Used when debugging and
@@ -873,6 +889,20 @@ public static function validation(?ValidationConfig $config = null, bool $getSha
873889
return new Validation($config, AppServices::get('renderer'));
874890
}
875891

892+
/**
893+
* Returns a typed validated input object.
894+
*
895+
* @param array<string, mixed> $data
896+
*/
897+
public static function validatedinput(array $data = [], bool $getShared = false): ValidatedInput
898+
{
899+
if ($getShared) {
900+
return static::getSharedInstance('validatedinput', $data);
901+
}
902+
903+
return new ValidatedInput($data);
904+
}
905+
876906
/**
877907
* View cells are intended to let you insert HTML into view
878908
* that has been generated by any callable in the system.

system/HTTP/FormRequest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace CodeIgniter\HTTP;
1515

1616
use CodeIgniter\Exceptions\RuntimeException;
17+
use CodeIgniter\Validation\ValidatedInput;
1718
use ReflectionNamedType;
1819
use ReflectionParameter;
1920

@@ -187,7 +188,7 @@ public function validated(): array
187188
*/
188189
public function validatedInput(): ValidatedInput
189190
{
190-
return new ValidatedInput($this->validatedData);
191+
return service('validatedinput', $this->validatedData, false);
191192
}
192193

193194
/**

system/Input/InputData.php

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
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\Input;
15+
16+
use CodeIgniter\Exceptions\InvalidArgumentException;
17+
18+
/**
19+
* @see \CodeIgniter\Input\InputDataTest
20+
*/
21+
class InputData
22+
{
23+
/**
24+
* @param array<string, mixed> $data
25+
*/
26+
public function __construct(private readonly array $data)
27+
{
28+
}
29+
30+
/**
31+
* Returns a single input value by name, or the default value if the field
32+
* is not present.
33+
*
34+
* Supports dot-array syntax for nested input data.
35+
*/
36+
public function get(string $key, mixed $default = null): mixed
37+
{
38+
helper('array');
39+
40+
if (! dot_array_has($key, $this->data)) {
41+
return $default;
42+
}
43+
44+
return dot_array_search($key, $this->data);
45+
}
46+
47+
/**
48+
* Returns true when the named field exists, even if its value is null.
49+
*
50+
* Supports dot-array syntax for nested input data.
51+
*/
52+
public function has(string $key): bool
53+
{
54+
helper('array');
55+
56+
return dot_array_has($key, $this->data);
57+
}
58+
59+
/**
60+
* Returns an input field as a string.
61+
*
62+
* Supports dot-array syntax for nested input data.
63+
*/
64+
public function string(string $key, ?string $default = null): ?string
65+
{
66+
$value = $this->get($key, $default);
67+
68+
if ($value === null || is_string($value)) {
69+
return $value;
70+
}
71+
72+
throw $this->invalidType($key, 'string');
73+
}
74+
75+
/**
76+
* Returns an input field as an integer.
77+
*
78+
* Supports dot-array syntax for nested input data.
79+
*/
80+
public function integer(string $key, ?int $default = null): ?int
81+
{
82+
$value = $this->get($key, $default);
83+
84+
if ($value === null || is_int($value)) {
85+
return $value;
86+
}
87+
88+
if (is_string($value)) {
89+
$integer = filter_var($value, FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
90+
91+
if ($integer !== null) {
92+
return $integer;
93+
}
94+
}
95+
96+
throw $this->invalidType($key, 'integer');
97+
}
98+
99+
/**
100+
* Returns an input field as a boolean.
101+
*
102+
* Supports dot-array syntax for nested input data.
103+
*/
104+
public function boolean(string $key, ?bool $default = null): ?bool
105+
{
106+
$value = $this->get($key, $default);
107+
108+
if ($value === null || is_bool($value)) {
109+
return $value;
110+
}
111+
112+
if (is_int($value) || is_string($value)) {
113+
$boolean = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
114+
115+
if ($boolean !== null) {
116+
return $boolean;
117+
}
118+
}
119+
120+
throw $this->invalidType($key, 'boolean');
121+
}
122+
123+
/**
124+
* Returns an input field as an array.
125+
*
126+
* Supports dot-array syntax for nested input data.
127+
*
128+
* @param array<array-key, mixed>|null $default
129+
*
130+
* @return array<array-key, mixed>|null
131+
*/
132+
public function array(string $key, ?array $default = null): ?array
133+
{
134+
$value = $this->get($key, $default);
135+
136+
if ($value === null || is_array($value)) {
137+
return $value;
138+
}
139+
140+
throw $this->invalidType($key, 'array');
141+
}
142+
143+
protected function invalidType(string $key, string $type): InvalidArgumentException
144+
{
145+
return new InvalidArgumentException(
146+
sprintf('The input "%s" value cannot be read as %s.', $key, $type),
147+
);
148+
}
149+
}

0 commit comments

Comments
 (0)