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

Serializer Extension Bundle Laravel Package

invis1ble/serializer-extension-bundle

Symfony bundle that extends the Serializer component with additional normalizers, encoders, and configuration options, making it easier to serialize and deserialize PHP objects to JSON, XML, and other formats in Symfony applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the bundle with Composer:

composer require invis1ble/serializer-extension-bundle

Version 1.1.0 adds Symfony 8 support while keeping Symfony 6.4 / 7.x working. Existing ^1.0 constraints already resolve to it; to pin the release line explicitly:

composer require invis1ble/serializer-extension-bundle:^1.1 --with-all-dependencies

If Flex doesn't provide a recipe, register it manually in config/bundles.php:

return [
    // ...
    Invis1ble\SerializerExtensionBundle\SerializerExtensionBundle::class => ['all' => true],
];

There is typically nothing mandatory to configure — the bundle's job is to register a set of normalizers/context helpers on top of the framework's serializer service. Check whether a config file was created under config/packages/ (the alias is usually derived from the bundle name, e.g. serializer_extension); if not, defaults apply. No service configuration changes are required when upgrading to v1.1.0.

Where to look first:

  1. vendor/invis1ble/serializer-extension-bundle/src/DependencyInjection/ — the extension class and its Configuration show every config key and how services are wired.
  2. vendor/invis1ble/serializer-extension-bundle/src/Resources/config/ — as of v1.1.0 the service definitions are PHP files (Symfony 8 dropped XML DI). Look for *.php definitions with the serializer.normalizer tags; older tags are still at priority 10.
  3. The underlying invis1ble/symfony-serializer-extension package (v1.1.0 requires ^1.2) — the bundle is mostly a DI wrapper; the actual normalization logic lives there.

First use case: you have DTOs/entities containing \DateTimeInterface, backed enums, and \Stringable value objects, and you're tired of writing one-off normalizers or sprinkling #[Context] attributes. Inject SerializerInterface as usual and serialize — the bundle's normalizers should produce consistent scalar output without extra code:

final class OrderController
{
    public function __construct(private SerializerInterface $serializer) {}

    public function __invoke(Order $order): Response
    {
        return new Response(
            $this->serializer->serialize($order, 'json'),
            200,
            ['Content-Type' => 'application/json']
        );
    }
}

Implementation Patterns

Treat it as a serializer configuration layer, not a replacement. The bundle extends symfony/serializer; you still use SerializerInterface, #[Groups], #[SerializedName], #[MaxDepth], and the standard context keys. The win is fewer custom normalizers and more predictable output for common PHP types.

Reusable context builders. Rather than repeating context arrays across controllers, centralize them in a small service or the bundle's context-builder abstraction (if exposed). A typical pattern:

final class ApiContextFactory
{
    public function forList(): array
    {
        return [
            'groups' => ['order:list'],
            'datetime_format' => \DateTimeInterface::ATOM,
            'json_encode_options' => JSON_UNESCAPED_UNICODE,
        ];
    }
}

Then $serializer->serialize($orders, 'json', $contextFactory->forList()). This keeps format/date/enum behavior consistent across endpoints.

Overriding the bundle's normalizers. When the bundle's behavior for a type doesn't match your domain (e.g. you want a custom date format for a specific class, or a different representation for a backed enum), register your own normalizer and control ordering via the tag priority:

services:
    App\Serializer\MoneyNormalizer:
        tags:
            - { name: serializer.normalizer, priority: 100 }

Higher priority wins for supportsNormalization(). The bundle registers its normalizers at priority 10 (unchanged in v1.1.0), so anything above that reliably takes precedence. Verify the effective order with bin/console debug:container --tag=serializer.normalizer.

PHP service definitions, not XML. Since v1.1.0 the bundle ships PHP DI files because Symfony 8 removed XML configuration support. If you were overriding or decorating a bundle service by importing or editing its XML, rewrite that override as a PHP service definition (services.php or a services: block in YAML) using the same service IDs — the IDs themselves did not change. This is a mechanical port, but it must be done before you upgrade to Symfony 8, since the legacy XML files are gone.

Per-format handling. Symfony's serializer supports json, xml, csv, etc. The bundle's normalizers generally return scalars, so they compose well across formats — but be deliberate: date formats and empty-collection handling differ between JSON and XML. Use EncoderInterface-level context for encoder-specific options and keep normalizer context type-agnostic.

URI value objects. The bundle exposes a URI factory alias in the container (kept stable in v1.1.0, and covered by the release's URI/JSON round-trip tests). If you serialize URI-bearing DTOs, rely on that alias rather than instantiating a URI factory yourself, so the same configuration is used everywhere.

API Platform and Messenger. Anything resolving the shared serializer service benefits automatically: API Platform's JSON-LD/JSON:API output, Messenger's SerializerInterface transport serializer, and symfony/messenger envelope stamping. If you use Messenger with a custom transport serializer, confirm it decorates the same serializer service and not a separately-built one.

Value objects and enums. Backed enums typically normalize to their ->value; pure (non-banked) enums and \Stringable objects usually go through __toString() or a dedicated normalizer. Audit one representative payload per type early (var_dump the JSON) so you know exactly what shape downstream consumers get.

Testing. Use KernelTestCase and fetch serializer from the container so you exercise the real bundle configuration rather than a hand-built Serializer:

self::assertJsonStringEqualsJsonString(
    '{"createdAt":"2024-01-01T00:00:00+00:00","status":"paid"}',
    self::getContainer()->get('serializer')->serialize($order, 'json')
);

Mirroring the bundle's own approach in v1.1.0 — container checks for normalizer registration/autowiring/priority, plus HTTP-style round trips and invalid-input cases — is a good template for your own integration tests.

Gotchas and Tips

  • Normalizer priority collisions. Symfony ships a DateTimeNormalizer and BackedEnumNormalizer already. The bundle registers its normalizers at priority 10, which can silently change output versus the framework defaults. Always dump debug:container --tag=serializer.normalizer and confirm which one wins for each type.
  • Bundle registration order. Compiler passes that alter serializer.normalizer tags depend on bundle order in bundles.php. If custom normalizers are ignored, try registering the bundle after FrameworkBundle and rebuild the cache.
  • Config alias guessing. The YAML root key is derived from the bundle class name and can differ from what you expect (serializer_extension vs invis1ble_serializer_extension). Inspect DependencyInjection/Configuration.php before writing config — a wrong key throws an InvalidConfigurationException at cache warmup, not at runtime.
  • It is not JMS Serializer. No YAML/XML mapping metadata, no @Type annotations, no exclusion policies. If you're migrating from JMS, plan a separate port; this bundle only extends the native attribute-based serializer.
  • Circular references remain your problem. The bundle won't invent a circular-reference handler. Keep CircularReferenceHandler configured and use #[MaxDepth]/#[Groups] to break graph cycles before they hit the serializer.
  • Empty collections vs empty objects. [] encodes as a JSON array — fine — but a normalized empty \stdClass may encode as {}. If consumers are strict, normalize empty collections to [] explicitly in the DTO or via context.
  • Debugging a wrong payload. Work bottom-up: (1) debug:container --tag=serializer.normalizer, (2) call $normalizer->supportsNormalization($object) directly, (3) inspect the returned array before encoding. Most "the bundle broke my output" issues trace to a priority collision or an unexpected context key.
  • Extension points. The cleanest customization is a decorator around SerializerInterface (for cross-cutting context defaults) or a small normalizer for your value objects. Avoid monkey-patching bundle services; override via services.yaml (or PHP definitions) bindings instead.
  • Compatibility matrix. v1.1.0 supports Symfony 6.4, 7.x and 8.x. PHP 8.1 is the floor for 6.4/7.x; Symfony 8 requires PHP 8.4.1+. The release was exercised on PHP 8.1/Symfony 6.4, 8.2/7.4, 8.4/8.0 and 8.5/8.1. Run your full test suite after changing either PHP or Symfony minor, not just the serializer tests — normalizer signatures shifted across 5.x/6.x/7.x/8.x.
  • Upgrading to Symfony 8. Two things to check: (a) your platform satisfies php >= 8.4.1, and (b) any application code that directly imported the bundle's legacy XML files is switched to the equivalent PHP files. Applications that only registered the bundle need no changes. Confirm the resolved dependency with composer show invis1ble/serializer-extension-bundle invis1ble/symfony-serializer-extension.
  • Vendor risk, somewhat reduced. This is still a single-author package, so pin the version in composer.json, read the service definitions before upgrading, and be prepared to vendor/fork the normalizer you depend on. v1.1.0 is a better signal than before: it fixes issue #1, ships a documented changelog diff, and passed CI across four PHP/Symfony combinations plus a production-consumer install without dev dependencies. Even so, verify the actual tag and version you get with composer show invis1ble/serializer-extension-bundle rather than trusting "last release" metadata — a future-dated entry usually means an unreleased branch or a metadata quirk.
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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core