cuyz/valinor
Valinor maps raw inputs like JSON and plain arrays into strongly typed PHP objects, validating every value along the way. It supports native types plus PHPStan and Psalm advanced types, gives precise human-readable errors, and can normalize objects back into formats like JSON or CSV.
fromArray() factories per DTO (cheap to start, expensive at scale, inconsistent error messages), symfony/serializer + symfony/validator (powerful, framework-coupled, two stacks to configure), or a bespoke mapping layer (pure cost, no differentiation). Valinor is a single MIT, zero-dependency Composer package — a small build-vs-buy line item with a clear "buy" answer for teams not already deep in Symfony Serializer.MapAsInt, MapAsBool(true: ['on','yes']), MapExplodedStringToList, MapFromJson, MapFromKey, MapWithPrefix) let a product absorb messy partner data — booleans sent as "on", lists flattened into comma-separated strings, zipCode vs postalCode naming — at the boundary, instead of scattering defensive casts through the domain. That's a roadmap lever: "we can onboard partner X without a data-cleanup project."NormalizeKeyTo, NormalizeToSingleValue, IgnoreOnNormalization) supports keeping snake_case public APIs while the PHP codebase stays camelCase, and makes "never serialize this field" a declarative, reviewable attribute rather than a unset() someone forgets. This is a security/PR-review decision as much as a formatting one.Consider it when:
Look elsewhere when:
Diligence flags: public dependent count is effectively zero/unreliable as an adoption signal; weigh the ~1.5k stars, published docs site, active release cadence (2.6.0 with a substantial feature set), and the Stryker mutation-testing badge instead. Require a short internal spike plus a documented fallback path before making it load-bearing.
For executives: Valinor is a free, MIT-licensed PHP library that converts raw input — API responses, webhooks, CSV, JSON, config files — into strongly-typed objects, rejecting anything malformed with clear, actionable error messages. It replaces the repetitive, per-project "glue code" we currently hand-write to validate and populate objects, which is where a large share of data-quality bugs originate: bad payloads pass silently, then surface as null-pointer crashes or corrupt records downstream. Adopting it moves failure to the boundary, where it's cheap, visible, and testable. The commercial case is modest but real: lower maintenance cost on every integration we build, faster onboarding of messy partner data, and a smaller, better-audited dependency surface (zero runtime dependencies). Risk is contained — it's a single package we can adopt incrementally behind our own interfaces and remove if needed.
For engineering: This is a mapper and normalizer, not a framework. One MapperBuilder maps source data into constructor-promoted, readonly DTOs and validates it against native PHP types plus PHPStan/Psalm types (generics, shaped arrays, integer ranges, non-empty-string). Failures throw a MappingError you can traverse for field paths — ideal for API error responses and import reports. The 2.6.0 configurators cover the boring-but-expensive cases: scalar casting for stringly-typed inputs, key remapping for inconsistent upstreams, JSON/CSV-string sub-field decoding, and per-property attributes to keep strictness global while relaxing locally. The normalizer gives us the reverse direction with key renaming and IgnoreOnNormalization for sensitive fields. Recommended path: pilot on one inbound integration, wrap the mapper behind our own port interface so the dependency stays swappable, add contract tests against real payload fixtures, benchmark with cache warmup before it lands on a hot path, and confirm the maintainer/bus-factor story before it becomes load-bearing.
How can I help you explore Laravel packages today?