Weave Code
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

Laravel Userstamps Laravel Package

danielemontecchi/laravel-userstamps

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require danielemontecchi/laravel-userstamps
    

    Publish the config (optional):

    php artisan vendor:publish --provider="DanieleMontecchi\Userstamps\UserstampsServiceProvider"
    
  2. Configure Database Macros: Edit config/userstamps.php to define which columns (created_by, updated_by, deleted_by) and their data types (e.g., unsignedBigInteger). Example:

    'columns' => [
        'created_by' => 'unsignedBigInteger',
        'updated_by' => 'unsignedBigInteger',
        'deleted_by' => 'unsignedBigInteger',
    ],
    
  3. Apply to Models: Use the HasUserstamps trait in your Eloquent models:

    use DanieleMontecchi\Userstamps\HasUserstamps;
    
    class Post extends Model
    {
        use HasUserstamps;
    }
    
  4. Run Migrations: Publish and run the migration to add the columns to your tables:

    php artisan vendor:publish --tag="userstamps-migrations"
    php artisan migrate
    

First Use Case

Audit Trail for a Model:

// Automatically sets `created_by` to the authenticated user
$post = Post::create(['title' => 'Hello World']);

// Manually override (e.g., for admin actions)
$post->setCreatedBy(1); // User ID 1
$post->save();

Implementation Patterns

Core Workflows

  1. Automatic Stamping:

    • The trait automatically fills created_by, updated_by, and deleted_by when using create(), save(), or delete().
    • Uses Laravel’s Auth facade to fetch the current user (default: auth()->id()).
  2. Manual Overrides:

    • Explicitly set stamps for non-authenticated actions (e.g., API calls, cron jobs):
      $post->setCreatedBy($userId);
      $post->setUpdatedBy($userId);
      $post->setDeletedBy($userId);
      
  3. Query Scopes:

    • Filter models by user:
      Post::createdBy($userId)->get();
      Post::updatedBy($userId)->get();
      Post::deletedBy($userId)->get();
      
  4. Custom User Resolver:

    • Override the default user resolver in config/userstamps.php:
      'user_resolver' => function () {
          return auth('api')->id() ?? 0; // Fallback to 0 for unauthenticated
      },
      

Integration Tips

  • APIs: Use middleware to set a default user (e.g., API client ID) for unauthenticated requests:

    public function handle($request, Closure $next) {
        if (!$request->user()) {
            $request->setUserResolver(fn() => $request->header('X-Client-ID'));
        }
        return $next($request);
    }
    
  • Commands/Cron Jobs: Pass the user ID explicitly:

    $post = new Post();
    $post->setCreatedBy($cronUserId)->save();
    
  • Soft Deletes: Ensure deleted_by is set when using delete():

    $post->delete(); // Automatically sets `deleted_by`
    
  • Observers/Events: Extend logic in retrieved, saved, or deleted events:

    public function saved(Model $model) {
        if ($model instanceof Post) {
            $model->logActivity("Updated by {$model->updated_by}");
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Migration Conflicts:

    • If the columns already exist in your table, the migration will fail. Either:
      • Skip the migration and manually add the columns.
      • Use Schema::defaultStringLength() if your Laravel version requires it.
  2. User Resolver Edge Cases:

    • If auth()->id() returns null, the column will be set to null. Configure a fallback in user_resolver:
      'user_resolver' => function () {
          return auth()->check() ? auth()->id() : 0; // 0 for "system"
      },
      
  3. Mass Assignment Risks:

    • The trait does not protect against mass assignment. Whitelist the columns in $fillable:
      protected $fillable = ['title', 'created_by', 'updated_by'];
      
  4. Soft Deletes + deleted_by:

    • If using SoftDeletes, ensure deleted_by is not included in $dates:
      protected $dates = ['deleted_at'];
      
  5. Performance:

    • Avoid selecting created_by, updated_by in queries if unused:
      Post::select(['id', 'title'])->get(); // Excludes userstamp columns
      

Debugging

  • Missing Columns: Check if the migration ran and columns exist in the table:

    php artisan migrate:status
    php artisan schema:dump
    
  • User Resolver Not Triggering: Verify the resolver is called by logging it in a model event:

    public static function boot() {
        static::creating(function ($model) {
            \Log::debug('User resolver result:', ['user_id' => app('userstamps')->resolveUser()]);
        });
    }
    
  • Override Not Working: Ensure setCreatedBy() is called before save():

    $post->setCreatedBy(1);
    $post->save(); // Now `created_by` is set
    

Extension Points

  1. Custom Columns: Extend the trait to support additional columns (e.g., created_ip):

    trait HasUserstamps
    {
        public static function bootHasUserstamps()
        {
            static::creating(function ($model) {
                $model->{$model->getCreatedIpColumn()} = request()->ip();
            });
        }
    
        public function getCreatedIpColumn()
        {
            return 'created_ip';
        }
    }
    
  2. Database Macros: Add custom macros to the Userstamps service provider for global query extensions:

    // In UserstampsServiceProvider
    public function boot()
    {
        \DB::macro('userstamped', function () {
            return $this->whereNotNull('created_by');
        });
    }
    

    Usage:

    Post::query()->userstamped()->get();
    
  3. Event Hooks: Dispatch custom events when stamps are updated:

    // In HasUserstamps trait
    public function setUpdatedBy($userId)
    {
        $this->updated_by = $userId;
        event(new UserUpdated($this, $userId));
    }
    
  4. Policy Integration: Use stamps for authorization:

    public function update(User $user, Post $post)
    {
        return $user->id === $post->updated_by;
    }
    
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.
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours