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

Buildable Serializer Bundle Laravel Package

remcosmitsdev/buildable-serializer-bundle

A Symfony bundle that integrates a buildable serializer, letting you compose reusable builders to control object normalization, reduce boilerplate, and keep API responses consistent and maintainable.

View on GitHub
Deep Wiki
Context7

Getting Started

Note on this release: 1.0.0 is the initial tagged release, and the changelog contains no itemized entries (only a compare link). Treat the README, composer.json, and the test suite as the authoritative documentation — there is no migration story to read because there is no prior version.

  1. Confirm what you're actually installing. The package name ends in -bundle, and the namespace convention (*Bundle, DependencyInjection/, Resources/config/services.yaml) strongly implies a Symfony bundle. Laravel has no bundle loader and no registerBundles(). Before anything else, run:

    composer require remcosmitsdev/buildable-serializer-bundle
    cat vendor/remcosmitsdev/buildable-serializer-bundle/composer.json
    

    Look at type and require. If it pulls in symfony/framework-bundle or symfony/dependency-injection, you will not get the serializer service for free — you'll need to construct it yourself or find the framework-agnostic core package it wraps.

  2. Check for a framework-agnostic core. Most *-bundle packages are a thin DI wrapper around a plain-PHP library. If buildable-serializer (or similar) exists as a separate package, depend on that in Laravel and skip the bundle entirely. The bundle's Resources/config/services.yaml is the best map of which concrete classes do the real work.

  3. Read the tests first. With an empty changelog, tests/ is the de-facto API reference. Look for a fixture DTO with attributes and the assertion that hydrates it — that's your copy-paste starting point.

  4. Wire it once, in a provider. Register the serializer as a singleton in AppServiceProvider::register() so you pay metadata-parsing cost once per request:

    $this->app->singleton(Serializer::class, fn () => /* construct from the bundle's service definitions */);
    

First use case: hydrating a request payload into a typed DTO, then validating it. Replace the usual $request->validated() → new Dto(...) hand-mapping with a single serializer call. If you already use spatie/laravel-data and it covers your needs, this package has to beat it on attribute ergonomics or performance to justify the extra wiring — prove that on one endpoint before rolling it out.

Implementation Patterns

Mirror the bundle config into Laravel config. Symfony's Configuration.php / Extension.php defines what's tunable (usually cache dir, debug flags, custom normalizer lists). Copy those keys into config/serializer.php and pass them at construction time. Don't expect php artisan vendor:publish to work — there is no Laravel service provider shipped.

DTO-per-endpoint, serializer as the boundary. The payoff pattern is a thin controller:

public function store(StoreOrderRequest $request, Serializer $serializer)
{
    $dto = $serializer->denormalize($request->validated(), CreateOrder::class);
    $order = $this->orders->place($dto);

    return new OrderResource($order);
}

Keep Eloquent models out of the serializer. Serialize DTOs out and hydrate DTOs in; let repositories own persistence. This sidesteps lazy-loading surprises and keeps the attribute metadata small.

Register custom normalizers via a tag-like loop. In Symfony you'd tag services. In Laravel, collect them in a config array and loop at construction:

$normalizers = array_map(
    fn (string $class) => $this->app->make($class),
    config('serializer.normalizers', [])
);

This is your escape hatch for money objects, enums with custom wire formats, and third-party value objects.

Compose with Form Requests, not instead of them. Let Laravel validate the raw array, then denormalize. Doing validation inside normalizers couples two concerns and makes error messages hard to surface. If the package throws its own exception type on malformed input, catch it in Handler::render() or a dedicated exception renderer and convert to a 422.

API resources are the outbound mirror. JsonResource for presentation, serializer for inbound hydration and cross-service payloads. Mixing both directions through one mechanism is where teams get confused about where behaviour lives.

Testing. Use the serializer directly in unit tests against fixture DTOs — no HTTP, no container. In feature tests, app(Serializer::class) from the container. This gives fast coverage of the mapping layer independent of your endpoints.

Gotchas and Tips

  • Composer type is a trap. If it's symfony-bundle, Laravel's package discovery won't register anything. You must write the provider. Check extra.laravel in composer.json for a providers key — if it's absent, nothing is auto-wired.
  • Version 1.0.0 means the semver contract starts now, not that it's battle-tested. Pin ^1.0 and read the diff of the 1.0.0 tag against main if you need to know what landed. An empty changelog on a first tag usually means "this is what we shipped", not "we've hardened it".
  • Metadata caching is the classic footgun. Attribute/reflection-driven serializers cache class metadata. In dev, stale caches after editing a DTO produce baffling "unknown property" errors. Find the cache invalidation hook and call it from a deploy script or php artisan optimize:clear.
  • Constructor promotion + readonly + defaults are where denormalizers most often break: a missing key that has a default should be omitted, not passed as null. Test each optional field explicitly rather than assuming.
  • Enums and DateTimeImmutable need verified round-trip tests. These are the two types where every serializer library differs, and the difference surfaces in production, not in the happy-path README example.
  • Nested collections (array<Item>) usually need either a docblock parser or an explicit generic syntax. If the package relies on docblocks, static analysis and runtime can disagree — keep phpstan in CI so the shapes stay honest.
  • Debugging: when denormalization throws, dump the raw input and the target class in the same message. The most common cause is a key-name mismatch (camelCase JSON vs snake_case properties) or a nested object sent as a scalar.
  • Extension points to look for: custom normalizer/denormalizer interfaces, a name converter (for case mapping), and a constructor/instantiator strategy (for DTOs with required params or private constructors). If none of these are exposed, the package will hit a wall on the first non-trivial domain object — check before committing.
  • Weigh it against spatie/laravel-data. That package is Laravel-native, ships its own provider, has validation and resource integration, and a large user base. This one wins only if you specifically want the buildable/attribute-driven model or you're sharing DTOs with a Symfony service. Make that trade explicit in your ADR.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core