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

Earmark Laravel Package

poing/earmark

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require poing/earmark
    

    Add the service provider to config/app.php under providers (automatically included if using Laravel 5.5+).

  2. Publish Config:

    php artisan earmark:config
    

    Review config/earmark.php for defaults (e.g., lock_timeout, recycle_after_minutes).

  3. Run Migrations:

    php artisan migrate
    

    Creates the earmarks table with key, value, locked_at, and recycled_at columns.

  4. First Use Case: Reserve a phone extension for a user:

    use Poing\Earmark\Facades\Earmark;
    
    $extension = Earmark::get('phone_extension');
    // Returns next available value (e.g., "1001") and locks it for the session.
    

Implementation Patterns

Core Workflows

  1. Reserving Values:

    • Use Earmark::get($key) to fetch the next available value (e.g., sequential IDs, phone numbers).
    • Locks the value for the current request (configurable timeout via lock_timeout).
    • Example:
      $userId = Earmark::get('user_id'); // Returns "1001" and locks it
      
  2. Recycling Values:

    • Release a value back to the pool when no longer needed:
      Earmark::unset('phone_extension', $extension);
      
    • Values are marked as recycled_at and reused in future requests.
  3. Batch Reservations:

    • Reserve multiple values at once (e.g., for bulk operations):
      $extensions = Earmark::getMultiple(['phone_extension', 'fax_extension'], 2);
      // Returns array of 2 values for each key.
      
  4. Custom Series:

    • Define custom series logic via the series config (e.g., alphanumeric, date-based):
      'series' => [
          'invoice' => function ($current) {
              return 'INV-' . str_pad($current + 1, 6, '0', STR_PAD_LEFT);
          },
      ],
      

Integration Tips

  • Database Transactions: Wrap reservations in transactions to ensure atomicity:

    DB::transaction(function () {
        $extension = Earmark::get('phone_extension');
        // Use $extension in your logic...
    });
    
  • Session Binding: Bind reserved values to the user session for persistence:

    session()->put('phone_extension', $extension);
    
  • Fallback Logic: Handle edge cases (e.g., no values available) with callbacks:

    $value = Earmark::get('key', function () {
        return 'DEFAULT_VALUE';
    });
    
  • Testing: Use Earmark::flush() to reset the table for tests:

    Earmark::flush('phone_extension'); // Clear all values for a key
    

Gotchas and Tips

Pitfalls

  1. Lock Timeouts:

    • Default lock_timeout is 5 minutes. Adjust in config/earmark.php if needed.
    • Long-running processes may cause stale locks. Monitor locked_at timestamps.
  2. Race Conditions:

    • Database locks prevent duplicates, but ensure your application handles timeouts gracefully:
      try {
          $value = Earmark::get('key', 10); // 10-second timeout
      } catch (\Poing\Earmark\Exceptions\LockException $e) {
          // Retry or fallback
      }
      
  3. Recycling Delays:

    • Values recycled via unset() are not immediately reused. Wait for recycle_after_minutes (default: 1 minute) or force a refresh:
      Earmark::refresh('phone_extension');
      
  4. Key Collisions:

    • Ensure keys are unique across your application. Overlapping keys (e.g., user_id and invoice_id) may cause unexpected behavior.

Debugging

  • Check Locks: Query the earmarks table for locked values:

    SELECT * FROM earmarks WHERE locked_at IS NOT NULL;
    

    Manually update locked_at to NULL to release stuck locks.

  • Log Warnings: Enable debug mode in config/earmark.php to log lock failures:

    'debug' => env('APP_DEBUG', false),
    

Extension Points

  1. Custom Storage: Override the default Eloquent model by binding your own:

    Earmark::extend(function ($app) {
        $app->singleton(\Poing\Earmark\Contracts\EarmarkRepository::class, function () {
            return new CustomEarmarkRepository();
        });
    });
    
  2. Event Listeners: Listen for earmark.locked and earmark.unlocked events to trigger side effects:

    Earmark::locked(function ($key, $value) {
        // Log or notify when a value is reserved
    });
    
  3. Series Customization: Extend the series logic for complex patterns (e.g., hierarchical IDs):

    'series' => [
        'ticket' => function ($current, $key) {
            $prefix = explode('_', $key)[0];
            return $prefix . '-' . strtoupper(dechex($current));
        },
    ],
    
  4. Rate Limiting: Combine with Laravel’s rate limiting to prevent abuse:

    RateLimiter::for('earmark')->by(function (Request $request) {
        return $request->user()->id;
    })->allow(10)->perMinute();
    
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.
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
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