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

Doctrine Lazy Json Odm Laravel Package

vuryss/doctrine-lazy-json-odm

Adds lazy-loading JSON fields to Doctrine MongoDB ODM documents, so large JSON blobs stay unserialized until accessed. Keeps hydration fast and memory low while preserving a simple typed API for reading and updating nested JSON data.

View on GitHub
Deep Wiki
Context7

Getting Started

  • composer require vuryss/doctrine-lazy-json-odm:^3.0. Before anything else, verify php -v — v3.0.0 requires PHP 8.5. Confirm your container image, Forge/Ploi/Vapor runtime, and CI matrix are on 8.5, otherwise stay on 2.x.

  • This is a Doctrine package, not an Eloquent one. It only matters if your app already runs Doctrine via laravel-doctrine/orm (or a hand-wired EntityManager) inside Laravel. Eloquent-only apps can stop here.

  • First place to look: the package's DBAL Type class (to get the exact registered type name) and the mapping snippet in the README. Then register that type where your Doctrine config lives — config/doctrine.php under 'types' => [...], or Type::addType(...) in a service provider if you wire Doctrine manually.

  • Map the property on the entity with that type instead of json/json_array:

    #[ORM\Column(type: 'lazy_json')] // confirm exact name from the package
    private array $payload = [];
    
  • First use case to try it on: a wide legacy table (audit_logs.payload, products.attributes, webhook_events.body) where list screens hydrate thousands of rows but only a handful ever read the JSON blob. The win is skipping json_decode() during hydration — measure memory_get_peak_usage() on a 1k-row findAll() before and after.

Implementation Patterns

  • Opt in per column, not globally. Leave the stock json type as default and switch only the fat columns. Mixing is fine and keeps behaviour predictable for the columns you actually read often.
  • No schema migration needed. The underlying column stays JSON/JSONB/TEXT; only the Doctrine mapping changes. Write a data-free migration only if you're also changing column type at the DB level.
  • List cheap, read deliberately. Pattern: repository returns entities for a paginated list without touching the JSON property; the detail/show action accesses it once. This is where most of the benefit lands.
  • Convert at the boundary. In API resources / view models, explicitly materialise (->toArray(), or the package's unwrap accessor) rather than returning the entity and hoping the wrapper serialises as a plain array.
  • Pair with partial selects when a query genuinely never needs the blob: $qb->select('p.id', 'p.name') avoids hydrating the field at all — cheaper than lazy-loading it.
  • Dirty-tracking pattern: treat the value as immutable. Read → modify → assign the whole array back to the property so Doctrine's change detection sees it.
  • Testing: assert on the decoded value, not the wrapper object; add one test that hydrates a large result set and asserts the property is not decoded until accessed (e.g. a decode counter or a json_decode spy) so a future refactor doesn't silently undo the lazy behaviour.
  • Upgrade path from 2.x: bump the constraint, run the suite on PHP 8.5 + Symfony 8 (and on 7.4 LTS if you're mid-upgrade), and diff behaviour on any code that type-hinted the field as array — the property type may now be a wrapper object.

Gotchas and Tips

  • v3.0.0 is a hard breaking change on runtime version. PHP 8.5 only. In practice this means your whole Laravel app must run 8.5, not just this package — audit other Doctrine/DBAL extensions and any pinned ^8.2 app constraint first. Symfony 8.0 is now tested; 7.4 LTS support is retained, which is your bridge if you're upgrading the framework separately.
  • Change tracking is the classic trap. Mutating inside the wrapper ($entity->payload['a'] = 1) may not mark the field dirty, so flush() writes nothing. Always reassign the full value.
  • Identity and array semantics. If the field is a wrapper object, ===, empty(), count(), isset($e->payload['k']) and foreach can behave differently than on a plain array. Type-hint the concrete wrapper (or unwrap in a getter) rather than leaving it as array.
  • Serialisation surprises. json_encode($entity) and toArray() on the entity may emit wrapper internals. Use API Resources/JsonSerializable explicitly.
  • Queues: lazy wrappers are not meaningful across a serialised job payload — pass IDs and re-fetch.
  • Register the type before metadata is read. Registering in a provider that boots after Doctrine's metadata driver causes Unknown column type "lazy_json" at getRepository() time. After changing the mapping, clear Doctrine's metadata cache (php artisan cache:clear, and the doctrine metadata cache command if installed).
  • Debugging: SQL logs won't show any of this since decoding is PHP-side. Use memory_get_usage(), Blackfire, or a temporary json_decode shim to confirm the field is actually deferred. If memory is unchanged, you're probably touching the property in a lifecycle callback (postLoad, accessor in __construct), which defeats the laziness.
  • Octane: nothing long-lived is cached by the wrapper itself, but verify per-request memory returns to baseline under load — a wrapper retained on a singleton entity manager is a leak vector.
  • Extension point: if you need custom encode/decode (encryption, compression), subclass the package's type or decorate it rather than switching back to json, so you keep the lazy behaviour.
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib