Website review
This review may include AI-generated content and is not individually verified. Domain, certificate and other facts come from the observed data on this page.
What is Valinor?
Valinor is a PHP library for mapping arbitrary input into strongly-typed value objects. Instead of hand-writing validation and hydration code that turns raw arrays or decoded JSON into objects, you describe the target structure with PHP types, and Valinor performs the conversion and type checking for you.
Its practical value shows up when input arrives as loosely typed data but your application logic wants real objects with typed properties. A typical case: an HTTP request body decoded to an array, mapped into a CreateOrder object with an int $customerId, a DateTimeImmutable $placedAt, and a list of OrderLine objects. Valinor handles nested objects and collections so you do not write recursive array-walking code.
Who it suits
- Backend PHP developers building APIs or command handlers that consume JSON or form data.
- Teams that want type errors surfaced at the mapping boundary rather than deep inside business logic.
- Codebases already using typed properties and constructor promotion, where a mapper fits naturally.
Trade-offs to weigh
- You take on a dependency and its conventions; simple one-off casts may not justify it.
- Mapping behavior depends on how precisely you express types, so vague type hints produce weak guarantees.
- Very dynamic or schema-less input still needs custom handling.
A useful next step is to try one real payload: define a small value object with a nested object and a collection, map an array into it, and see what happens when you pass a wrong type. That single experiment tells you quickly whether Valinor fits your codebase better than manual hydration or a framework's built-in serializer. For context, comparable mapping and serialization tools exist in the wider PHP ecosystem, such as Symfony's Serializer component.
How does Valinor map array or JSON input into a strongly-typed PHP object?
Valinor is a PHP mapping library that takes array or JSON-shaped input and constructs strongly-typed value objects from it. Instead of manually reading keys, casting scalars, and instantiating nested objects, you define the target class structure and let the mapper handle the conversion.
How the mapping generally works
- Decode input into arrays. For JSON, you typically run
json_decode($json, true)to get a nested associative array. Valinor works on that array structure. - Describe the target type. You map to a class with typed constructor parameters or typed properties. The types drive the conversion.
- Let Valinor construct the object. The mapper inspects the class, matches input keys to parameters, converts values, and recursively maps nested arrays into nested objects.
- Fail loudly on invalid input. If a value cannot be converted to the declared type, mapping throws an exception rather than silently producing a wrong-typed object.
A concrete example
Suppose you have a User class with a string $name, int $age, and an Address $address, where Address has string $city. Given:
$data = [
'name' => 'Ada',
'age' => 36,
'address' => ['city' => 'London'],
];
Valinor maps name and age to their scalar types and recursively turns the address array into an Address instance. The result is a real User object, not an array.
Where it fits
- API request handling: Convert decoded request bodies into command or DTO objects before passing them into your domain layer.
- Config loading: Turn configuration arrays into typed config objects so mistakes surface at load time.
- Message/queue consumers: Map incoming message payloads into typed objects before processing.
Trade-offs to weigh
| Approach | Strength | Cost |
|---|---|---|
| Hand-written hydration | Full control, no dependency | Repetitive, easy to miss nested cases |
| Valinor-style mapper | Type-driven, recursive, fails on bad input | Requires clear type definitions; some learning curve |
Plain json_decode |
Trivial | No type safety; errors appear later |
If your classes are already well-typed and you want validation and nested mapping without writing boilerplate, a mapper like Valinor is a good fit. If your input shapes are highly irregular or you need very custom per-field logic, hand-written hydration may be simpler.
Next step: start with one DTO that has a scalar field and a nested object, decode a sample JSON payload to an array, and map it. If the nested object is built correctly and a wrong-typed value throws, the setup is working as intended.
How do I install and configure Valinor in a PHP project?
Valinor is a PHP library for mapping raw input (arrays, JSON-decoded data, request payloads) into strongly typed value objects. The site itself currently just redirects to its documentation, so the practical starting point is Composer and the official docs.
The usual path is:
- Add the package with Composer in your project root.
- Require Composer's autoloader if your project does not already.
- Build a mapper instance and point it at your target class.
- Feed it the input array and let it construct the typed object, throwing on invalid data.
composer require cuyz/valinor
use CuyZ\Valinor\MapperBuilder;
$mapper = (new MapperBuilder())->mapper();
$user = $mapper->map(
User::class,
['name' => 'Ada', 'age' => 36]
);
Configuration is mostly done through MapperBuilder rather than a config file. Typical adjustments: enabling flexible/lenient handling for imperfect input, registering constructors for classes you cannot change, and adding custom exception messages so validation failures are readable in logs or API responses.
A useful decision criterion: use Valinor when you want one consistent, type-driven boundary between untrusted input and your domain objects. If you only need to validate a flat form and never build objects, a plain validator may be lighter. For the exact builder methods and supported types, check the documentation linked from Valinor.
How does Valinor compare to manual array-to-object mapping or other PHP mapping libraries?
Valinor is a PHP library for mapping arbitrary input into strongly typed value objects. It sits between two extremes: hand-written mapping code and full-featured serialization frameworks.
Manual array-to-object mapping
You write constructors or static factory methods that pull each key, cast it, validate it, and handle missing or nested data yourself.
- Full control over every rule and error message.
- No dependency, no configuration, no learning curve.
- Cost: repetitive per-class code, easy to forget edge cases, and type safety only as good as your manual checks.
- Nested structures and collections multiply the boilerplate quickly.
Valinor
Per the project's own description, it maps any input into a strongly typed value object structure. That means the library infers the target shape from your class — constructor parameters, property types, nested classes, collections — and constructs valid objects, reporting errors when input doesn't fit.
- Less glue code: you define the value object, not the mapping routine.
- Types are enforced at construction, so downstream code can trust the object.
- Error reporting is centralized rather than scattered through your mapper.
- Trade-off: you adopt its conventions and its type system, and you need to learn how it handles edge cases such as unions, nullable fields, or custom scalar types.
Other PHP mapping libraries
The wider ecosystem includes tools with different focal points — for instance, Symfony's Serializer Symfony for normalization/denormalization across formats, or CuyZ/Valinor GitHub if you want to read the source and issue history. Compare on:
| Criterion | Manual mapping | Valinor | General serializers |
|---|---|---|---|
| Boilerplate | High | Low | Low to medium |
| Type enforcement | As written | Built in | Depends on config |
| Error detail | You design it | Provided | Varies |
| Config surface | None | Moderate | Often large |
| Format support | N/A | Input to objects | Often JSON/XML/CSV |
Decision guide
Choose manual mapping when the shapes are few, stable, and trivial. Choose Valinor when you have many value objects, nested structures, and want construction-time type guarantees without writing each mapper. Choose a general serializer when you also need to emit multiple formats or integrate with an existing framework's normalization pipeline.
Next step: take one representative payload and one target class, and write the mapping three ways — by hand, with Valinor, and with your framework's serializer. Compare lines of code, error messages on a deliberately malformed field, and how each handles a nested collection. That small experiment will tell you more than feature lists.
Can Valinor handle nested objects, collections, and custom value object types?
Yes. Valinor is built for exactly that: it maps arbitrary input into a strongly-typed value object structure, which means nested objects, collections of objects, and your own custom value object classes are the intended use cases rather than edge cases.
What each case looks like in practice
- Nested objects: A top-level value object whose properties are themselves typed objects. Valinor walks the type tree and constructs each level, so you don't hand-write recursive hydration.
- Collections: Typed arrays/iterables of objects (for example a list of line items or a list of tags). The element type is part of the declared property type, so each item is mapped individually.
- Custom value objects: Your own classes — a
Money,Email,UserIdor similar — are treated as mapping targets, provided Valinor can construct them (a usable constructor, or a named/static constructor it can find).
How to decide whether it fits
| Situation | Valinor is a good fit | Look elsewhere |
|---|---|---|
| Input shape is untrusted or loosely typed (JSON, form data, arrays) | Yes — validation and mapping happen together | — |
| You want strict types at the boundary of your app | Yes | — |
| You mostly map flat scalars with no object graph | Works, but the benefit is smaller | A simple manual cast may be enough |
| You need a full ORM with persistence and lazy loading | No — this is mapping, not persistence | A database/ORM layer |
| You want attribute-driven mapping on the domain classes themselves | Depends on your style preference | A mapper that relies on PHP attributes |
The main trade-off is that you must declare your types accurately; the library's value comes from those declarations. If your classes are permissive (mixed properties, no constructor), you lose much of the safety.
A concrete next step
Take one real payload from your app — say an order with a customer, a list of items, and a total — and write the corresponding PHP classes with explicit property types. Then map the payload once and see whether the errors you get are the ones you'd want to see for bad input. That single experiment tells you more than any feature list.
For the authoritative details on supported type syntax and extension points, start at Valinor.
How does Valinor validate input and report mapping errors?
Valinor validates input by mapping it into a strongly-typed PHP value object structure, then reporting anything that fails to fit that structure. The validation isn't a separate rule engine you call first; it's the mapping process itself. You define classes with typed properties (and constructor parameters), and Valinor attempts to fill them from a source such as an array, JSON payload, or request data. A value that can't be coerced or matched to the declared type produces an error rather than a partially built object.
Valinor
What the validation covers
- Type correctness — each input value must be compatible with the target property's declared type.
- Nested structures — arrays of objects and object-valued properties are mapped recursively, so errors point at the specific nested path.
- Missing or extra data — absent required values and unexpected fields are handled according to the mapper's configuration rather than silently ignored.
How errors are reported
Because the output is a typed tree, Valinor can collect failures as structured messages tied to the path where they occurred, instead of throwing on the first problem. That means you get a list of issues in one pass — useful when you want to return several validation messages to a client rather than one at a time. The exact error object shape and message formatting come from the library's mapper settings, so check the current documentation for the precise API.
Practical example
Imagine an endpoint that accepts a JSON body for a User object with an email string and an age integer. If age arrives as "unknown", mapping fails at age and Valinor reports that path; if email is missing, that path is flagged too. You can then translate those paths into a 422 response without writing per-field checks by hand.
Choosing this approach
| Consideration | Mapping-based validation | Hand-written checks |
|---|---|---|
| Boilerplate | Low — types define the rules | High — one check per field |
| Nested data | Handled recursively | Often manual |
| Error detail | Path-aware, collected | Depends on your code |
If your application already models data as typed classes, mapping validation removes duplicated checks. If your validation rules are mostly cross-field business logic, you'll still write those separately — Valinor handles structure and types, not arbitrary domain rules.
Next step: define one small value object, feed it a deliberately broken payload, and inspect the error output. That shows you the reporting format before you commit the pattern across a larger API.
User reviews (0)