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

Opensoft Simple Serializer Bundle Laravel Package

opensoft/opensoft-simple-serializer-bundle

A Symfony bundle that simplifies serializing PHP objects into arrays or JSON using the Symfony Serializer. Configure and control output through annotations or attributes, reducing boilerplate for APIs and data transfer objects.

View on GitHub
Deep Wiki
Context7

Getting Started

This bundle is a thin Symfony 2 integration layer around Opensoft's Simple Serializer library — it wires the plain-PHP Serializer into the container, adds annotation/attribute mapping discovery, and exposes a Twig extension. Treat it as a legacy integration: Symfony 2 is EOL and the last release is 2018-01-23, so use it only in an existing SF2 project that already depends on opensoft/simple-serializer, not in anything new.

Minimal setup:

  1. Install (composer will resolve the matching opensoft/simple-serializer version):
    composer require opensoft/opensoft-simple-serializer-bundle
    
  2. Register the bundle in app/AppKernel.php (SF2 has no bundle auto-discovery):
    $bundles = [
        // ...
        new Opensoft\SimpleSerializerBundle\OpensoftSimpleSerializerBundle(),
    ];
    
  3. Look here first inside the vendor tree, in this order:
    • DependencyInjection/Configuration.php — the actual config tree (groups, cache, annotation reader, handlers).
    • Resources/config/services.xml — service IDs and aliases; this tells you whether the service is opensoft_simple_serializer.serializer, simple_serializer, or aliased to the library class.
    • DependencyInjection/OpensoftSimpleSerializerBundleExtension.php — defaults that get applied if you configure nothing.
  4. First use case — serialize an entity/document to an array for a JSON API endpoint:
    // controller
    public function showAction($id)
    {
        $entity = $this->getDoctrine()->getRepository(Post::class)->find($id);
    
        $data = $this->get('opensoft_simple_serializer.serializer')
            ->toArray($entity);
    
        return new JsonResponse($data);
    }
    
    Annotate the model with whatever the underlying library expects (@Exclude, @Groups, @SerializedName, custom handler annotations) — the bundle's job is mainly making those annotations resolvable via the container's annotation reader.

Implementation Patterns

Define serialization shape on the model, not in controllers. The whole value of this bundle over hand-written toArray() methods is that each entity carries its own annotations. Keep controllers dumb:

use Opensoft\SimpleSerializerBundle\Annotation\Groups;
use Opensoft\SimpleSerializerBundle\Annotation\Exclude;
use Opensoft\SimpleSerializerBundle\Annotation\SerializedName;

class User
{
    /** @Groups({"list", "detail"}) */
    private $id;

    /** @Groups({"detail"}) */
    private $email;

    /** @Exclude */
    private $passwordHash;
}

Use groups for API versioning / list-vs-detail. This is the single most useful day-to-day pattern: one model, several serialization contexts:

$listItem = $serializer->toArray($user, ['groups' => ['list']]);
$full     = $serializer->toArray($user, ['groups' => ['detail']]);

Wrap it in a small application-level service. Don't scatter the bundle's service ID through controllers; wrap it once so you can swap serializers (e.g. to JMS or Symfony Serializer) later without a repo-wide find-and-replace:

class ApiSerializer
{
    public function __construct(private $serializer) {}

    public function forList($object): array
    {
        return $this->serializer->toArray($object, ['groups' => ['list']]);
    }
}

Compose with Symfony's JsonResponse / view listeners, not the bundle's Twig filter for API work. The Twig extension is fine for templates, but for API payloads you want the array in a controller so you can version, paginate, and apply HTTP caching deliberately.

Feed the serializer plain arrays or DTOs when the shape doesn't match the entity. Simple Serializer is shallow-ish by design; deep entity graphs are cheaper to flatten yourself into an array and serialize the leaf objects, than to fight the mapping.

Handle collections explicitly. Most serializers of this style do not recurse into ArrayCollection automatically in a predictable order — loop and serialize, then wrap:

$items = array_map(fn($u) => $serializer->toArray($u, ['groups' => ['list']]), $users);

Integration tips

  • Register the annotation reader (doctrine/annotations) as a service and point the bundle at it; without it annotation-based mapping silently serializes everything by reflection.
  • If your project already uses JMS Serializer, don't mix — pick one and delete the other's annotations from shared models. Two annotation sets on one entity is a debugging nightmare.
  • Enable the bundle's cache (if configured) in prod only; annotation parsing is the slowest part and caching it in dev gets stale during model edits.

Gotchas and Tips

Symfony 2 only, and abandoned. The bundle targets the SF2 bundle structure (AppKernel, services.xml, no autowiring). It will not drop into Symfony 4+ unchanged: no AbstractBundle/AbstractBundle alias, no #[AsService], and the service definitions assume SF2's container semantics. In an SF4+ project, port the services.xml definitions to your own services.yaml and skip the bundle class entirely.

PHP version ceiling. 2018-era code targeting SF2 typically runs on PHP 5.6–7.x. If you're on PHP 8, watch for ReflectionParameter::getClass() deprecations, dynamic property notices, and each()-style helpers in the vendor tree. Run composer why-not php 8.x before assuming it installs.

Service ID guessing is the #1 time-waster. The bundle's serializer service is aliased, but the exact ID varies by version. Don't guess — inspect the container:

php app/console debug:container | grep -i serial

Then use the canonical alias, or (better) inject the underlying library's Serializer type-hint via the alias so you're not coupled to the ID.

Annotations are read from Doctrine\Common\Annotations. If doctrine/annotations is missing or the reader isn't configured, @Exclude/@Groups are silently ignored and your private fields leak into JSON. Test this deliberately: serialize an object with an @Excluded field and assert it's absent. Do this in an integration test, not just a unit test — the failure is configuration, not logic.

No groups configured means everything serializes. toArray($obj) with no group option includes every public getter and (depending on the underlying library's reflection strategy) possibly private properties. Always pass groups explicitly for user-facing responses; don't rely on "it only serializes what I annotated."

Circular references and lazy proxies. A serialized Doctrine entity with a bidirectional relation will either recurse forever or serialize a proxy object as []. @Exclude the inverse side, or better, serialize a DTO. If you see {} for a related entity in JSON, that's the proxy, not a bug in the serializer.

JsonSerializable / jsonSerialize() on entities will not be called. This serializer builds arrays from reflection and annotations, bypassing your model's own JSON contract. If you've written jsonSerialize() methods, they won't fire — a common source of "why is my custom formatting ignored?"

Config caching bites in dev. If you enable the bundle's metadata cache, changes to annotations on a model won't apply until you clear var/cache/dev. Clear cache after model edits, or disable caching for dev in config_dev.yml.

Extension points. When the built-in mapping isn't enough, the intended escape hatches are (a) custom annotation handlers registered via config, and (b) the underlying library's handler/normalizer interfaces — register them as services and pass them into the serializer. The bundle itself adds almost no behavior beyond wiring, so any serious customization belongs on the library side, not as a bundle override.

Have an exit plan. Given 9 stars, zero dependents, and no release since 2018, assume no security fixes. Budget for migration to symfony/serializer with groups + normalizers, or JMS Serializer. The wrapper-service pattern from "Implementation Patterns" makes that a one-class change rather than a project-wide rewrite — worth doing on day one.

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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo