You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Accept UnitEnum case instances and string case names; keep BackedEnum tryFrom behavior
- Add ColorEnum fixture and tests; document API and update changelog/roadmap
- Trim ISSUES.md now that UnitEnum support is implemented
Copy file name to clipboardExpand all lines: AGENTS.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,7 +20,7 @@ Core validation logic lives in `src/Lemmon/Validator/`. Tests in `tests/` follow
20
20
-**Shared:**`NumericConstraintsTrait` (min, max, multipleOf, etc.); `PipelineType` enum; variant enums `IpVersion`, `Base64Variant`, `UuidVariant` for format methods
21
21
-**String formats:** email, URL, UUID, IP, hostname, domain, time, base64, hex, regex, datetime, date
22
22
-**Schema validation:** AssociativeValidator/ObjectValidator with nested error aggregation; shared `SchemaValidatorOptionsTrait` (`coerceAll`, `passthrough`, schema clone helper); `passthrough()` keeps undeclared keys/properties (unvalidated); default output is schema keys only
23
-
-**Logical combinators:**`Validator::allOf`, `anyOf`, `not`; instance `satisfiesAny`, `satisfiesAll`, `satisfiesNone`; `const()` for single allowed value; `enum()` for BackedEnum
23
+
-**Logical combinators:**`Validator::allOf`, `anyOf`, `not`; instance `satisfiesAny`, `satisfiesAll`, `satisfiesNone`; `const()` for single allowed value; `enum()` for `BackedEnum` and `UnitEnum`
24
24
-**Behavior:** Optional by default (null allowed unless `required()`); form-safe coercion (empty string → null, not 0/false); pipeline order guaranteed; fail-fast per field; `satisfies()` accepts validators or callables with `(value, key, input)`; extend via `satisfies()`, not custom validators
Copy file name to clipboardExpand all lines: CHANGELOG.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
4
4
5
5
## [Unreleased]
6
6
7
+
### Added
8
+
9
+
-`enum()` on `FieldValidator` now accepts PHP `UnitEnum` (non-backed enums): the value must be an instance of the enum or a string equal to one of the case names; `BackedEnum` behavior is unchanged (int or string backed values via `tryFrom()`)
Copy file name to clipboardExpand all lines: ISSUES.md
+1-25Lines changed: 1 addition & 25 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,31 +2,7 @@
2
2
3
3
This document tracks identified bugs, architectural inconsistencies, and potential improvements for the Lemmon Validator library.
4
4
5
-
## 1. Architectural Suggestions
6
-
7
-
### IntValidator Coercion Precision
8
-
9
-
`IntValidator` uses `is_numeric()` during coercion, which means a string like `"1.5"` is successfully coerced (truncated) to `1`. While "form-safe," this truncation can hide data precision issues. Consider providing a way to enforce strict integer strings or documenting this behavior clearly.
10
-
11
-
### UnitEnum Support
12
-
13
-
The `enum()` validator currently only supports `BackedEnum`. Adding support for basic `UnitEnum` (cases only) would increase utility for projects that do not use backed values for all enums.
14
-
15
-
### Mixed Type Coercion in Combinators
16
-
17
-
The static combinators `Validator::anyOf()`, `allOf()`, and `not()` return a "mixed" validator that does not support top-level coercion. Users expecting coercion must enable it on individual sub-validators.
18
-
19
-
---
20
-
21
-
## 2. Feature Suggestions
22
-
23
-
### Built-in String Sanitizers
24
-
25
-
Common operations like `trim()`, `lowercase()`, and `uppercase()` are currently implemented via `pipe('trim')`. Adding them as first-class methods (e.g., `->trim()`) would improve discoverability and follow the fluent API pattern of other validators.
26
-
27
-
### Explicit nullable() Method
28
-
29
-
Although fields are optional (allow null) by default, adding an explicit `->nullable()` method (as an alias for default behavior) can improve code readability and intent, especially when contrasted with `->required()`.
Copy file name to clipboardExpand all lines: README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -46,7 +46,7 @@ Rather than reimplementing every possible transformation or validation rule, Lem
46
46
-**API-friendly flattened errors** with field paths for easy frontend integration (`getFlattenedErrors()`, `ValidationException::flattenErrors()`)
47
47
-**Intuitive custom validation** with `satisfies()` method and optional error messages
48
48
-**Single-value validation** with `const()` for exact value matching (available on all validators)
49
-
-**PHP BackedEnum validation** with `enum()` for type-safe enum case validation (available on all validators)
49
+
-**PHP enum validation** with `enum()` for `BackedEnum` (backed values) and `UnitEnum` (case instances or string case names) (available on all validators)
50
50
-**Logical combinators** (`Validator::allOf()`, `Validator::anyOf()`, `Validator::not()`) for complex validation logic
51
51
-**Form-safe coercion** - empty strings become `null` (not dangerous `0`/`false`) for real-world safety
52
52
-**Accurate schema validation** - results only include provided fields and fields with defaults (no unexpected properties)
**Available on:** All validators (`FieldValidator` base)
764
764
765
-
Validates that the value matches one of the backed values of a PHP BackedEnum. The value must be `int` or `string` (non-scalar values fail). Use `enum(StatusEnum::class)` instead of `in(array_map(fn($e) => $e->value, StatusEnum::cases()))`.
765
+
Validates against a PHP `BackedEnum` or `UnitEnum`.
766
+
767
+
**BackedEnum:** The value must be `int` or `string` and must match one of the enum’s backed values (`tryFrom()`). Non-scalar values fail. Use `enum(StatusEnum::class)` instead of `in(array_map(fn($e) => $e->value, StatusEnum::cases()))`.
768
+
769
+
**UnitEnum** (non-backed): The value must be an instance of the enum, or a `string` equal to one of the case names (`$case->name`). Other types fail.
766
770
767
771
```php
772
+
// BackedEnum
768
773
enum StatusEnum: string { case Active = 'active'; case Pending = 'pending'; }
// $color->validate(ColorEnum::Blue); // invalid: isString() runs before enum()
777
789
```
778
790
791
+
For an enum **case instance**, chain `enum()` on a validator whose type step accepts objects (for example a custom `FieldValidator` with a permissive `validateType`, or logical combinators that accept mixed input).
792
+
779
793
**Parameters:**
780
794
781
-
-`$enumClass`: Fully qualified BackedEnum class name (e.g. `StatusEnum::class`)
795
+
-`$enumClass`: Fully qualified enum class name (`BackedEnum` or `UnitEnum`, e.g. `StatusEnum::class`)
782
796
-`$message` (optional): Custom error message for invalid values
783
797
784
798
**Returns:** Same validator instance for method chaining.
785
799
786
-
**Throws:**`InvalidArgumentException` if `$enumClass` is not a BackedEnum.
800
+
**Throws:**`InvalidArgumentException` if `$enumClass` is not a `BackedEnum` or `UnitEnum`.
Copy file name to clipboardExpand all lines: docs/guides/custom-validation.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
3
3
The Lemmon Validator allows you to add custom validation logic using the `satisfies()` method. This is perfect for business rules, complex validation logic, and context-aware validation that built-in validators can't handle.
4
4
5
-
For simple allowed-value validation, consider built-in methods first: `const()` for a single allowed value (e.g. `->const('active')`), `enum()` for PHP BackedEnums (e.g. `->enum(StatusEnum::class)`), or `in()` for multiple values on string, int, float, and bool validators.
5
+
For simple allowed-value validation, consider built-in methods first: `const()` for a single allowed value (e.g. `->const('active')`), `enum()` for PHP enums (e.g. `->enum(StatusEnum::class)` for a backed enum or `->enum(ColorEnum::class)` for a unit enum by case name or instance), or `in()` for multiple values on string, int, float, and bool validators.
const(mixed $value, ?string $message = null): static // Restrict to exactly one value (strict ===)
70
-
enum(string $enumClass, ?string $message = null): static // Validate against PHP BackedEnum cases; $enumClass e.g. StatusEnum::class; value must be int|string
70
+
enum(string $enumClass, ?string $message = null): static // BackedEnum: int|string backed values; UnitEnum: enum instance or string case name
0 commit comments