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

Symfony Serializer Extension Laravel Package

invis1ble/symfony-serializer-extension

A lightweight extension for Symfony Serializer that adds practical enhancements to object (de)serialization, helping PHP applications handle common normalization and denormalization scenarios with less custom code.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony Serializer extension — normalizers/encoders plus a cached path for URI round trips and JSON — not a Laravel package. There is no service provider, no config file, no facade. Expect to wire it yourself; budget an hour, not a day.

  1. Install the serializer and the extension together. Laravel does not require symfony/serializer, so pull it explicitly:

    composer require symfony/serializer invis1ble/symfony-serializer-extension
    
  2. Choose your constraint deliberately. Any existing ^1.0 / ^1.1 constraint already resolves to v1.2.0 — there are no breaking changes and the normalizer API is untouched, so most apps get this on the next composer update for free. Pin the new line only if you want to signal intent:

    composer require invis1ble/symfony-serializer-extension:^1.2 --with-all-dependencies
    

    Symfony Serializer 8 requires PHP 8.4.1+. On PHP 8.1–8.3, Composer resolves the Symfony 6.4/7 branch of the same package version — same release, different dependency graph. Check composer show symfony/serializer before assuming which one you got.

  3. Where to look first. The README is thin; the tests are the documentation. Read vendor/invis1ble/symfony-serializer-extension/src for the normalizer list, then the test suite — the v1.2 integration coverage is explicitly organised around the four things you'll actually do: URI round trips, JSON, context handling, and cached support. Those tests are executable examples.

  4. First use case. Serialize a DTO or URI value object to JSON in a controller, then deserialize it back:

    // app/Providers/SerializerServiceProvider.php
    public function register(): void
    {
        $this->app->singleton(Serializer::class, function () {
            return new Serializer(
                normalizers: [/* package normalizers, then ObjectNormalizer */],
                encoders: [new JsonEncoder()],
            );
        });
    }
    

    Confirm the round trip works before you build anything on top of it — a broken URI normalizer surfaces later as a 500 in a webhook path.

Implementation Patterns

Bind a singleton, inject it. One Serializer instance per app, registered in a dedicated provider (not AppServiceProvider, which tends to become a dumping ground). Inject into controllers, actions, jobs, and console commands by type. Keep it immutable and stateless so it's safe under Octane.

URI round trips. This is the sharpest tool in the package. URLs, signed callback endpoints, pagination links, and Location headers all become value objects you can normalize to a string and denormalize back without hand-rolled string juggling:

$json  = $serializer->serialize($webhookEndpoint, 'json');
$again = $serializer->deserialize($json, WebhookEndpoint::class, 'json');

Write a test asserting $again->equals($webhookEndpoint), not just that deserialization didn't throw — round trip fidelity is the whole point.

Map context to query parameters. Symfony's serialization context maps cleanly onto Laravel's ?include= / ?fields= conventions. Build the context array in a form request, pass it through to serialize(), and you get sparse responses without touching API Resources. Handle invalid include names by validating against a whitelist before passing them into the serializer — unknown group names fail quietly rather than loudly.

Cache with Laravel's own stores. The package's cached support expects a PSR-6/PSR-16 cache. Illuminate\Contracts\Cache\Repository already extends Psr\SimpleCache\CacheInterface, so wrapping Cache::store() in Symfony\Component\Cache\Adapter\Psr16Adapter avoids introducing a second cache subsystem. Use array in tests, Redis in production, and namespace the pool by package version so a deploy invalidates stale metadata.

Turn invalid input into 422s, not 500s. Deserialization failures throw NotNormalizableValueException / PartialDenormalizationException, which Laravel will happily render as a 500. Catch ExceptionInterface at the boundary and rethrow as ValidationException with the offending fields. Enable collect_denormalization_errors in the deserialization context so you report all bad fields at once instead of failing on the first.

Composer constraints across a CI matrix. If you test on multiple PHP versions, let the constraint float rather than pinning ^1.2 — you'll get Symfony 8 on 8.4/8.5 and Symfony 7 on 8.2/8.3, which is exactly what this release supports. Pinning ^1.2 with a PHP 8.2 runner will fail to resolve.

Gotchas and Tips

  • Same version, two different dependency graphs. v1.2.0 on PHP 8.4.1+ pulls Symfony Serializer 8; below that it pulls 6.4/7. Your local lockfile and CI lockfile can disagree without any version number being different. If behaviour diverges between machines, composer show symfony/serializer is the first command to run.
  • No Laravel integration ships with it. No auto-discovery, no published config, no facade, no container bindings. If you're expecting config/serializer.php, you'll be writing it.
  • Symfony major mixing is fine until it isn't. Running symfony/serializer:^8.0 alongside symfony/http-foundation:^7.x (pulled by Laravel 11/12) works, but any third-party package requiring symfony/serializer:^7 will hard-block the upgrade. Check composer why symfony/serializer before blaming this package.
  • Implement getSupportedTypes() in custom normalizers. Symfony removed the old supportsNormalization()-per-class caching path. If you wrote custom normalizers against an older Symfony, they'll still function but lose cached-metadata benefits — and this is the seam most likely to bite when moving between the 6.4/7/8 branches.
  • Clear caches on deploy after upgrading. Cached serializer metadata from v1.1.x is not guaranteed to be meaningful to v1.2.0's internals. Add the cache flush to your deploy script rather than discovering it in staging.
  • 100% coverage on 25 tests is not coverage of your use case. The suite is small and self-referential. Pin versions in composer.lock, and write your own contract tests around the specific value objects and URI shapes you depend on — especially if you rely on edge cases like IDNs, ports, or empty query strings.
  • Don't replace API Resources with this. Reach for the serializer for DTOs, value objects, and cross-boundary contracts (webhooks, third-party payloads, signed URLs). Transforming Eloquent models through it invites lazy-loading surprises; keep JsonResource for that.
  • Debugging tip. When normalization produces something unexpected, log get_class() of the normalizer that handled the value by iterating getNormalizers() (or your own wrapper) — the package's normalizers sit ahead of the generic ones, so ordering bugs look like data bugs.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource