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

Vich Uploader Serialization Bundle Laravel Package

rithlock/vich-uploader-serialization-bundle

Bridges VichUploaderBundle and Symfony Serializer so uploadable entities can be serialized cleanly in APIs. Adds normalizers and helpers for exposing file URIs, metadata, and upload fields without custom boilerplate, simplifying JSON responses for REST and JSON:API projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first. Despite the "PHP package" framing, this is a Symfony bundle (Rithlock\VichUploaderSerializationBundle) and has zero relevance to a Laravel application. There is no service provider, no facade, no Eloquent bridge. Do not attempt to composer require it into a Laravel app — you would drag in vich/uploader-bundle, jms/serializer-bundle, and Doctrine ORM for no benefit. If you're on Laravel, stop here and use Storage::url() in an APIResource instead; the equivalent is a 30-line JsonResource.

Minimal steps (Symfony only).

  1. Confirm your stack already has vich/uploader-bundle and jms/serializer-bundle installed and pinned. If not, this bundle is not for you — the prerequisite adoption cost dwarfs the benefit.
  2. Install:
    composer require rithlock/vich-uploader-serialization-bundle
    
  3. Register the bundle in config/bundles.php, after the two dependencies:
    return [
        // ...
        Vich\UploaderBundle\VichUploaderBundle::class => ['all' => true],
        JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true],
        Rithlock\VichUploaderSerializationBundle\VichUploaderSerializationBundle::class => ['all' => true],
    ];
    
  4. Configure a Vich mapping with an explicit uri_prefix — this prefix is what surfaces in your JSON:
    vich_uploader:
        db_driver: orm
        mappings:
            avatars:
                uri_prefix: /uploads/avatars
                upload_destination: '%kernel.project_dir%/public/uploads/avatars'
                namer: Vich\UploaderBundle\Naming\UniqidNamer
    

Where to look first. Before writing any code, read two things in the package source: the DependencyInjection/ extension (to see whether the serializer handler is auto-registered or must be tagged jms_serializer.subscribing_handler), and the handler class itself. With zero stars and zero dependents there is no community documentation — the source is the documentation.

First use case. A User entity with an avatarName column. GET /api/users/1 should return {"id":1,"avatar":"/uploads/avatars/abc123.webp"} rather than "abc123.webp". That single transformation — filename to resolvable URL during JMS serialization — is the entire value proposition.

Implementation Patterns

The two-field entity invariant. Vich always uses a pair: a non-persisted File property (uploaded, validated) and a persisted string property (the stored filename). This bundle operates on the second one via the serializer handler:

use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;

#[Vich\Uploadable]
class User
{
    #[Vich\UploadableField(mapping: 'avatars', fileNameProperty: 'avatarName')]
    private ?File $avatarFile = null;

    // Persisted; routed through the bundle's handler so JSON shows a URL.
    private ?string $avatarName = null;
}

Keep the file field out of serialization. Annotate avatarFile with @JMS\Exclude (or a @JMS\Groups allowlist). The bundle's job is to transform avatarName; it is not meant to touch the uploaded File.

Per-field vs. per-entity configuration. If the package exposes a URI-prefix or asset-base-path option at the field level, prefer field-level scoping over entity-wide defaults. This keeps avatarName and, say, a documentPath in the same entity from colliding on a shared prefix.

Serialization grouping. Wrap the annotated filename field in a JMS serialization group (e.g. api:read) so the handler only fires on API responses, not on internal serializer calls (audit logs, message queues, cache warmers). This avoids leaking filesystem-derived URLs into contexts that expect raw storage keys.

Integration tip — verify output parity before cutting over. If you already have a hand-written JMS handler or a @PostSerialize listener doing the same job, run both side by side in a test environment and diff the JSON. The bundle's URI generation may differ from yours in subtle ways (leading slash, trailing slash, CDN base path) and any divergence is a public API contract break.

Testing pattern. Write a functional test that persists an entity with a known filename, serializes it via jms_serializer, and asserts the exact JSON string. This test is your only safety net — without it you have no way to detect a breaking change on a future (however unlikely) update.

Gotchas and Tips

The bundle is unmaintained. Zero stars, zero dependents, single maintainer. Treat declared version constraints as unverified and budget a composer why-not spike against your pinned Symfony and JMS versions before adopting. On a Symfony major upgrade, expect resolution failure and plan to fork.

Missing mapping resolves to null, silently. If an entity is annotated for serialization by this bundle but its Vich mapping is absent from vich_uploader.yaml, the handler typically returns null or an empty string rather than erroring. Your API just starts returning {"avatar": null} for every user. Cross-check that every serialized file field has a matching mapping key.

Missing files render as broken URLs, not errors. Vich happily generates a URI from a stored filename whether or not the file exists on disk. If users delete files out-of-band, your API will emit 404-ing links. Add a post-serialization check or a smoke test that HEADs the constructed URLs in staging.

Namer changes break URLs retroactively. If you switch Vich from UniqidNamer to a directory-namer mid-project, new files get new paths but old stored filenames still resolve fine only if the old namer's path convention still exists at fetch time. Snapshot the URI shape in tests so a namer config change is caught.

The uri_prefix is your public contract. Whatever you put in vich_uploader.mappings.<name>.uri_prefix appears verbatim in the JSON. If you later front the files with a CDN, you must change this prefix — which is a breaking change for clients. Set it to something abstract (e.g. /uploads/avatars) and let a reverse proxy or CDN rewrites handle the rest.

Register the handler explicitly if auto-registration fails. Because the bundle is small, DI auto-wiring may not kick in for your Symfony version. If JSON output shows raw filenames instead of URLs, verify in debug:container that the handler service is registered and tagged jms_serializer.subscribing_handler, and that jms_serializer.yaml hasn't disabled the tag auto-discovery.

Vendor it, don't depend on it. For production use, copy the handler class into an internal bundle (one file, a few dozen to a couple hundred lines) and add your own tests. This eliminates the abandoned-dependency risk entirely while preserving the behavior. The glue code is small enough that this is cheaper than negotiating maintenance risk with your security team.

Not a Laravel pattern to imitate. Do not port the annotation-driven design to Laravel. The idiomatic equivalent — Storage::url($this->avatar_path) inside an app/Http/Resources/UserResource.php — is clearer, testable, and doesn't require a serializer handler. Use this bundle's source as a reference for the idea, not for the implementation.

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