A Laravel package that provides user auditing capabilities for your database tables and Eloquent models. Easily track which users create, update, and delete records in your application.
- 🕵️ User Auditing: Automatically track
created_by,updated_by, anddeleted_by - 🔧 Flexible Macros: Schema macros for easy migration creation
- 🎯 Multiple Key Types: Support for ID, UUID, and ULID
- 🏷️ Relationships: Built-in relationships to user models
- 📊 Query Scopes: Easy filtering by user actions
- 🎭 Custom Events: Track any business event with dynamic
EventAuditabletrait - ⚡ Zero Configuration: Works out of the box
- PHP 8.1 or higher
- Laravel 9.0 or higher
Laravel 9 notice: Laravel 9 reached End of Life in February 2024 and carries known security advisories. This package declares compatibility with Laravel 9 but CI tests for that version may fail due to Composer blocking EOL packages. Use Laravel 9 at your own risk.
composer require ernestoch/user-auditable-for-laravelPublish the configuration file (optional):
php artisan vendor:publish --tag=user-auditable-configNote:
fullAuditable()requiresuser_auditableto also be listed inenabled_macros. If you disableuser_auditablein the published config, registeringfull_auditablewill throw aRuntimeExceptionat boot time.
Use the provided macros in your migrations:
// Basic usage with default values
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->fullAuditable(); // Adds timestamps, soft deletes, and user auditing
});
// Custom user table and UUID key type
Schema::create('products', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('name');
$table->fullAuditable('admins', 'uuid');
});
// Only user auditing columns (no timestamps or soft deletes)
Schema::create('settings', function (Blueprint $table) {
$table->string('key')->primary();
$table->text('value');
$table->userAuditable('users', 'ulid');
});Use eventAuditable() to stamp any custom business event with its own _at timestamp
and/or _by user FK, reading user_table and key_type from config('user-auditable.defaults'):
// Both columns: released_at (timestamp) + released_by (FK to users)
Schema::table('products', function (Blueprint $table) {
$table->eventAuditable('released');
});
// Timestamp only: approved_at
Schema::table('orders', function (Blueprint $table) {
$table->eventAuditable('approved', 'at');
});
// FK only: archived_by
Schema::table('posts', function (Blueprint $table) {
$table->eventAuditable('archived', 'by');
});All creation macros have corresponding drop macros for clean rollbacks:
// Reverse fullAuditable()
Schema::table('posts', function (Blueprint $table) {
$table->dropFullAuditable(); // Drops timestamps, soft deletes, and audit columns
});
// Reverse userAuditable()
Schema::table('settings', function (Blueprint $table) {
$table->dropUserAuditable(); // Drops audit columns only
});
// Reverse uuidColumn()
Schema::table('products', function (Blueprint $table) {
$table->dropUuidColumn();
// or with custom column name:
// $table->dropUuidColumn('product_uuid');
});
// Reverse ulidColumn()
Schema::table('orders', function (Blueprint $table) {
$table->dropUlidColumn();
// or with custom column name:
// $table->dropUlidColumn('order_ulid');
});
// Reverse statusColumn()
Schema::table('users', function (Blueprint $table) {
$table->dropStatusColumn();
// or with custom column name:
// $table->dropStatusColumn('user_status');
});
// Reverse eventAuditable()
Schema::table('products', function (Blueprint $table) {
$table->dropEventAuditable('released'); // Both columns
$table->dropEventAuditable('released', 'by'); // Only released_by
$table->dropEventAuditable('released', 'at'); // Only approved_at
});Use the UserAuditable trait in your Eloquent models:
<?php
namespace App\Models;
use ErnestoCh\UserAuditable\Traits\UserAuditable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model
{
use SoftDeletes, UserAuditable;
protected $fillable = [
'title',
'content',
'created_by',
'updated_by',
'deleted_by'
];
}Use the EventAuditable trait for dynamic access to custom events:
<?php
namespace App\Models;
use ErnestoCh\UserAuditable\Traits\EventAuditable;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use EventAuditable;
protected $fillable = [
'name',
'released_by',
'released_at',
'approved_by',
'approved_at'
];
}The traits automatically provide relationships:
$post = Post::first();
// Get the user who created the post
$creator = $post->creator;
// Get the user who updated the post
$updater = $post->updater;
// Get the user who deleted the post (if using soft deletes)
$deleter = $post->deleter;With EventAuditable trait, access relationships dynamically for any event:
$product = Product::first();
// Get user who released the product
$releasedBy = $product->releasedBy(); // BelongsTo User
// Get user who approved the product
$approvedBy = $product->approvedBy(); // BelongsTo User
// Works for any event defined via eventAuditable() macro
$archivedBy = $product->archivedBy();Filter records by user actions:
// Get all posts created by user with ID 1
$posts = Post::createdBy(1)->get();
// Get all posts updated by user with ID 2
$posts = Post::updatedBy(2)->get();
// Get all posts deleted by user with ID 3
$posts = Post::deletedBy(3)->get();With EventAuditable trait, filter by any event user dynamically:
// Get products released by user with ID 5
$released = Product::releasedBy(5)->get();
// Get products approved by user with ID 10
$approved = Product::approvedBy(10)->get();
// Works for any event defined via eventAuditable() macro
$archived = Product::archivedBy(8)->get();| Macro | Description | Parameters |
|---|---|---|
| userAuditable() | Adds user auditing columns | ?string $userTable = null, ?string $keyType = null |
| dropUserAuditable() | Removes user auditing columns | bool $dropForeign = true |
| fullAuditable() | Adds timestamps, soft deletes, and user auditing | ?string $userTable = null, ?string $keyType = null |
| dropFullAuditable() | Removes timestamps, soft deletes, and user auditing | bool $dropForeign = true |
| uuidColumn() | Adds UUID column | string $columnName = 'uuid' |
| dropUuidColumn() | Removes UUID column | string $columnName = 'uuid' |
| ulidColumn() | Adds ULID column | string $columnName = 'ulid' |
| dropUlidColumn() | Removes ULID column | string $columnName = 'ulid' |
| statusColumn() | Adds status enum column | string $columnName = 'status', array $allowed = ['active','inactive','pending'], string $default = 'active' |
| dropStatusColumn() | Removes status column | string $columnName = 'status' |
| eventAuditable() | Adds a custom event timestamp and/or user FK | string $event, ?string $column = null |
| dropEventAuditable() | Removes custom event columns | string $event, ?string $column = null, bool $dropForeign = true |
A .env.testing.example file is included in the repository as a reference. Copy it and fill in your local values:
# Linux / macOS
cp .env.testing.example .env.testing
# Windows
copy .env.testing.example .env.testing
⚠️ Never commit.env.testingto the repository. It is already listed in.gitignore.
Set the following environment variables and fill in your values in the .env.testing file:
TEST_DB_HOST=127.0.0.1
TEST_DB_PORT=3306
TEST_DB_DATABASE=test_database
TEST_DB_USERNAME=root
TEST_DB_PASSWORD=your-local-mysql-password-hereThen set DB_CONNECTION in your terminal session:
# Linux / macOS
export DB_CONNECTION=mysql
# Windows
set DB_CONNECTION=mysqlNo additional configuration is needed. SQLite in-memory is the default driver used by phpunit.xml.
# Linux / macOS
./vendor/bin/phpunit
# Windows
vendor\bin\phpunitPlease see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
If you discover any security related issues, please email ernestochapon@gmail.com instead of using the issue tracker.
Author: Ernesto Chapon.
All contributors (
The MIT License (MIT). Please see License File for more information.