-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathllms.txt
More file actions
211 lines (168 loc) · 10.3 KB
/
llms.txt
File metadata and controls
211 lines (168 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# Lemmon/Validator Technical Spec
## Core Concepts
- **Form-Safe Coercion:** `coerce()` converts types but treats empty strings `''` as `null` for `Int`, `Float`, and `Bool` to prevent dangerous defaults (0/false).
- **Optional by Default:** All fields accept `null` unless `required()` is called.
- **Fail-Fast Per Field:** Each validator chain stops at the first failing rule; schema validation still aggregates errors across fields.
- **Null Handling:**
- **Validations** (`satisfies`, `min`, `email`): Skip `null` values.
- **Transformations**:
- `pipe(callable)`: Skips `null` values (type-preserving, expects specific type).
- `transform(callable, bool $skipNull = true)`: Skips `null` by default (most type conversions don't need null). Set `$skipNull = false` to process null values.
- **Pipeline Order:** Pipeline steps execute in the exact order defined. `default()` and `required()` are flags evaluated after the pipeline regardless of position: `default()` is the last-resort fallback for null, `required()` enforces presence after default has had its chance.
- **Mutable Defaults:** `default()` stores the value as-is; scalars and flat arrays are copied by value in PHP, but objects (and arrays containing objects) share handles across runs. Use `defaultUsing()` when the default contains any mutable objects.
- **Transformation Types:**
- `pipe(callable)`: Intended for sanitization. Preserves type context and applies type-coercion to result.
- `transform(callable)`: Intended for type conversion. Updates type context; no coercion.
## Core Patterns
- **Namespace:** `Lemmon\Validator`
- **Entry Point:** `Validator` static factory (e.g., `Validator::isString()`).
- **Fluency:** Validators are mutable during configuration but used sequentially.
- **Execution:**
- `validate(mixed $value, string $key = '', mixed $input = null)` throws `ValidationException`.
- `tryValidate(mixed $value, string $key = '', mixed $input = null)` returns tuple `[bool $valid, mixed $data, ?array $errors]`.
- **Fail-Fast:** Each validator chain stops at the first failing rule; schema validators aggregate errors across fields.
- **Error Structure:** `ValidationException` contains nested array of error messages. Use `getFlattenedErrors()` for API format `[{path: string, message: string}]`.
- **Null Handling:** Validators skip `null` values unless `required()` is called. `default()` fills in null as a last-resort fallback after the pipeline; `required()` enforces presence at the very end.
- **Pipeline:** Supports both validation (`satisfies`) and transformation (`transform`, `pipe`). Flow: coerce -> type check -> pipeline -> default -> required.
- **Coercion:** `coerce()` enables smart type conversion (e.g., "true" -> `true`). Non-coercible values pass through unchanged.
- **Form Safety:** Empty strings `''` are treated as `null` for primitives if coerced.
## API Reference
### Factory (`Lemmon\Validator\Validator`)
```php
static isString(): StringValidator
static isInt(): IntValidator
static isFloat(): FloatValidator
static isBool(): BoolValidator
static isArray(): ArrayValidator
static isAssociative(array<string, FieldValidator> $schema = []): AssociativeValidator
static isObject(array<string, FieldValidator> $schema = []): ObjectValidator
static anyOf(array<FieldValidator> $validators, ?string $message = null): FieldValidator
static allOf(array<FieldValidator> $validators, ?string $message = null): FieldValidator
static not(FieldValidator $validator, ?string $message = null): FieldValidator
```
### Base API (`FieldValidator`)
_Available on all validators_
```php
required(?string $message = null): static
default(mixed $value): static
defaultUsing(callable(): mixed $factory): static
coerce(): static
outputKey(string $key): static (schema fields only: output under different key, e.g. input service_id -> output service)
nullifyEmpty(): static (transforms '' or [] to null)
clone(): static (deep copy with bound closures)
// Custom Validation
satisfies(callable|FieldValidator $rule, ?string $message = null): static
satisfiesAny(array<callable|FieldValidator> $rules, ?string $message = null): static
satisfiesAll(array<callable|FieldValidator> $rules, ?string $message = null): static
satisfiesNone(array<callable|FieldValidator> $rules, ?string $message = null): static
const(mixed $value, ?string $message = null): static // Restrict to exactly one value (strict ===)
enum(string $enumClass, ?string $message = null): static // BackedEnum: int|string backed values; UnitEnum: enum instance or string case name
// Transformation
transform(callable $fn, bool $skipNull = true): static (can change type, skips null by default)
pipe(callable ...$fns): static (preserves type, skips null)
```
### StringValidator
```php
email(?string $message = null): static
url(?string $message = null): static
uuid(UuidVariant $variant = UuidVariant::Any, ?string $message = null): static
ip(IpVersion $version = IpVersion::Any, ?string $message = null): static
hostname(?string $message = null): static
domain(?string $message = null): static // Requires dot
time(?string $message = null): static // HH:MM or HH:MM:SS
base64(Base64Variant $variant = Base64Variant::Standard, ?string $message = null): static
hex(?string $message = null): static
regex(string $pattern, ?string $message = null): static // Alias for pattern()
pattern(string $pattern, ?string $message = null): static
datetime(string $format = 'Y-m-d\TH:i:s', ?string $message = null): static
date(string $format = 'Y-m-d', ?string $message = null): static
minLength(int $min, ?string $message = null): static
maxLength(int $max, ?string $message = null): static
length(int $exact, ?string $message = null): static
between(int $min, int $max, ?string $message = null): static
notEmpty(?string $message = null): static
in(array $values, ?string $message = null): static
oneOf(array $values, ?string $message = null): static // Deprecated alias for in()
```
### IntValidator / FloatValidator
_Both support NumericConstraintsTrait_
```php
min(int|float $min, ?string $message = null): static
max(int|float $max, ?string $message = null): static
between(int|float $min, int|float $max, ?string $message = null): static
gt(int|float $threshold, ?string $message = null): static
gte(int|float $threshold, ?string $message = null): static
lt(int|float $threshold, ?string $message = null): static
lte(int|float $threshold, ?string $message = null): static
multipleOf(int|float $divisor, ?string $message = null): static
positive(?string $message = null): static
negative(?string $message = null): static
nonPositive(?string $message = null): static
nonNegative(?string $message = null): static
clampToRange(int|float $min, int|float $max): static // Transformation, not validation
in(array $values, ?string $message = null): static
oneOf(array $values, ?string $message = null): static // Deprecated alias for in()
```
_IntValidator Only:_
```php
port(?string $message = null): static // 1-65535
```
### ArrayValidator (`Validator::isArray()`)
_Indexed arrays / Lists_
```php
items(FieldValidator $validator): static
filterEmpty(): static (removes null/'', reindexes)
notEmpty(?string $message = null): static
minItems(int $min, ?string $message = null): static
maxItems(int $max, ?string $message = null): static
contains(mixed|FieldValidator $valueOrValidator, ?string $message = null): static
uniqueField(string $fieldName, ?string $message = null): static
```
**Cross-Item Validation:** `uniqueField()` validates a nested field is unique across items. All members of a duplicate group receive errors with field-level paths (e.g., both `symlinks.0.destination` and `symlinks.2.destination`). For custom cross-item logic, use `satisfies()` directly -- structure errors as `[index => [field => [message]]]` for field-level paths. Both run after item validation and receive validated data.
### AssociativeValidator / ObjectValidator
_Schema validation_
```php
// Constructor accepts array<string, FieldValidator>
coerceAll(): static // Recursively enables coercion on schema fields, nested schemas, and array item validators (each validator is cloned so shared instances are not mutated); does not propagate into assertion operands (satisfies, contains, etc.) -- call coerce() on those individually
passthrough(): static // Copy undeclared keys/properties from input to output without validating them; schema fields still validated; does not overwrite keys already set from the schema (including outputKey targets)
```
By default, outputs only schema-defined keys (plus defaults). With `passthrough()`, any input key not in the schema is copied through unchanged (shallow); nested structures are not recursively validated. For `ObjectValidator`, only **public** properties from the input object are considered (via `get_object_vars()`).
### BoolValidator
```php
in(array $values, ?string $message = null): static
oneOf(array $values, ?string $message = null): static // Deprecated alias for in()
// Coercion handles: 'true','on','1' -> true; 'false','off','0' -> false
```
## Enums
### IpVersion
`Any`, `IPv4`, `IPv6`
### UuidVariant
`Any`, `V1`, `V2`, `V3`, `V4`, `V5`, `V7`
### Base64Variant
`Standard`, `UrlSafe`, `Any`
### PipelineType
`VALIDATION`, `TRANSFORMATION`
## Quick Examples
```php
// Pipeline order demonstration: shows value transformation at each step
Validator::isString()
->pipe('trim') // Transformation: " \n " → "" (preserves string type, skips null)
->nullifyEmpty() // Transformation: "" → null (converts empty string/array to null)
->required() // Flag: enforced after pipeline + default(); throws if value is still null
->date('Y-m-d') // Validation: checks format Y-m-d (skips null, but required() ensures non-null)
->transform(fn($s) => DateTime::createFromFormat('Y-m-d', $s)); // Transformation: String → DateTime (receives validated string)
// With valid input "2024-01-15": "2024-01-15" → trim → "2024-01-15" → nullifyEmpty (no-op) → date validation → transform receives "2024-01-15" → DateTime
// Form-safe coercion: '' -> null (not 0/false)
Validator::isInt()->coerce()->validate(''); // null (if not required)
// Schema with defaults
Validator::isAssociative([
'name' => Validator::isString()->required(),
'age' => Validator::isInt()->default(0)
]);
// Error handling
try {
$data = $validator->validate($input);
} catch (ValidationException $e) {
$errors = $e->getFlattenedErrors(); // [{path: 'field', message: '...'}]
}
```