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

Activity Log Bundle Laravel Package

madmis/activity-log-bundle

A Symfony bundle for tracking user activity and entity changes. It provides configurable activity logging, Doctrine event integration, and a simple API to record, retrieve, and display activity history in your application.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: it is not a Laravel package. madmis/activity-log-bundle is a Symfony bundle (AppKernel registration, YAML service config, Doctrine annotations). It extends gedmo/doctrine-extensions' Loggable listener to record who made a change alongside the versioned diff. There is no service provider, no facade, no config publish, and nothing Composer will autodiscover in a Laravel app.

For a Laravel developer the useful move is therefore to read it as a reference implementation, not a dependency:

  1. Open the bundle's LoggableListener (or whatever it subclasses from Gedmo) and its log-entry entity. The delta over stock Gedmo is small: an extra username column populated from the Symfony security token at flush time.
  2. That is the entire feature. Once you have seen it, the Laravel equivalent is a 60-line trait + observer, or an off-the-shelf package.
  3. First use case to reason about: "show me the field-level history of this record and who changed it, and let me revert."

If you were in a Symfony 2.8/3.x app, minimal setup would be: composer require madmis/activity-log-bundle, register the bundle in AppKernel, enable gedmo/doctrine-extensions' Loggable listener, import the bundle's routing/service config, annotate entities with @Gedmo\Loggable / @Gedmo\Versioned, then doctrine:schema:update to create the log table. Laravel has no equivalent of any of those four steps.

The Laravel-native starting points, in order of fit:

  • owen-it/laravel-auditing — closest match to what this bundle does: per-field old_values/new_values, causer (user) tracking, per-model opt-in via a trait, revert support.
  • spatie/laravel-activitylog — event/description style with a properties JSON blob and batch UUIDs; better if you want "user X did Y" narrative logs than field diffs.

Both are maintained. This bundle's last release was 2017-08-07 and the repo is archived.

Implementation Patterns

What the bundle's model looks like (and what to copy): one row per changed field-set per flush, with columns roughly action (create/update/remove), objectId, objectClass, version, data (the changed fields), loggedAt, and the added username. Reading history is a query on objectClass + objectId ordered by version DESC; reverting is hydrating an entity from a prior row's data.

Porting the pattern to Laravel:

trait Auditable
{
    public static function bootAuditable(): void
    {
        static::created(fn ($m) => $m->writeAudit('created', [], $m->getAttributes()));
        static::updated(fn ($m) => $m->writeAudit('updated', $m->getOriginal(), $m->getChanges()));
        static::deleted(fn ($m) => $m->writeAudit('deleted', $m->getOriginal(), []));
    }

    protected function writeAudit(string $event, array $old, array $new): void
    {
        $this->audits()->create([
            'event' => $event,
            'old_values' => $old,
            'new_values' => $new,
            'user_id' => auth()->id(),          // null-safe: console/queue have no session
            'url' => request()?->fullUrl(),
            'ip_address' => request()?->ip(),
            'batch_id' => static::$auditBatchId ??= (string) Str::uuid(),
        ]);
    }
}

Key integration tips that mirror how the bundle is wired:

  • Resolve the causer behind a seam, not inline. The bundle reads the security token; in Laravel read Auth::id() but allow an explicit override (Auditor::actingAs($userId)) for console commands, queued jobs, and impersonation. Without this you get a table full of null causers from cron.
  • Opt-in per model, not globally. Gedmo does this via the @Loggable annotation; in Laravel do it via the trait. Do not wire a global Model::updated listener — you will capture session rows, pivot churn, and job bookkeeping.
  • Shape the table for querying: subject_type/subject_id index, an index on (causer_type, causer_id, created_at), and a JSON column. The bundle's objectClass/objectId pair is exactly this; keep the composite index or history screens get slow fast.
  • Batch correlation. The bundle has no concept of "one request, many writes." Add a batch_id (Spatie calls it batch_uuid) so a multi-model transaction renders as a single timeline entry.
  • Revert as a first-class operation: load the audit row, $model->fill($audit->old_values)->saveQuietly() inside a transaction, and write the revert itself as an audit event so the history stays append-only.
  • Cross-app interop: if a legacy Symfony service owns the log table, don't re-implement it — add a second read-only DB connection in config/database.php and map an Eloquent model onto log_entry. Consume; don't co-own.

Gotchas and Tips

  • Composer will not resolve it in a modern Laravel app. The bundle targets Symfony 2.8/3.x and PHP 5.6/7.0-era constraints; Laravel 9+ pulls Symfony 6 components. Expect symfony/* version conflicts and legacy Doctrine\Common\Persistence interfaces. This is a hard blocker, not a nuisance.
  • Archived since 2017, 11 stars, 0 dependents. No security releases, no PHP 8 support, no maintainer. Treat any transitive dependency it pins as unpatched.
  • Bulk operations bypass the audit trail silently. Gedmo's listener fires on onFlush for managed entities; DQL UPDATE/DELETE, ->update() on a query builder, and raw SQL all skip it. Same trap in Laravel with Model::query()->update() (no model events). Document it, or forbid bulk writes on audited tables.
  • The data column is often PHP-serialized. If you ever read the legacy table from Laravel, use unserialize($v, ['allowed_classes' => false]) or migrate the column to JSON first. Never unserialize() untrusted rows.
  • Console/queue flushes have no token, so username lands as null — indistinguishable from an anonymous web edit. This is the bundle's weakest point and the thing to fix first in a port.
  • Unbounded growth. One row per changed field-set per save, no pruning. Add a scheduled retention command (audits:prune --days=365) or the table outgrows the app within a year on a busy model.
  • Sensitive fields. Gedmo's allow-list is opt-in via @Versioned; in Laravel use $model->getHidden() or an explicit $auditExclude array. Password hashes, tokens, and PII must never land in the diff column.
  • Debugging "nothing is logging": in the Symfony original, check the listener is actually registered on the entity manager, the entity is mapped @Loggable, and the log table exists — in that order. The Laravel analogue is: trait booted (bootAuditable naming matters), events not suppressed (saveQuietly, withoutEvents), and the migration ran.
  • Extension points if you inherit a Symfony app using it: override the log-entry entity via the bundle's config, and decorate the listener service to change username resolution. Everything else is stock Gedmo and configured through gedmo.listener.loggable.
  • Verdict for adoption: score 0.1975, archived, single-digit stars — do not adopt. Use owen-it/laravel-auditing if you need field-level diffs with a causer, spatie/laravel-activitylog if you need event timelines, and steal this bundle's one good idea (causer resolved at flush time, overridable per execution context) wholesale.
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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource