nwidart/laravel-normalizer
A Laravel package for normalizing data into consistent, predictable formats. Define custom normalizers to clean and transform input, making validation and storage simpler across your application.
Before your first composer require, read the source. The package is pre-1.0, last tagged in July 2016 (0.2, PHP 7 scalar type hints), and has no published API reference. composer require nwidart/laravel-normalizer will resolve on modern PHP only if the composer.json constraints permit it — check the php and illuminate/* requirements first and, if needed, pin explicitly:
composer require nwidart/laravel-normalizer:^0.2
Where to look first, in order:
src/ — the whole package is small. Read every class top to bottom in one sitting; you need to know the exact contract (normalize() signature, return type, whether it accepts scalars/arrays/Arrayable).composer.json — confirm the PHP floor and which Illuminate version was targeted. This was written against Laravel 5.x-era Illuminate.README.md — the usage example, if present, is your fastest path to a working call.tests/ (if shipped) — the most reliable description of intended behavior for a dormant package.Auto-discovery: if the package ships a service provider, Laravel 5.5+ will register it via extra.laravel.providers. If it predates that convention (likely for a 2016 package), add it manually to config/app.php providers and check whether a facade alias is needed.
First use case — normalize a form request before validation or persistence. The natural entry point is the boundary where untrusted, shape-variable input arrives:
$normalized = app(SomeNormalizer::class)->normalize($request->all());
Start with one normalizer class that handles a single, well-understood payload (e.g., a phone/email/date-bearing "contact" form), assert the output shape in a unit test, and only then wire it into a controller. Do not introduce it across your codebase until that one path is proven — the payoff (centralized normalization) is real, but the package gives you no safety net.
1. Wrap normalization in your own interface, not the package's. Because the package is unmaintained and pre-1.0, do not let nwidart\laravel-normalizer types leak into your domain code. Define a small Normalizer contract of your own and let one adapter implementation delegate to the package:
interface Normalizer { public function normalize(array $input): array; }
class PackageNormalizer implements Normalizer
{
public function normalize(array $input): array
{
return app(\Nwidart\Normalizer\...::class)->normalize($input);
}
}
This is the single most important pattern in this assessment: it means swapping the package for 40 lines of hand-rolled code (or laravel-data/spatie/laravel-data later) is a one-file change, not a refactor.
2. Normalize at the ingress boundary, then validate. Order matters: normalize → validate → persist. Normalizing first means your FormRequest rules see a predictable shape (consistent casing, trimmed strings, arrays where scalars were allowed), so rules stay simple and don't need prepareForValidation() branches.
protected function prepareForValidation(): void
{
$this->merge(app(ContactNormalizer::class)->normalize($this->all()));
}
3. Model attribute normalization via mutators. For attribute-level rules, call the normalizer from an Eloquent mutator or a small HasNormalizedAttributes trait so that any write path (seeders, jobs, imports) gets the same treatment as HTTP input:
public function setPhoneAttribute($value): void
{
$this->attributes['phone'] = $this->normalizer->normalize(['phone' => $value])['phone'];
}
4. Centralize per-payload normalizers, one per DTO/screen. Create App\Normalizers\* classes keyed to a specific payload rather than one god-normalizer. Composition is fine — a UserNormalizer can call an AddressNormalizer — but keep each class's input shape narrow and documented in a docblock, since the package itself documents nothing.
5. Integrate at job/import boundaries too. The highest-value use is not HTTP at all: CSV imports, webhooks, and queue payloads are where shape drift actually bites. Normalize once when the job is dispatched or when the import row is read, and log the pre/post shape on failure.
6. Bind normalizers in a service provider so they are injectable and testable, and so you have one obvious place to change when you eventually replace the package.
composer.lock and pin ~0.2.0; a 0.x minor bump is allowed to break you under semver."1" → 1, null → int) now throw TypeError on PHP 7+ and are stricter still on PHP 8. Test with declare(strict_types=1) in your files too, since that changes call-site behavior.$request->input('x'), which is null when absent. If the package's signature declares string/array without a ?, you will get runtime TypeErrors that no amount of validation-rule tweaking fixes. Guard with ?? [] / ?? '' at the call site.extra.laravel block. If the container can't resolve the normalizer, register it manually — that's usually the whole problem.assertSame(['phone' => 'string', ...], array_map('gettype', $out))). When behavior looks wrong, diff input-vs-output on one fixture rather than reading the package source again — the package is small enough to single-step in a debugger in one pass.php artisan vendor:publish gives you anything; if config/normalizer.php is referenced in source but absent from your app, defaults live in the package's PHP files and are not overridable without a fork.TrimStrings/ConvertEmptyStringsToNull middleware, prepareForValidation(), casts, and Arr::wrap/Arr::only for structural work.How can I help you explore Laravel packages today?