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 Model Flags Laravel Package

spatie/laravel-model-flags

Add lightweight “flags” to Eloquent models via a trait—store process state without extra columns. Check, set, and clear flags, and query with flagged/notFlagged scopes. Ideal for idempotent, restartable jobs like one-time emails or migrations.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:
    composer require spatie/laravel-model-flags
    
  2. Publish migrations and run them:
    php artisan vendor:publish --tag="model-flags-migrations"
    php artisan migrate
    
  3. Use the trait in your model:
    use Spatie\ModelFlags\Models\Concerns\HasFlags;
    
    class User extends Model
    {
        use HasFlags;
    }
    

First Use Case: Idempotent Operations

// Flag a user as having received a notification
$user->flag('received_notification');

// Check if a user has the flag
if (!$user->hasFlag('received_notification')) {
    // Send notification
    $user->flag('received_notification');
}

Implementation Patterns

Common Workflows

1. Flagging and Checking

// Set a flag
$user->flag('processed');

// Check existence
if ($user->hasFlag('processed')) {
    // Do something
}

// Remove a flag
$user->unflag('processed');

2. Batch Operations with Scopes

// Process only unflagged users
User::notFlagged('processed')
    ->chunk(100, function ($users) {
        foreach ($users as $user) {
            // Process user
            $user->flag('processed');
        }
    });

3. Tracking Timestamps

// Get when a flag was last set
$lastProcessedAt = $user->lastFlaggedAt('processed');

// Get the most recent flag timestamp
$lastActivityAt = $user->lastFlaggedAt();

4. Enum Support (v1.4.0+)

use Spatie\ModelFlags\Enums\FlagName;

class User extends Model
{
    use HasFlags;

    protected string $flagNameEnum = FlagName::class;
}

enum FlagName: string
{
    case PROCESSED = 'processed';
    case NOTIFIED = 'notified';
}

// Usage
$user->flag(FlagName::PROCESSED);

5. Mass Flag Removal

// Remove a flag from all models
Flag::where('name', 'old_flag')->delete();

Integration Tips

With Artisan Commands

// Idempotent command example
User::notFlagged('sent_email')
    ->each(function (User $user) {
        Mail::to($user)->send(new WelcomeEmail());
        $user->flag('sent_email');
    });

With Events

// Flag on event trigger
event(new UserRegistered($user));
$user->flag('registered_via_event');

With Observers

// Auto-flag on model creation
public function created(Model $model)
{
    $model->flag('created_via_observer');
}

Gotchas and Tips

Pitfalls

  1. Missing Migration:

    • Forgetting to run php artisan migrate after publishing migrations will cause ModelNotFoundException.
  2. Flag Name Collisions:

    • Ensure flag names are unique across your application to avoid unintended behavior.
  3. Performance with Large Datasets:

    • Scopes like flagged() or notFlagged() can be slow on large tables. Consider adding database indexes:
      Schema::table('flags', function (Blueprint $table) {
          $table->index(['model_type', 'model_id', 'name']);
      });
      
  4. Model Deletion:

    • Flags are not automatically deleted when the parent model is deleted (fixed in v1.1.0+). Use $model->flags()->delete() if needed.
  5. Enum Validation:

    • When using enums, ensure the enum class is properly defined and accessible to the trait.

Debugging Tips

  1. Check Flag Existence:

    dd($user->flags); // Inspect all flags
    dd($user->flagNames()); // Get flag names as array
    
  2. Query Debugging:

    // Debug scope queries
    User::notFlagged('test')->toSql();
    
  3. Timestamp Issues:

    • If lastFlaggedAt() returns unexpected values, verify the flags table's updated_at column is properly populated.

Extension Points

  1. Custom Flag Model:

    • Override the default Flag model by publishing the config:
      php artisan vendor:publish --tag="model-flags-config"
      
    • Then update config/model-flags.php:
      'flag_model' => App\Models\CustomFlag::class,
      
  2. Custom Flag Storage:

    • Extend the Flag model to add custom logic (e.g., soft deletes, additional metadata).
  3. Bulk Operations:

    • Use flags()->delete() for bulk flag removal:
      $user->flags()->where('name', 'temp_flag')->delete();
      
  4. Array Unflagging (v1.5.0+):

    // Remove multiple flags at once
    $user->unflag(['flag1', 'flag2', 'flag3']);
    

Advanced Usage

Conditional Flagging

// Flag only if condition is met
if ($user->shouldReceiveNotification()) {
    $user->flag('notification_sent');
}

Flag-Based Authorization

// Policy example
public function viewAny(User $user)
{
    return $user->hasFlag('admin_access');
}

Flag Expiration

// Soft-expiry via timestamp checks
if ($user->lastFlaggedAt('temporary_flag') < now()->subHours(1)) {
    $user->unflag('temporary_flag');
}

Testing Flags

// In tests
$user->flag('test_flag');
$this->assertTrue($user->hasFlag('test_flag'));

// Reset flags
$user->flags()->delete();
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.
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
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai