ernestoch / user-auditable-for-laravel
Laravel package for user auditing in migrations and models
Package info
github.com/3rn3st0/user-auditable-for-laravel
pkg:composer/ernestoch/user-auditable-for-laravel
Requires
- php: >=8.1
- laravel/framework: >=9.0 <14.0
Requires (Dev)
- nunomaduro/collision: ^6.0|^7.0|^8.0
- orchestra/testbench: ^7.0|^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.5|^11.0|^12.0
README
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.
Features
- 🕵️ 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
Requirements
- 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.
Installation
composer require ernestoch/user-auditable-for-laravel
Configuration
Publish the configuration file (optional):
php artisan vendor:publish --tag=user-auditable-config
Note:
fullAuditable()requiresuser_auditableto also be listed inenabled_macros. If you disableuser_auditablein the published config, registeringfull_auditablewill throw aRuntimeExceptionat boot time.
Usage
Migrations
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'); });
Custom Event Columns
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'); });
Reversing Migrations
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 });
Models
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' ]; }
Relationships
The traits automatically provide relationships:
UserAuditable 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;
EventAuditable Relationships
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();
Query Scopes
UserAuditable Scopes
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();
EventAuditable Scopes
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();
Available Macros
| 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 |
Testing
Setup
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.
Running with MySQL
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-here
Then set DB_CONNECTION in your terminal session:
# Linux / macOS export DB_CONNECTION=mysql # Windows set DB_CONNECTION=mysql
Running with SQLite (default)
No additional configuration is needed. SQLite in-memory is the default driver used by phpunit.xml.
# Linux / macOS ./vendor/bin/phpunit # Windows vendor\bin\phpunit
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security related issues, please email ernestochapon@gmail.com instead of using the issue tracker.
Credits
Author: Ernesto Chapon.
All contributors (⚠️ Not available yet).
License
The MIT License (MIT). Please see License File for more information.