Skip to content

Commit 67f4650

Browse files
committed
feat(validators): introduce in() method as an alias for oneOf()
Added a new `in()` method to StringValidator, IntValidator, FloatValidator, and BoolValidator for clearer allowed-value validation. The `oneOf()` method is now deprecated in favor of `in()`, which enhances the API's intuitiveness. Updated documentation and tests to reflect these changes, ensuring backward compatibility with the retained `oneOf()` alias.
1 parent 42bdadd commit 67f4650

21 files changed

Lines changed: 71 additions & 47 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ All notable changes to this project will be documented in this file.
77
### Added
88
- `notEmpty()` convenience method for `StringValidator` and `ArrayValidator` to reject empty strings/arrays
99
- `between()` shorthand for string length and numeric range constraints
10+
- `in()` alias for `oneOf()` on primitive validators for clearer allowed-value validation
11+
12+
### Deprecated
13+
- `oneOf()` in favor of `in()` (alias retained for backward compatibility)
1014

1115
### Documentation
1216
- Clarified fail-fast behavior per field and schema-level error aggregation in guides and examples

ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ $stringValidator = Validator::isString()
308308

309309
### Real-World Validation Gaps (For Consideration)
310310
- [x] **`notEmpty()` method** - Explicit validation that value is not empty string/array (clearer than custom validation)
311-
- [ ] **`in()` alias for `oneOf()`** - More intuitive method name (`->in(['active', 'inactive'])`)
311+
- [x] **`in()` alias for `oneOf()`** - More intuitive method name (`->in(['active', 'inactive'])`)
312312
- [x] **`between(min, max)` for strings** - Length validation shorthand (`->between(3, 50)` instead of `->minLength(3)->maxLength(50)`)
313313
- [x] **`between(min, max)` for numerics** - Range validation shorthand (`->between(1, 100)` instead of `->min(1)->max(100)`)
314314
- [ ] **`filled()` method** - Requires non-null AND non-empty (stricter than required())

TASKS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ Public repo; keep this list short (about 7) and up to date. Rules: no numbering
88
- Structured error codes
99
- Add programmatic error codes to validation errors (e.g., 'STRING_TOO_SHORT', 'INVALID_EMAIL') for better error handling and i18n support; keep backward compatibility.
1010

11-
- `in()` alias for `oneOf()`
12-
- Add `in()` method as an alias for `oneOf()` for more intuitive API (`->in(['active', 'inactive'])` reads better than `->oneOf()`).
11+
- `filled()` method
12+
- Require non-null AND non-empty values; document how it interacts with `required()`, `nullifyEmpty()`, and `coerce()`.
1313

1414
- Mutation testing pilot
1515
- Wire Infection (or similar) to the test suite, add baseline config, and document how to run it locally for enhanced test quality verification.

docs/api-reference/validator-factory.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ class UserSchemas
373373
private static function preferences(): AssociativeValidator
374374
{
375375
return Validator::isAssociative([
376-
'theme' => Validator::isString()->oneOf(['light', 'dark'])->default('light'),
376+
'theme' => Validator::isString()->in(['light', 'dark'])->default('light'),
377377
'notifications' => Validator::isBool()->default(true)
378378
]);
379379
}
@@ -468,7 +468,7 @@ $result2 = $notEmail->validate(123); // Valid (not an email)
468468

469469
// User status that cannot be banned or suspended
470470
$validStatus = Validator::not(
471-
Validator::isString()->oneOf(['banned', 'suspended']),
471+
Validator::isString()->in(['banned', 'suspended']),
472472
'User cannot have banned or suspended status'
473473
);
474474

@@ -663,27 +663,29 @@ $result = $validator->validate(''); // Returns: 'N/A'
663663

664664
---
665665

666-
### `oneOf(array $values, ?string $message = null): self`
666+
### `in(array $values, ?string $message = null): self`
667667

668668
**Available on:** `StringValidator`, `IntValidator`, `FloatValidator`, `BoolValidator` only
669669

670670
Restricts the value to one of the specified allowed values. This method is implemented as a transformation and respects the fluent API execution order.
671671

672+
**Deprecated alias:** `oneOf()` (use `in()` instead)
673+
672674
```php
673675
// String with allowed values
674676
$status = Validator::isString()
675-
->oneOf(['active', 'inactive', 'pending'], 'Invalid status')
677+
->in(['active', 'inactive', 'pending'], 'Invalid status')
676678
->validate('active'); // Valid
677679

678680
// Integer with allowed values
679681
$priority = Validator::isInt()
680-
->oneOf([1, 2, 3, 4, 5], 'Priority must be 1-5')
682+
->in([1, 2, 3, 4, 5], 'Priority must be 1-5')
681683
->validate(3); // Valid
682684

683685
// Execution order matters
684686
$validator = Validator::isString()
685687
->pipe('trim', 'strtolower') // Transform first
686-
->oneOf(['yes', 'no']) // Then validate allowed values
688+
->in(['yes', 'no']) // Then validate allowed values
687689
->validate(' YES '); // Valid (becomes 'yes' after transformation)
688690
```
689691

docs/examples/form-validation.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ class ProductFormValidator
187187

188188
'category' => Validator::isString()
189189
->required('Category is required')
190-
->oneOf(['electronics', 'clothing', 'books', 'home'], 'Invalid category'),
190+
->in(['electronics', 'clothing', 'books', 'home'], 'Invalid category'),
191191

192192
// Optional fields with form-safe handling
193193
'description' => Validator::isString()
@@ -336,7 +336,7 @@ class UserRegistrationValidator
336336
),
337337

338338
'gender' => Validator::isString()
339-
->oneOf(['male', 'female', 'other', 'prefer_not_to_say'], 'Please select a valid gender option')
339+
->in(['male', 'female', 'other', 'prefer_not_to_say'], 'Please select a valid gender option')
340340
->default('prefer_not_to_say'),
341341

342342
// Address (optional)
@@ -591,7 +591,7 @@ class ProductFormValidator
591591

592592
// Status and Visibility
593593
'status' => Validator::isString()
594-
->oneOf(['draft', 'active', 'archived'], 'Invalid product status')
594+
->in(['draft', 'active', 'archived'], 'Invalid product status')
595595
->default('draft'),
596596

597597
'published_at' => Validator::isString()
@@ -878,7 +878,7 @@ class FileUploadValidator
878878

879879
'type' => Validator::isString()
880880
->required()
881-
->oneOf(['image/jpeg', 'image/png', 'image/gif'], 'Invalid file type')
881+
->in(['image/jpeg', 'image/png', 'image/gif'], 'Invalid file type')
882882
]);
883883

884884
return $validator->tryValidate($file);

docs/getting-started/basic-usage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ $formValidator = Validator::isAssociative([
194194
### Allowed Values
195195

196196
```php
197-
$restricted = Validator::isString()->oneOf(['red', 'green', 'blue']);
197+
$restricted = Validator::isString()->in(['red', 'green', 'blue']);
198198

199199
$result = $restricted->validate('red'); // Valid
200200
$result = $restricted->validate('yellow'); // ❌ ValidationException

docs/getting-started/core-concepts.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ All validators extend `FieldValidator`, which provides:
4545
- `required(): static` - Makes the field mandatory
4646
- `default(mixed $value): static` - Sets default value for null inputs
4747
- `coerce(): static` - Enables automatic type conversion
48-
- `oneOf(array $values): static` - Restricts to specific values (primitive validators only)
48+
- `in(array $values): static` - Restricts to specific values (primitive validators only)
4949

5050
### Custom Validation
5151
- `satisfies(callable|FieldValidator $rule, ?string $message = null): static` - Enhanced custom validation accepting validators or callables
@@ -436,7 +436,7 @@ $schema = Validator::isAssociative([
436436
'name' => Validator::isString()->required(),
437437
'contacts' => Validator::isArray()->items(
438438
Validator::isAssociative([
439-
'type' => Validator::isString()->oneOf(['email', 'phone']),
439+
'type' => Validator::isString()->in(['email', 'phone']),
440440
'value' => Validator::isString()->required()
441441
])
442442
)

docs/guides/array-validation.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ $validator = Validator::isArray()->satisfies(
331331
$result = $validator->validate([1, 2]); // Valid
332332
$validator->validate([1, 2, 3]); // Throws ValidationException
333333

334-
// Note: oneOf() is not available on ArrayValidator as it doesn't make semantic sense for complex types
334+
// Note: in() is not available on ArrayValidator as it doesn't make semantic sense for complex types
335335
```
336336

337337
### Empty Array Handling
@@ -582,7 +582,7 @@ $fileValidator = Validator::isArray()->items(
582582
Validator::isAssociative([
583583
'name' => Validator::isString()->required(),
584584
'size' => Validator::isInt()->min(1)->max(10485760), // Max 10MB
585-
'type' => Validator::isString()->oneOf([
585+
'type' => Validator::isString()->in([
586586
'image/jpeg', 'image/png', 'image/gif'
587587
])
588588
])

docs/guides/custom-validation.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ $conditionalValidator = Validator::isString()->satisfies(
106106
$accountSchema = Validator::isAssociative([
107107
'account_type' => Validator::isString()
108108
->required()
109-
->oneOf(['personal', 'business']),
109+
->in(['personal', 'business']),
110110
'company_name' => $conditionalValidator
111111
]);
112112
```
@@ -215,7 +215,7 @@ $discountValidator = Validator::isFloat()->satisfies(
215215
);
216216

217217
$orderSchema = Validator::isAssociative([
218-
'customer_tier' => Validator::isString()->oneOf(['bronze', 'silver', 'gold', 'platinum']),
218+
'customer_tier' => Validator::isString()->in(['bronze', 'silver', 'gold', 'platinum']),
219219
'order_total' => Validator::isFloat()->positive()->required(),
220220
'discount_amount' => $discountValidator
221221
]);

docs/guides/error-handling.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ class ApiValidator
416416
$schema = Validator::isAssociative([
417417
'status' => Validator::isString()
418418
->required('Status is required')
419-
->oneOf(['success', 'error'], 'Status must be success or error'),
419+
->in(['success', 'error'], 'Status must be success or error'),
420420

421421
'data' => Validator::isAssociative()
422422
->required('Data is required'),
@@ -460,7 +460,7 @@ class ConfigValidator
460460
])->required('Database configuration is required'),
461461

462462
'cache' => Validator::isAssociative([
463-
'driver' => Validator::isString()->oneOf(['redis', 'memcached', 'file'])->default('file'),
463+
'driver' => Validator::isString()->in(['redis', 'memcached', 'file'])->default('file'),
464464
'ttl' => Validator::isInt()->positive()->default(3600)
465465
])->default([]),
466466

0 commit comments

Comments
 (0)