Download the PHP package williamug/audited without Composer

On this page you can find all versions of the php package williamug/audited. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package audited

Audited

Latest Version on Packagist tests Total Downloads

"The only Laravel audit package that ships a complete admin UI — Livewire table, Vue/Inertia table, and per-model timeline — with zero configuration."

A simple, robust audit logging package for Laravel applications. Drop one trait onto a model and every create, update, delete, and many-to-many relationship change is automatically recorded. Authentication events, manual logging, per-model subject relationships, request-level tracing, async queue support, scheduled pruning, and a configurable schema are included out of the box.


Table of Contents


Requirements

Dependency Version
PHP ^8.2
Laravel ^10.0, ^11.0, ^12.0, ^13.0

Installation

1. Require the package

2. Run the install command

This publishes config/audit.php and copies a timestamped migration into database/migrations/. Running the command a second time is safe — it skips files that already exist.

3. Run the migration

That's it. The package is now active. Authentication events are logged automatically and the audit:prune command is scheduled quarterly without any further setup.


Configuration

After installation, config/audit.php is in your application. Every option has a sensible default — you only need to change the values that differ from those defaults.


Basic Usage

Automatic Model Logging with the Auditable Trait

Add use Auditable; to any Eloquent model. Every created, updated, and deleted event on that model will be recorded automatically — no observers or extra setup required.

That single trait registration produces entries like:

action module description
create Billing Created Invoice #42
update Billing Updated Invoice #42
delete Billing Deleted Invoice #42

Update entries only record what changed. If five fields exist on the model but only one was modified, old_values and new_values will each contain that one field — not the full row.

Saving without changes produces no log entry. If save() is called with no dirty fields, nothing is written.


Customising the Log Description

Define auditLabel() on your model to replace the default ClassName #id label in log descriptions.

Log descriptions will now read:


Excluding Fields from Logs

To exclude specific fields from being recorded for a particular model, define the $auditExclude property. This is applied on top of the global sensitive_fields in the config.


Manual Logging

For events not tied to a model lifecycle — approving a report, exporting data, any custom business action — the package gives you three equivalent ways to write a log entry. Pick the one that fits your style.

Facade (recommended — no import needed, IDE-friendly):

The Audited facade is registered automatically via Laravel's package auto-discovery — no use import required in your controllers or services.

Global helper (best for quick one-liners):

The audited() helper is loaded automatically via Composer's files autoload — available everywhere in your application with no imports.

Service class (explicit, useful when injecting or mocking):

All three call the same underlying logic and write to the same table. The Facade and helper both support the full set of named arguments:

Using a custom action string

The $action parameter accepts both the AuditAction enum and a plain string. Use a plain string for any domain-specific action that is not in the enum — there is no need to extend it.

Custom action strings are stored verbatim in the action column. Handle them gracefully in your UI:

Attaching tags to a log entry

Pass a tags array to attach arbitrary key-value metadata to any log entry. Useful for batch IDs, import sources, workflow step names, or any context that does not belong in the description.

Tags are stored as JSON and cast to an array on retrieval:

Linking a manual log entry to a specific model

Pass a subject to associate the log entry with an Eloquent model. This populates subject_type and subject_id so the entry appears in $model->auditLogs() alongside the automatically generated entries.

Specifying the actor

By default the log reads auth()->user() as the actor. Pass an explicit causer when you need to attribute the log entry to a different user, or to a system process with no user at all.

For system actors (jobs, commands, scheduled tasks) see System Actors (Causer).


Suppressing Audit Logging

Use withoutAudit() to run a block of code without generating any log entries for that model class. This is useful for bulk imports, seeders, and test factories where the individual operations are not meaningful audit events.

withoutAudit() only suppresses the model class it is called on. Other auditable models used inside the same callback are logged normally:

Logging is always re-enabled after the callback, even if the callback throws an exception.


System Actors (Causer)

When logging from a job, command, or scheduled task there is no authenticated user. Without explicit attribution user_id is null, which is ambiguous — was this a guest action or a background process?

The causer parameter solves this. It accepts any Eloquent user model (same as always), a SystemCauser, or anything that implements the Causer interface.

The causer_type column makes the actor unambiguous in every log entry:

user_id user_name causer_type Meaning
42 Jane Doe user Authenticated human
null ImportMembersJob job Queued job
null sessions:prune command Artisan command
null NightlyReportGenerator system Scheduled process
null null null No actor (e.g. failed login attempt)

Custom causer type

Implement the Causer interface on any class:


Authentication Event Logging

When log_auth_events is true in the config (the default), the package automatically listens for Laravel's Login, Logout, and Failed auth events and writes a log entry for each.

Event Action recorded
Illuminate\Auth\Events\Login login
Illuminate\Auth\Events\Logout logout
Illuminate\Auth\Events\Failed failed_login

To disable this behaviour:

Custom login credential field

If your app identifies users by something other than email (for example, phone_number or username), configure the field used to identify subjects in failed login entries:


Soft Deletes

Models that use Laravel's SoftDeletes trait get full lifecycle coverage automatically — no extra configuration required.

Event Action recorded Description
delete() delete Deleted Invoice #42
restore() restore Restored Invoice #42
forceDelete() force_delete Permanently deleted Invoice #42

The restore() event produces a clean restore log entry. The intermediate updated event that Laravel fires internally during the restore operation is automatically suppressed so you do not see a spurious deleted_at change in the log.


Many-to-Many Relationships

Changes to BelongsToMany pivot tables are not recorded by default — pivot operations (attach, detach, sync, updateExistingPivot) bypass Eloquent's standard model events and would otherwise go untracked.

The Auditable trait intercepts these operations transparently through a custom relation class. Opt in per model by declaring an $auditRelationships array with the names of the relationships you want to track.

Opting in

No other changes are needed. All four pivot operations are now automatically logged for the permissions relationship:

Operation Action recorded old_values new_values
attach($ids) update null ['permissions' => [1, 2]]
detach($ids) update ['permissions' => [1, 2]] null
sync($ids) update × 2 detach entry + attach entry (see above)
updateExistingPivot($id, $attrs) update null ['permissions' => [1]]

sync() produces two log entries when IDs change — one for the detached IDs and one for the newly attached IDs. When the synced set is identical to the current set, no entries are written.

What it looks like

Multiple relationships

List every relationship you want audited:

Relationships not in the list are silently skipped even if attach() or detach() is called on them.

Suppressing pivot logs

withoutAudit() suppresses pivot log entries for the model class in the same way it suppresses create/update/delete entries:


The AuditAction Enum

Williamug\Audited\Enums\AuditAction provides a standard set of actions that covers most applications. Each case has a label() method for display text and a badgeColor() method for Tailwind CSS badge classes.

Use these directly in Blade views to render consistent action badges:


Querying Audit Logs

The old_values and new_values columns are automatically cast to arrays. You can query AuditLog directly or use the named scopes described below.

Query Scopes

All scopes are chainable and work with any other Eloquent query methods.

Scope Description
forUser($user) Filter by a User model instance or a raw user ID integer
forModule(string $module) Filter by module name
withAction(AuditAction\|string $action) Filter by action — accepts the enum or a plain string
between($from, $to) Filter by created_at date range — accepts Carbon instances, strings, or timestamps
forSubject(Model $subject) Filter by a specific Eloquent model instance

Subject Relationship

Every log entry written by the Auditable trait stores a polymorphic link back to the model that was acted on (subject_type and subject_id columns). This link is also populated when you pass subject: to ActivityLogService::log() manually.

Querying from the model:

Resolving the subject from a log entry:

Existing apps: see Upgrading existing installs for the migration that adds all new columns at once.


Audit Trail Viewer

The package ships with two ready-made viewer components:


Global Audit Log Table

A full-featured, live-filtered table for an audit log admin page. Drop one tag and it works:

That single tag renders:

Requires Livewire 3 or 4. The component is only registered when Livewire is detected — no error if it is absent.


Per-model Timeline

A chronological history viewer scoped to one record. Drop it on any show/detail page:

A timeline is a vertical list of events ordered by time, connected by a line. Each entry shows the action badge, the module, what changed, who did it, and when.

Blade component

Prop Type Default Description
subject Model required The Eloquent model whose history to display
limit int 25 Maximum number of entries to show
show-values bool false Render a before/after diff table for each entry

Each rendered entry includes:

Livewire component (live pagination)

If your application uses Livewire 3 or 4, a live-paginated version is available:

Prop Type Default Description
subject Model required The Eloquent model whose history to display
per-page int 10 Entries per page
show-values bool false Render a before/after diff table for each entry

Livewire is an optional dependency — the component is only registered when Livewire is detected. No error is thrown if Livewire is not installed.

Tailwind CSS setup

The package views use Tailwind CSS utility classes. In production, Tailwind's content scanner only looks at your application files — vendor/ is excluded by default. Add the package view path to your Tailwind config so the classes are never purged.

Tailwind v3 (tailwind.config.js):

Tailwind v4 (resources/css/app.css):

Without this, the audit views will render with no styling in any environment where Tailwind's output is built (staging, production, or any Vite/Mix build step).


Customising styles with CSS

Every meaningful element in the package views has a semantic audited-* CSS class alongside the Tailwind utilities. You can target these with plain CSS in your own stylesheet — no need to publish the views.

Timeline components (<x-audited::timeline> and <livewire:audited.timeline>):

Class Element
audited-timeline Outer wrapper
audited-timeline-entry Each <li> entry
audited-timeline-connector Vertical connecting line
audited-timeline-dot Circle dot for each entry
audited-action-badge Action badge (Create, Update, etc.)
audited-module-label Module chip
audited-timeline-description Description text
audited-timeline-actor Actor/user name line
audited-causer-badge Causer-type badge (job, command, etc.)
audited-values-diff Before/after diff table wrapper
audited-values-diff-field Field name cell
audited-values-diff-before Old value cell
audited-values-diff-after New value cell
audited-timestamp <time> element

Log table (<livewire:audited.log-table>):

Class Element
audited-log-table Outer wrapper
audited-log-table-filters Filters card
audited-log-table-search Search input
audited-log-table-select Filter dropdowns
audited-log-table-date Date range inputs
audited-log-table-clear Clear Filters button
audited-log-table-row Each table row
audited-log-table-row--expanded Modifier on an expanded row
audited-log-table-detail Expanded detail <tr>
audited-log-table-detail-context Request context section inside detail row
audited-log-table-detail-tags Tags section inside detail row
audited-log-table-toggle View/Close toggle button
audited-action-badge Action badge
audited-causer-badge Causer-type badge
audited-platform-badge Platform badge
audited-platform-badge--web Web platform variant
audited-platform-badge--mobile Mobile platform variant
audited-platform-badge--cli CLI platform variant
audited-values-diff Before/after diff table wrapper
audited-values-diff-field Field name cell
audited-values-diff-before Old value cell
audited-values-diff-after New value cell

Example — brand the action badge with your own colours:

No view publishing required.


Publishing and fully overriding the views

For deeper structural changes, publish and edit:

Published views live in resources/views/vendor/audited/ and are never overwritten by package updates.


Vue and Inertia

The package ships two Vue 3 components — AuditLogTable.vue and AuditTimeline.vue — that mirror the Livewire components exactly. They work in two modes automatically detected at runtime:

Mode When to use How data flows
Self-fetch Standalone Vue SPA, or any page where you don't want to write a controller Component fetches JSON from the built-in API routes
Props / Inertia Inertia apps — data comes from your controller Pass a paginator as props; component emits events for filter changes

Step 1 — Publish the Vue components

Files are copied to resources/js/vendor/audited/. Edit them freely — they follow the same audited-* CSS class conventions as the Blade/Livewire views.

Step 2 — Enable the API routes (self-fetch mode only)

Skip this step if you are using Inertia props mode.

The routes are registered with ['web', 'auth'] middleware by default. Override in config/audit.php:

Self-fetch mode (standalone Vue / SPA)

Drop a component in and it works — no controller needed:

Props / Inertia mode

Use the ServesAuditLogs trait to build the controller with one line:

The props passed to the page match what the Vue components expect (logs, allActions, allModules, allLevels, filters).

In the Vue page component, listen to filter-change and call Inertia's router.get():

For the timeline in props mode:

Component props reference

AuditLogTable.vue

Prop Type Default Description
logs Object\|null null Paginator from auditLogProps(). If null → self-fetch mode
allActions Array [] Action filter options
allModules Array [] Module filter options
allLevels Array [] Level filter options
filters Object {} Initial filter values (Inertia mode)
endpoint String /audited/api/logs API endpoint (self-fetch mode)

Events: filter-change(filters), page-change(url)

AuditTimeline.vue

Prop Type Default Description
logs Object\|Array\|null null Paginator or array from auditTimelineProps(). If null → self-fetch mode
subjectType String null Eloquent model class (self-fetch mode)
subjectId String\|Number null Model primary key (self-fetch mode)
endpoint String /audited/api/timeline API endpoint (self-fetch mode)
showValues Boolean false Show before/after diff table
perPage Number 10 Entries per page (self-fetch mode)

Events: page-change(url)


Extending the AuditLog Model

If your application needs additional relationships or extra columns, extend the package's base model.

Step 1 — Create your extended model

Step 2 — Point the config to your model

Step 3 — Add extra columns in a separate migration

Create a new migration in your application (do not modify the package migration):


Multitenancy

The package supports single-database multitenancy with multiple branches out of the box. The column names are entirely up to your application — company_id, tenant_id, business_id, facility_id, branch_id — whatever your data model uses.

There are two sides to multitenancy: writing (stamping the tenant onto each log entry) and reading (ensuring each tenant only queries their own logs). Both are handled on your custom model.

Stamping Tenant Context on Every Log Entry

Override extraColumns() on your custom model. The package calls this method on every write and merges the returned array into the log entry automatically.

Add the corresponding columns in a migration:

Every log entry — whether written automatically by the Auditable trait, by auth event listeners, or by a manual ActivityLogService::log() call — will now include the current user's company_id and branch_id.

Scoping Queries per Tenant

Add a global scope to your custom model so tenant A can never read tenant B's logs:

Branch-level Isolation

Make the scope conditional — head-office users see all branches while branch users see only their own:

Full Example


Queue / Async Logging

By default, audit log entries are written synchronously on every model event. In high-traffic applications this adds a small database write to every request. You can move all writes to a background queue with a single config change:

Or via your .env file:

When queued, a WriteAuditLog job is dispatched instead of writing directly. No call sites change — the public API is identical. Make sure your queue worker is running:

To return to synchronous writes, set 'queue' => false (the default).


Silent Failures

By default, a failed audit log write (connection error, missing table, constraint violation) throws an exception and surfaces to the caller. In production you may prefer that audit logging never crashes a real user request:

Or via .env:

When enabled, exceptions from log writes are caught, logged to Laravel's default logger at error level, and then silently discarded. The rest of the request continues normally.


Request Context

Every log entry automatically captures full context about the request it came from. No configuration required.

Column Web request API request CLI command
platform web mobile cli
ip_address Client IP Client IP null
user_agent Browser UA string Client UA string null
url Full URL with query string Full URL null
http_method GET, POST, PUT, … GET, POST, PUT, … null
route_name Named route or null Named route or null null
auth_guard web, api, admin, … web, api, admin, … Guard name or null
request_id UUID (same for all logs in the request) UUID UUID (per command invocation)

Request ID

A single HTTP request often triggers multiple audit log entries — a model update, a manual ActivityLogService::log() call, an observer firing. By default these entries look unrelated in the log table.

The request_id UUID is generated once per request using Laravel's scoped() container binding, which resets automatically between requests in long-running processes like Octane. All log entries from the same request share the same UUID:

URL and HTTP method

Route name

The named route is more stable than the URL path — routes are renamed less often than URLs change. Use it to group logs by feature:

Auth guard

In applications with multiple authentication guards (e.g. web for the admin panel, api for the mobile app), the guard column tells you which path the user came through:

Upgrading existing installs

If you are upgrading from an earlier version, add all new columns with a single migration:


Pruning Old Logs

The audit:prune command deletes log entries older than the configured retention period.

The command is automatically scheduled quarterly by the package's service provider. You do not need to add it to your application's schedule.

To disable automatic pruning, set prune_after_months to null in the config:

When prune_after_months is null and no --months flag is passed, the command warns and exits without deleting anything.


Advanced Configuration

Custom User Fields

By default the package reads name from the authenticated user as the display name, and does not record a user level. Change these to match your User model:

Custom Login Credential Field

Applications that identify users by phone number or username rather than email should configure this field so that failed login entries contain the correct identifier:

Sensitive Fields

Extend the default list of fields that are stripped before writing old_values and new_values:

Per-model exclusions can also be declared with $auditExclude on the model (see Excluding Fields from Logs).

Custom Table Name

If audit_logs conflicts with an existing table in your application, change the name before running the migration:


Real-World Example

The following shows a complete integration in a billing module. This is the full picture — model, controller action, background job, and audit history page. The only additions to your existing code are the trait, the causer, and one component tag.

The model

Every create, update, delete, restore, and forceDelete on Invoice is now automatically recorded. Nothing else is required for that coverage.

A controller action

A background job

The audit history page

That is the entire integration. The controller has no audit-specific wiring beyond the one manual log() call. The view has no query, no loop, no formatting logic. The background job identifies itself as a system actor with one line.


Testing

When writing tests that involve audit logging, use RefreshDatabase and assert against the audit_logs table directly.

To suppress audit logging during unrelated tests that create models, use withoutAudit() instead of Model::withoutEvents() — it only suppresses audit writes and leaves other observers intact:

To test queued logging, use Queue::fake():


License

The MIT License. See LICENSE for details.


All versions of audited with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
illuminate/support Version ^10.0|^11.0|^12.0|^13.0
illuminate/database Version ^10.0|^11.0|^12.0|^13.0
illuminate/auth Version ^10.0|^11.0|^12.0|^13.0
illuminate/bus Version ^10.0|^11.0|^12.0|^13.0
illuminate/console Version ^10.0|^11.0|^12.0|^13.0
illuminate/http Version ^10.0|^11.0|^12.0|^13.0
illuminate/queue Version ^10.0|^11.0|^12.0|^13.0
illuminate/routing Version ^10.0|^11.0|^12.0|^13.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package williamug/audited contains the following files

Loading the files please wait ...