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 Changelog Bundle Laravel Package

softspring/doctrine-changelog-bundle

A Symfony bundle for Softspring Doctrine Changelog that automatically records entity changes and stores an audit trail of inserts, updates, and deletes. It integrates with Doctrine ORM to help track data history, surface modifications, and support compliance and debugging workflows.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package is a Symfony bundle that hooks Doctrine ORM's unit of work, computes field-level before/after diffs on selected entities, and persists them with an author and timestamp. The architectural fit for a Laravel/Eloquent estate is therefore poor as a dependency and good as a pattern. It has no awareness of Eloquent models, model events, DB::table() writes, or raw SQL, so on a typical Laravel service it would observe nothing at all. What transfers is the design: an opt-in per-entity marker, a synchronous diff writer on flush, a callable user resolver, and a separate presenter layer for rendering history. Treat the repository as reference architecture, not a component to install, unless the target service is a Symfony app or a Laravel app already running Doctrine as its persistence layer.

Integration feasibility. Two distinct paths, with very different costs. (1) Native adoption — only viable if the service is Symfony + Doctrine, or Laravel + Doctrine bridge. Then integration is a composer require, bundle registration (or manual listener/subscriber binding in a service provider), a changelog table migration, and a user resolver pointed at Auth::id(). Days, not weeks, for a single entity. (2) Laravel-native adoption — requires manual re-implementation: bind the listener and its collaborators, map the bundle's config tree into a plain config/changelog.php, hand-write the schema to match the bundle's changelog entity, and accept that the documented configuration surface is only partially applicable. That is a spike plus a sprint, at which point a Laravel-native package is the better buy. For our purposes, the feasible path is path (1) or "pattern reuse."

Technical risk. This is where the TPM should spend the most attention, because the risks are concentrated and mostly non-technical in nature.

  • License is the headline risk. AGPL-3.0 is a strong copyleft license with a network-use clause. For any service we operate over a network, AGPL can be read as obliging us to offer the corresponding source of the combined work. Most corporate legal functions will either reject it outright or require an isolated-process boundary. This must go to legal before engineering spends a sprint, not after.
  • Bus factor of one, effectively. One GitHub star and no visible community means no third-party security review, no ecosystem of fixes, and a single maintainer's availability is the entire support model. Assume no CVE response SLA.
  • Release hygiene is weak. The v5.6.0 notes contain only a compare link — no enumerated features, no breaking-change list, no deprecations. Release dates in the metadata also look anomalous relative to the current date, which itself warrants a provenance check before we trust the version line.
  • Doctrine ORM 3.x compatibility is an evolving area for this package family, and Doctrine unit-of-work timing (diffs on onFlush, identifiers materializing on postFlush) is where integrations break silently.
  • Data-handling risk is real, not theoretical. Old/new values are stored verbatim and the package ships no redaction, so password hashes, API keys, remember-tokens, and PII flow straight into an append-only table with no retention policy. That converts an audit feature into a GDPR/HIPAA liability if unmanaged.
  • Coverage risk. Mass updates, query-builder updates, seeding, backfills, and writes from other services write nothing. Any compliance narrative built on this must explicitly scope the claim to "changes made through the ORM," or it is misleading.

Key questions. These should be answered before any commitment:

  1. Is the target service Symfony/Doctrine, or Laravel/Eloquent? If the latter, are we evaluating this as prior art only?
  2. Has legal signed off on AGPL-3.0 in a network-delivered service, or is a process boundary required?
  3. What is the precise audit obligation — "who changed this record," or a tamper-evident ledger? The package satisfies the former, not the latter.
  4. Which 3–5 entities are in scope, and what is the redaction list for each?
  5. What retention window and archival destination are we committing to, and who owns the pruning job?
  6. Is the audit row legally required to be transactional with the business write, or is best-effort logging acceptable? This determines whether we swallow listener exceptions.
  7. Who is on the hook if the maintainer disappears — do we fork, or do we accept the freeze risk?

Integration Approach

Stack fit. Score the package against the actual runtime, not the marketing description. If the estate is Laravel/Eloquent — which the framing of this evaluation implies — the correct decision is to not install it and instead adopt owen-it/laravel-auditing or spatie/laravel-activitylog, both of which have the community, license clarity, and Eloquent-native hooks this package lacks. Borrow three ideas from this repository regardless: opt-in per-entity tracking via an interface, a user-resolver closure rather than a hardcoded auth source, and a dedicated presenter that turns a diff payload into a human timeline. If the estate genuinely has Symfony services, this bundle is a legitimate candidate for those services only, and the Laravel decision should be made independently.

Migration path. The package is additive — one table, one listener, config entries — so adoption is reversible in principle. The migration path is: (a) create the changelog table via doctrine:migrations:diff on the bundle's own entity, or mirror those columns in a Laravel migration (entity class, entity ID, action, JSON/TEXT diff payload, user identifier, created-at); (b) register the listener; (c) enable exactly one entity; (d) instrument and compare against a hand-written expectation for a week. The rollback path is a config change plus a down-migration, but note the data does not roll back with it — history accumulated under a license or vendor we later reject still sits in our database.

Compatibility. Verify four things concretely rather than reading release notes: the composer.json constraints for PHP, doctrine/orm, and symfony/*; the schema of the changelog table across the 5.5.x → 5.6.0 boundary (did it gain required columns?); behavior under Doctrine ORM 3.x; and behavior under our auth stack's user resolver, including queue workers where the authenticated user is null. Pin the exact version in composer.json — do not float. If the resolver returns null in a worker, every async-originated change records as anonymous, which quietly destroys the value of the audit trail for exactly the writes most likely to be questioned.

Sequencing. A defensible order:

  1. Week 0 — decision gate. Legal review of AGPL-3.0 and an architecture confirmation of the target stack's persistence layer. If either fails, stop; the remaining steps are moot.
  2. Week 1 — pattern selection. Compare this bundle against the Laravel-native alternatives on hooks, license, maintenance activity, and redaction support. Decide install vs. emulate.
  3. Week 2 — single-entity spike. One high-value entity (invoice, contract, price record), composite index on (entity_class, entity_id, created_at), redaction list defined, presenter written.
  4. Weeks 3–4 — hardening. Insert/delete edge cases, queue-worker actor propagation, retention command, try/catch around the recording path so audit failure never rolls back a business transaction.
  5. Post-launch — expansion. Add entities only when a named stakeholder asks for that entity's history. Do not enable global tracking; signal-to-noise collapses and the table grows fast.

Operational Impact

Maintenance. The package is small and additive, so code maintenance is low — but the ownership burden is not, because it lands entirely on us. Budget for: a pinned dependency that will not receive timely security patches, a changelog file that has historically lived in commit messages rather than curated notes, and Doctrine compatibility work that arrives with Doctrine's release cadence rather than ours. A realistic estimate is a recurring slice of one engineer's attention per quarter, plus a documented fork-or-freeze contingency if the maintainer stops.

Support. There is no commercial support and effectively no community. Internal support therefore means one or two engineers who understand Doctrine unit-of-work timing well enough to debug missing or mistimed changelog rows. Make that a named-person dependency rather than "the team," and write down the three failure signatures (null entity ID on inserts, missing rows on mass updates, noisy association diffs) so on-call can triage without the original author. User-facing support improves materially: "why did this record change" tickets get answered from a timeline view instead of a database archaeology exercise, and MTTR on data incidents drops because point-in-time state is reconstructable.

Scaling. Two axes to plan for explicitly, because the package itself plans for neither.

  • Write amplification. One changelog row per mutation means write volume on the audit table scales with business write volume, and every tracked entity write becomes two writes plus serialization. On high-write tables this dominates. Set a per-entity write-rate threshold in the adoption criteria — if an entity exceeds it, it is out of scope.
  • Unbounded storage growth. Append-only tables are never pruned until they are a problem. Decide a retention window on day one, schedule the pruning command, and agree an archival destination. Also size the diff column as TEXT/LONGTEXT/JSON — VARCHAR(255) will silently truncate rich-text changes and produce an audit trail that is confidently wrong.

Failure modes. Enumerate these in the runbook, each with a detection signal:

Failure Detection Mitigation
Listener error rolls back a business write Elevated 5xx on tracked endpoints try/catch + log the recording path unless the audit row is legally mandatory
Inserts record null entity ID Changelog rows with null IDs Handle inserts in the post-flush pass
Silent coverage gaps Diff between row counts and business operations Document loudly that query-builder/raw SQL writes are invisible
Secrets persisted verbatim Regex scan of the changelog payload Maintained redaction list, reviewed on every entity addition
Anonymous authors from queues/console Null user IDs in worker-originated rows Resolver closure that takes the job's actor, plus an explicit system marker
Orphaned history after refactor Two histories for one conceptual entity Rows are keyed by FQCN string — treat class renames as data migrations
Stale config after deploy Changelog behavior "randomly" reverting Restart queue workers; treat the listener binding as the fragile seam

Ramp-up. Expect one engineer-day to first value if the stack is Symfony/Doctrine, and roughly a sprint if we are emulating the pattern in Laravel. The learning is not in the package API — it is in Doctrine's flush lifecycle and in building the presenter. Invest half a day in a written demo: one entity, one detail page, one revert-or-not decision, and a walkthrough of the diff renderer. Two things must be communicated to stakeholders at the point of adoption, because they will be asked about later and the answers should not be improvised: the audit trail covers ORM-mediated changes only, and retention/archival is our responsibility, not the package's. Framing the decision as "we are adopting an audit pattern and choosing a component per service, with AGPL and maintenance risk explicitly scored" is defensible; framing it as "we bought an audit solution" is not, given a one-star, AGPL-licensed, single-maintainer bundle with empty release notes.

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.
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
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource