Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Lib Normalization Bundle Laravel Package

paysera/lib-normalization-bundle

A Symfony bundle that integrates Paysera’s normalization library, providing configurable normalizers and denormalizers for converting PHP objects to arrays and back—ideal for consistent API request and response data handling.

View on GitHub
Deep Wiki
Context7

Getting Started

First, verify this is the right package. paysera/lib-normalization-bundle is a Symfony bundle, not a Laravel package. It ships a Bundle subclass plus a DI extension that registers Paysera's normalization services into a Symfony container. Laravel will not auto-discover it, will never boot the bundle, and will never process its configuration tree. So the real dependency you want in a Laravel app is almost certainly the underlying paysera/lib-normalization library; the bundle is only useful to you as a reference for how to wire those services.

Minimal steps

  1. composer require paysera/lib-normalization-bundle:^1.4 on a branch, then run composer why-not paysera/lib-normalization-bundle 1.4.0 and composer outdated --direct. Release 1.4.0 is a Symfony 7.4 compatibility change; confirm your Laravel version's Symfony component constraints (Laravel 11/12 sit on Symfony 7.x) resolve cleanly.
  2. Read the source before writing code. Open vendor/paysera/lib-normalization-bundle/ and look at, in this order:
    • *Bundle.php and DependencyInjection/*Extension.php — the canonical list of service IDs, aliases, parameters, and tags this package expects.
    • Resources/config/*.xml|yaml|php — the actual definitions you'll need to mirror.
    • The composer.json of both the bundle and paysera/lib-normalization for the PHP and Symfony version matrix.
  3. Decide your wiring strategy (see below) and create one NormalizationServiceProvider.
  4. First use case: canonicalizing request input at the HTTP boundary. In a FormRequest::prepareForValidation(), run the incoming payload through the normalizer so downstream validation, DTOs, and persistence all see the same types.
protected function prepareForValidation(): void
{
    $this->replace(
        app(NormalizerRegistry::class)->normalizeArray($this->all(), $this->normalizationMap())
    );
}

Pick that boundary deliberately. If you normalize in controllers, jobs, and console commands separately, you'll get three different canonical forms within a month.

Implementation Patterns

Wire it once, in one provider. Because the bundle's extension never runs, you own the container definitions. Two viable shapes:

  • Mirror the bundle: replicate the service IDs from the extension file in register()/boot(), binding interfaces to implementations and tagging custom normalizers.
  • Skip the bundle: require paysera/lib-normalization directly and require --dev the bundle only as documentation. This is usually the lower-maintenance choice — you avoid a "Symfony bundle" entry in a Laravel app that does nothing at runtime and confuses the next developer.

Use a registry, not scattered new. Laravel has no tag system, so emulate Symfony's tagged-collector:

// config/normalization.php
return [
    'normalizers' => [
        Money::class    => MoneyNormalizer::class,
        LocalDate::class => DateNormalizer::class,
    ],
];

Then in the provider, foreach (config('normalization.normalizers') as $type => $class) { $registry->register($type, $this->app->make($class)); }. This gives you the bundle's extensibility story without its container.

Normalize at the edges, not in the domain. Three boundaries where this earns its keep:

  1. Inbound HTTP — FormRequest::prepareForValidation() or a global middleware for API routes.
  2. Imports/queues — CSV imports, webhook consumers, and job payloads all bypass HTTP normalization. Route them through the same registry so an "off" from a CSV and an "off" from a form produce identical values.
  3. Outbound serialization — API resources and export writers, if you need stable string forms (money as "12.34", dates as ISO-8601) regardless of driver.

Compose, don't chain ad hoc. Chain steps as a pipeline — trim → empty-to-null → type cast → format — and keep the order fixed in config. Order is the entire contract; null→""→null round-tripping is a bug you can only avoid by pinning the sequence.

Keep money and decimals as strings. Normalizers that hand back floats will silently lose precision on the way to a DECIMAL(10,2) column. Normalize to a canonical string, and let the DB or a value object own arithmetic.

Testing. Unit-test each normalizer as a pure function. Then add one feature test per endpoint that posts deliberately hostile payloads ("0", "false", null, "", " 42 ", "2026-02-30") and asserts on what landed in the database, not on the validator's error bag. That's where normalization regressions actually surface.

Gotchas and Tips

Auto-discovery does not exist here. composer require plus nothing else will leave you with a package that is installed, autoloaded, and completely inert. If you see zero change in behaviour, that is expected — not broken.

Don't app()->make(PayseraNormalizationBundle::class) and hope. The bundle class is a Symfony kernel concept; instantiating it outside a kernel gets you nothing.

Config defaults will diverge. Symfony's Configuration tree supplies defaults the bundle applies silently. If you hand-translate to config/normalization.php, compare against the tree in DependencyInjection/Configuration.php — the default timezone, date format, and null-vs-empty policy are exactly the values people forget to copy, and the failure mode is quiet data drift, not an error.

Exceptions are not HTTP responses. Whatever the library throws for unnormalizable input (an InvalidArgumentException or a Paysera domain exception) becomes a 500 unless you catch it and rethrow as ValidationException::withMessages() or wrap it in a middleware. Decide this once in the provider or a middleware, not per controller.

Boolean coercion is the classic trap. "false", "off", "0", and 0 do not behave uniformly across normalizer implementations. Read the library's truthiness rules and write an explicit test — don't infer them from PHP's (bool) cast.

Timezone and locale are ambient state. Date normalization reads the default timezone. Set date_default_timezone_set(config('app.timezone')) consistently and include a DST-boundary test; a date-only normalizer is safe, a datetime one is not.

Bind implementations as singletons. Stateless normalizers should be singleton() in the provider. Rebuilding a normalizer graph per request is pure overhead, and if any normalizer caches format rules, prototype binding defeats it.

Debugging: app()->bound('your.service.id'), then dd(app()->make(...)). If a Symfony-style dotted service ID isn't resolving on a class-typed constructor argument, you're missing an alias — Laravel resolves by class name, Symfony by ID, and the bundle only defines the latter.

Version and provenance. This is a 0-star package with a small bus factor; the 1.4.0 note is a compatibility bump, not a feature release, and says nothing about CI coverage against Symfony 7.4. Pin an exact version in composer.json, commit the lockfile, and confirm the tag is signed/provenanced. Check that 1.4.0 didn't raise minimum constraints in a way that forces a broader Symfony upgrade across your other Laravel packages.

Extension point to watch: if you later need the bundle's own behaviour (Twig filter, validator constraint, autowired service), that's the moment to reassess — otherwise staying on the underlying library keeps your Laravel app free of a permanently dormant Symfony bundle.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment