cuyz/valinor
Valinor maps raw inputs (JSON/arrays) into validated, strongly typed PHP objects. Supports advanced PHPStan/Psalm types (shaped arrays, generics, ranges), produces precise human-readable errors, and can normalize data back to formats like JSON or CSV.
Valinor excels in Laravel/PHP ecosystems where strong typing, validation, and input normalization are critical. It aligns with Laravel’s dependency injection (DI) patterns, API-first design, and type safety (via PHPStan/Psalm). The package’s decoupled, dependency-free nature makes it a non-intrusive addition to existing Laravel architectures, avoiding framework lock-in while complementing Laravel’s built-in validation (e.g., Form Requests) or third-party libraries like Symfony Serializer or Spatie’s Laravel Data.
Key Fit Areas:
Request validation with type-safe, attribute-driven mapping (e.g., #[FromRoute], #[FromQuery]).Illuminate\Http\Request via HttpRequest::fromPsr().FormRequest validation for complex nested structures.Potential Conflicts:
FormRequest, ensure no redundant validation (e.g., use Valinor for DTOs and FormRequest for auth/CSRF).| Risk Area | Mitigation Strategy |
|---|---|
| Attribute Parsing | Test with PHP 8.1+ (attributes are stable). Fallback to constructor injection if needed. |
| Type System Limits | Use PHPStan/Psalm for static checks; Valinor’s runtime validation catches edge cases. |
| Error Handling | Customize MappingError to integrate with Laravel’s exception handler (e.g., return 422 JSON responses). |
| Normalization | Validate output formats early (e.g., ensure Normalizer matches API contracts). |
| Backward Compatibility | Monitor Valinor’s semver (current: ^2.4). Pin major versions in composer.json. |
FormRequest, or supplement it (e.g., for DTOs)?Symfony Serializer.MappingError integrate with Laravel’s exception handling (e.g., App\Exceptions\Handler)?422 responses?#[FromRoute]) or explicit mapping (e.g., MapperBuilder)?| Laravel Component | Valinor Integration Point | Notes |
|---|---|---|
| API Controllers | #[FromRoute], #[FromQuery], #[FromBody] |
Replaces manual Request->input() calls. |
| Form Requests | Optional: Use Valinor for DTO validation | Keep FormRequest for auth/CSRF; use Valinor for business logic DTOs. |
| Jobs/Commands | MapperBuilder::map() for payloads |
Validates queue/job inputs (e.g., HandlePayment::dispatch($data)). |
| Service Layer | Normalization for output consistency | Ensures API responses match contracts (e.g., Normalizer::toJson()). |
| PSR-7 Requests | HttpRequest::fromPsr() |
Works with Laravel’s Illuminate\Http\Request. |
| Testing | Mock HttpRequest for unit tests |
Reduces boilerplate vs. manual Request mocking. |
StorePostRequest with a Valinor-mapped DTO.// Before: FormRequest
public function store(StorePostRequest $request) { ... }
// After: Valinor DTO
public function store(PostDto $dto) { ... }
#[FromRoute]/#[FromQuery].Request->route('id') to #[FromRoute] int $id.Normalizer (e.g., ensure all JSON responses use snake_case).UserRepository::find($id) → UserRepository::findAs(User::class, $id)).nikic/php-parser).Psr\HttpMessage (e.g., Symfony\Component\HttpFoundation\Request via adapter).composer require cuyz/valinor.AppServiceProvider):
public function boot(): void {
$this->app->singleton(\CuyZ\Valinor\MapperBuilder::class, fn() => new MapperBuilder());
}
app/Dtos/UserCreateDto.php).FormRequest with Valinor mapping.Request (if needed).MappingError and return 422 JSON.Normalizer to API responses (e.g., in App\Http\Middleware\FormatJson).if (!$request->has('email'))).#[FromRoute] syntax.MappingError messages may require familiarity with Valinor’s format.MappingError to include user-friendly messages (e.g., translate field names).catch (MappingError $e) {
return response()->json([
'errors' => $e->getErrorsAsArray(),
], 422);
}
How can I help you explore Laravel packages today?