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

Eloquent Serializer Laravel Package

theofidry/eloquent-serializer

A lightweight serialization layer for Laravel Eloquent models. Define dedicated serializer classes to control which attributes and relationships are exposed, then turn models, collections, and paginated results into clean arrays for APIs and JSON responses.

View on GitHub
Deep Wiki
Context7

Getting Started

This package wires Symfony's Serializer component into Eloquent so you can turn models (and their loaded relations) into JSON/XML/arrays and hydrate models back from serialized payloads — instead of hand-rolling toArray() / fill() logic. Treat it as a serialization layer, not an ORM replacement.

Minimal setup (v1.1.0):

composer require theofidry/eloquent-serializer:^1.1

v1.1.0 targets Laravel ~5.5, Symfony ^3.4 || ^4.0, PHP ^7.1. On a modern Laravel/PHP you will still need to relax platform requirements:

composer require "theofidry/eloquent-serializer:^1.1" --ignore-platform-reqs

Since v1.1.0 the service provider uses Laravel package auto-discovery, so no manual registration is needed. If you're on an older Laravel or have discovery disabled, register it manually (and only then — see Gotchas):

// config/app.php (Laravel 5.x style, only if auto-discovery is off)
'providers' => [
    // ...
    TheoFidry\EloquentSerializer\EloquentSerializerServiceProvider::class,
],

Where to look first:

  1. The package README for the exact container binding / facade name and config key.
  2. The published config (config/eloquent-serializer.php or similar) — this controls relation handling and normalizer registration.
  3. The ServiceProvider source to see which normalizers are bound into Symfony's Serializer. v1.1.0 added the previously missing Symfony normalizers, so if you forked or hand-patched on 1.0.x, re-check this list.

First use case — serialize a model with a loaded relation to JSON:

$user = User::with('posts')->find(1);

$json = app('serializer')->serialize($user, 'json');
// {"id":1,"name":"...","posts":[{...}]}

Then the round trip — hydrate a model from a payload:

$user = app('serializer')->deserialize($json, User::class, 'json');

If that single round trip works against a throwaway model, the package is doing its job. Everything else is configuration.

Implementation Patterns

API response layer. Use the serializer as the single place that shapes model output. Keep controllers thin:

public function show(User $user)
{
    return response(
        app('serializer')->serialize($user->load('posts', 'profile'), 'json'),
        200,
        ['Content-Type' => 'application/json']
    );
}

Selective output with groups. Annotate (or configure) which attributes/relations belong to which group, then serialize per-context:

$json = app('serializer')->serialize($user, 'json', [
    'groups' => ['public', 'user:list'],
]);

This is what keeps you from leaking email / password on a public endpoint without maintaining a parallel $hidden list.

Hydrating from inbound payloads. Deserialize request bodies into models rather than manually mapping fields:

$user = app('serializer')->deserialize(
    $request->getContent(),
    User::class,
    'json'
);
$user->save();

Pair this with form-request validation before deserialization — the serializer hydrates, it does not validate.

Reusable serialization for queues and caches. Serialize a model to JSON, push it onto a job, and rehydrate on the worker instead of passing IDs and re-querying:

dispatch(new SyncUser(app('serializer')->serialize($user, 'json')));

Be deliberate here: rehydrated models are detached from the session/connection, and stale data is now your problem.

Custom normalizers for computed fields. Where a model exposes accessors or aggregates (full_name, post_count), register a small normalizer that adds them on top of the default output rather than polluting the model with $appends:

$serializer = app('serializer');
// register/override via config or a container binding that decorates the default normalizer

Integration tip — one serializer, one config. Bind the configured serializer under one container key and inject it, so tests and controllers share the same normalization rules. Do not new Serializer(...) ad hoc in controllers.

Gotchas and Tips

Still archived and stale — plan for ownership. v1.1.0 (Laravel 5.5 / Symfony 3.4–4.0 / PHP 7.1) is a compatibility bump, not a revival; assume no further patches. Before adopting: fork it, or budget a weekend to replace it with (a) Laravel API Resources, (b) spatie/laravel-data, or (c) Symfony Serializer used directly with your own model normalizer. For a greenfield project, option (c) is roughly 1–2 normalizer classes and gives you a maintained dependency.

Auto-discovery + manual registration = double bindings. v1.1.0 enabled Laravel package auto-discovery. If you copied the 1.0-era config/app.php snippet into a fresh app, the provider is registered twice — which typically shows up as duplicate normalizers in the chain or "normalizer already registered" errors. Remove the manual entry unless you're deliberately bypassing discovery.

Relations must be eager-loaded first. Normalization reads what's in getRelations(); it does not trigger queries for you reliably. Call ->load(...) or with(...) before serializing, or you will serialize models with missing relations — and if the normalizer does lazy-load, you get N+1s.

Circular references will bite. User → posts → author → posts is the classic. Enable Symfony Serializer's circular-reference handler (default behavior) or use groups to cut the graph. If you see CircularReferenceException, the fix is almost always a serialization group, not a config flag.

Hydration ignores $fillable semantics unless you wire them in. Symfony's denormalizer writes properties; it is not fill(). Verify mass-assignment protection still applies on the paths where you deserialize user-supplied JSON, or an attacker can set is_admin.

Casts, dates, and accessors differ between the two directions. serialize() may emit a Carbon date in one format; deserialize() expects the same format back. Test the round trip for any model with $dates, $casts, or accessors — round-trip asymmetry is the most common "it works until it doesn't" bug.

Platform constraints are the first failure. The v1.1.0 bump to PHP ^7.1 and Symfony ^4.0 still conflicts with modern Laravel/PHP 8.x. Expect to install with --ignore-platform-reqs, then verify the normalizer behaves under your Symfony Serializer version (the Serializer API changed across 3.x → 4.x → 5.x+); the bundled normalizers ship for 3.4/4.0, not for later majors.

Debugging output. There is no debug:serializer in Laravel. Dump the intermediate step instead:

dump(app('serializer')->normalize($user, null, ['groups' => ['public']]));

This shows the array before encoding, which is where groups, relation naming, and circular refs are actually decided.

Config quirks to check on day one: the config's relation-naming strategy (snake_case vs method name), whether unloaded relations are silently skipped or error, and how null attributes are emitted. Each of these changes your API contract, so snapshot the actual JSON output in a test and treat it as the source of truth.

Extension points. Add normalizers by decorating the serializer binding (or the package's normalizer service) rather than editing vendor code — the archived status makes vendor edits a guaranteed merge conflict. v1.1.0 filling in the "missing Symfony normalizers" is a good reminder to diff the provider against your fork if you carried local patches. Custom normalizers, custom encoders (CSV, XML), and custom name converters are all reachable through Symfony Serializer's standard NormalizerInterface / DenormalizerInterface, which is the main reason to use this package at all: you inherit that ecosystem even though the bridge is effectively dead.

When not to use it. If your app returns a handful of fixed response shapes, Laravel API Resources are simpler, maintained, and cover 90% of this package's day-to-day value. Reach for EloquentSerializer when you specifically need Symfony Serializer semantics — groups, name converters, multi-format (XML/CSV) output, and denormalization — and are willing to own a fork.

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.
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
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