happyr/serializer-bundle
Symfony bundle that integrates HappyR's serializer, wiring services and configuration so you can convert PHP objects to JSON and back with less boilerplate. Useful for APIs and apps that need consistent, configurable object serialization.
Bundle subclass plus a DI extension, so composer require happyr/serializer-bundle inside a Laravel app gets you a package that never boots — there is no service provider, no config file to publish, no facade. Its wiring only happens inside a Symfony kernel.Symfony\Component\Serializer\Serializer service plus an annotation-driven metadata layer so you can decorate plain PHP objects with @Exclude, @Groups, @VirtualProperty, @SerializedName-style markers instead of hand-maintaining arrays. Read src/Annotation/ first — the API surface is tiny and the README is thin; that directory is the whole value proposition.composer require symfony/serializer works standalone in Laravel. Bind it as a singleton in a service provider:$this->app->singleton(Serializer::class, function () {
$normalizer = new ObjectNormalizer(null, new MetadataAwareNameConverter(...));
return new Serializer([$normalizer, new JsonEncoder()], [new JsonEncoder()]);
});
password, remember_token, internal flags, and expose a computed full_name — without writing a per-endpoint toArray() or a resource class for every shape. If that's your problem, Symfony Serializer (the library) solves it; the bundle is only the annotations convenience layer on top.$user->only(['id','name']) in one controller and $user->toArray() in another, annotate properties with a group and select per endpoint:$serializer->serialize($user, 'json', ['groups' => ['list']]);
This is the pattern worth stealing even if you drop the bundle — it makes payload shape a property of the model, not of the controller.
@Exclude for write-only/sensitive fields. Treat it as defense-in-depth alongside Eloquent's $hidden. $hidden only affects toArray()/toJson(); it's bypassed the moment someone iterates getAttributes(), and it doesn't protect nested value objects.full_name, avatar_url, unread_count belong on the object as annotated accessors so every response includes them consistently. In Laravel this is the same role as an accessor + $appends, but scoped to serialization instead of leaking into every toArray().['groups' => ..., 'attributes' => [...], 'skip_null_values' => false] at the top level; the ObjectNormalizer forwards child context into nested objects. Build one helper (ApiSerializer::for('list')) so nobody hand-writes context arrays in fifty places.ModelNormalizer. Symfony doesn't understand Illuminate\Database\Eloquent\Model or Collection. Without a custom normalizer it getter-walks the model, which triggers relation lazy-loading (N+1 on a list endpoint) and dumps internals. Normalize from getAttributes() + explicitly requested getRelations(), and add a Collection normalizer.ObjectNormalizer. Money, UUIDs, Carbon dates, enums, and DTOs should be handled explicitly; order in the serializer array decides who wins.@Since/@Until-style markers keeps /v1 and /v2 payloads in one class instead of duplicating resources.symfony/serializer ~2.7|~3.0. It will not resolve alongside Symfony 5/6/7, and its annotation reader depends on doctrine/annotations, which is deprecated in favour of PHP 8 attributes. Do not put this on a new build — port the ideas.ObjectNormalizer calls public get*/is*/has* methods. On an Eloquent model that means getKey, getAttributes, getQueueableRelations, and more end up in your JSON, and is()-style business methods become booleans. Serialize DTOs, not models.user->posts->user->posts... throws CircularReferenceException. Either set circular_reference_handler in context or, better, don't serialize model graphs — build the tree you intend to return.@Exclude filters output, it doesn't skip work. The accessor still runs; expensive computed properties cost you even when excluded. Use the attributes context key to prune before normalizing hot paths.skip_null_values); Laravel consumers often expect explicit null keys. Set it deliberately per endpoint.@Groups. In Laravel, cache metadata only outside local.AbstractNormalizer::GROUPS at the call site.NotNormalizableValueException, ExtraAttributesException, CircularReferenceException → map to 422/500 rather than letting them bubble as opaque 500s.MetadataAwareNameConverter for camelCase→snake_case, and setCallbacks are all plain Symfony Serializer features you keep even after dropping the bundle.Symfony\Component\Serializer\Attribute\Groups (PHP 8 attributes, Symfony 6.3+) if you want to stay on the component, or spatie/laravel-data / API Resources if you want the same declarative shape with Laravel-native testing, validation, and pagination ergonomics.How can I help you explore Laravel packages today?