9
9
};
10
10
11
11
/**
12
- * @implements Constraint<array , non-empty-array<non-empty-string, mixed>>
12
+ * @implements Constraint<mixed , non-empty-array<non-empty-string, mixed>>
13
13
* @psalm-immutable
14
14
*/
15
15
final class Shape implements Constraint
@@ -31,43 +31,7 @@ private function __construct(array $constraints, array $optional)
31
31
32
32
public function __invoke (mixed $ value ): Validation
33
33
{
34
- $ optional = new \stdClass ;
35
- /** @var Validation<Failure, non-empty-array<non-empty-string, mixed>> */
36
- $ validation = Validation::success ([]);
37
-
38
- foreach ($ this ->constraints as $ key => $ constraint ) {
39
- $ keyValidation = Has::key ($ key );
40
-
41
- if (\in_array ($ key , $ this ->optional , true )) {
42
- /** @psalm-suppress MixedArgumentTypeCoercion */
43
- $ keyValidation = $ keyValidation ->or (Of::callable (
44
- static fn () => Validation::success ($ optional ),
45
- ));
46
- }
47
-
48
- $ ofType = Of::callable (
49
- static fn ($ value ) => match ($ value ) {
50
- $ optional => Validation::success ($ optional ),
51
- default => $ constraint ($ value )->mapFailures (
52
- static fn ($ failure ) => $ failure ->under ($ key ),
53
- ),
54
- },
55
- );
56
-
57
- $ validation = $ validation ->and (
58
- $ keyValidation ->and ($ ofType )($ value ),
59
- static function ($ array , $ value ) use ($ key , $ optional ) {
60
- if ($ value !== $ optional ) {
61
- /** @psalm-suppress MixedAssignment */
62
- $ array [$ key ] = $ value ;
63
- }
64
-
65
- return $ array ;
66
- },
67
- );
68
- }
69
-
70
- return $ validation ;
34
+ return Is::array ()($ value )->flatMap ($ this ->validate (...));
71
35
}
72
36
73
37
/**
@@ -126,4 +90,48 @@ public function asPredicate(): PredicateInterface
126
90
{
127
91
return Predicate::of ($ this );
128
92
}
93
+
94
+ /**
95
+ * @return Validation<Failure, non-empty-array<non-empty-string, mixed>>
96
+ */
97
+ private function validate (array $ value ): Validation
98
+ {
99
+ $ optional = new \stdClass ;
100
+ /** @var Validation<Failure, non-empty-array<non-empty-string, mixed>> */
101
+ $ validation = Validation::success ([]);
102
+
103
+ foreach ($ this ->constraints as $ key => $ constraint ) {
104
+ $ keyValidation = Has::key ($ key );
105
+
106
+ if (\in_array ($ key , $ this ->optional , true )) {
107
+ /** @psalm-suppress MixedArgumentTypeCoercion */
108
+ $ keyValidation = $ keyValidation ->or (Of::callable (
109
+ static fn () => Validation::success ($ optional ),
110
+ ));
111
+ }
112
+
113
+ $ ofType = Of::callable (
114
+ static fn ($ value ) => match ($ value ) {
115
+ $ optional => Validation::success ($ optional ),
116
+ default => $ constraint ($ value )->mapFailures (
117
+ static fn ($ failure ) => $ failure ->under ($ key ),
118
+ ),
119
+ },
120
+ );
121
+
122
+ $ validation = $ validation ->and (
123
+ $ keyValidation ->and ($ ofType )($ value ),
124
+ static function ($ array , $ value ) use ($ key , $ optional ) {
125
+ if ($ value !== $ optional ) {
126
+ /** @psalm-suppress MixedAssignment */
127
+ $ array [$ key ] = $ value ;
128
+ }
129
+
130
+ return $ array ;
131
+ },
132
+ );
133
+ }
134
+
135
+ return $ validation ;
136
+ }
129
137
}
0 commit comments