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 Status Laravel Package

open-southeners/laravel-model-status

Lightweight Laravel model status handling using native PHP enums—no extra tables needed. Define a status enum, attach it via a PHP attribute, and use a trait for helpers like setStatus, setStatusWhen, hasStatus, and optional status events.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require open-southeners/laravel-model-status
    

    No additional configuration is required beyond publishing the package (though none is needed by default).

  2. First Use Case: Define a status enum for your model (e.g., PostStatus for a Post model):

    use OpenSoutheners\LaravelModelStatus\ModelStatus;
    
    enum PostStatus: int implements ModelStatus
    {
        case Draft = 1;
        case Published = 2;
        case Archived = 3;
    }
    
    • Key: The enum must implement ModelStatus and use an int (or string) backing type.
  3. Model Integration: Attach the enum to your model via the ModelStatuses attribute and implement Statusable:

    use OpenSoutheners\LaravelModelStatus\Attributes\ModelStatuses;
    use OpenSoutheners\LaravelModelStatus\HasStatuses;
    use OpenSoutheners\LaravelModelStatus\Statusable;
    
    #[ModelStatuses(PostStatus::class)]
    class Post implements Statusable
    {
        use HasStatuses;
    }
    
    • Note: The HasStatuses trait provides all CRUD operations for statuses.
  4. Usage:

    $post = new Post();
    $post->setStatus(PostStatus::Published); // Set status
    $post->getStatus(); // Get current status (returns PostStatus::Published)
    $post->isStatus(PostStatus::Draft); // Check if status matches (returns bool)
    

Implementation Patterns

Common Workflows

  1. Status Transitions: Enforce valid transitions (e.g., Draft → Published but not Published → Draft) by overriding validateStatusTransition in your model:

    protected function validateStatusTransition(?ModelStatus $newStatus): bool
    {
        if ($this->status === PostStatus::Published && $newStatus === PostStatus::Draft) {
            return false;
        }
        return true;
    }
    
  2. Default Status: Set a default status in the model’s constructor:

    public function __construct(array $attributes = [])
    {
        parent::__construct($attributes);
        $this->setStatus(PostStatus::Draft); // Default to Draft
    }
    
  3. Querying by Status: Use the status() scope provided by the trait:

    $publishedPosts = Post::status(PostStatus::Published)->get();
    
  4. Status-Based Logic: Add methods to your model for status-specific behavior:

    public function isPublishable(): bool
    {
        return $this->isStatus(PostStatus::Draft);
    }
    
  5. Serialization: Cast the status to a string or integer for JSON/API responses:

    protected $casts = [
        'status' => 'int', // or 'string' if using string-backed enums
    ];
    

Integration Tips

  • Validation: Use Laravel’s validation rules to restrict status changes in forms:
    $request->validate([
        'status' => 'required|in:' . implode(',', array_column(PostStatus::cases(), 'value')),
    ]);
    
  • Observers: Trigger actions when status changes (e.g., send notifications):
    class PostObserver
    {
        public function saved(Post $post)
        {
            if ($post->wasStatusChanged) {
                // Send email, log activity, etc.
            }
        }
    }
    
  • Policies: Restrict status changes based on user roles:
    public function update(Statusable $model, User $user)
    {
        if (!$user->can('publish_posts') && $model->isStatus(PostStatus::Draft)) {
            abort(403);
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Enum Backing Type:

    • The package expects int or string backing types for enums. Using other types (e.g., float) will cause errors.
    • Fix: Ensure your enum uses int or string:
      enum PostStatus: string implements ModelStatus { ... } // Valid
      
  2. Missing ModelStatus Interface:

    • Forgetting to implement ModelStatus on your enum will throw runtime errors.
    • Fix: Always extend ModelStatus:
      enum PostStatus implements ModelStatus { ... } // Correct
      
  3. Status Not Persisted:

    • The package stores statuses in memory by default. If you need persistence, ensure your model uses a database driver (e.g., use Illuminate\Database\Eloquent\Model).
    • Tip: The package is designed to work without a database, but statuses are tied to the model instance’s lifecycle.
  4. Case-Sensitive Enum Values:

    • If using string-backed enums, ensure case matches exactly when validating or querying.
    • Fix: Use constants for enum values:
      case Published = 'PUBLISHED';
      
  5. Overriding HasStatuses:

    • Blindly overriding methods like getStatusKey() or setStatus() can break functionality.
    • Tip: Extend the trait’s methods carefully or use composition (e.g., add a status() method to your model).

Debugging

  1. Status Not Updating:

    • Check if validateStatusTransition() is returning false. Add logging:
      protected function validateStatusTransition(?ModelStatus $newStatus): bool
      {
          logger()->debug("Attempting transition to: {$newStatus->value}");
          return true; // Temporarily bypass for testing
      }
      
  2. Enum Not Recognized:

    • Verify the ModelStatuses attribute is correctly applied to the model class (not just the file).
    • Fix: Re-run composer dump-autoload if changes aren’t reflected.
  3. Performance with Large Datasets:

    • The status() scope adds a WHERE clause. For large tables, ensure your status column (if using a database) is indexed.
    • Tip: If using in-memory statuses, avoid querying by status in bulk operations.

Extension Points

  1. Custom Status Storage:

    • Override getStatusAttribute() to store statuses in a custom column or cache:
      public function getStatusAttribute(): ?ModelStatus
      {
          return $this->status ?? $this->customStatusColumn;
      }
      
  2. Status Events:

    • Publish the package’s event classes and listen for StatusChanged events:
      use OpenSoutheners\LaravelModelStatus\Events\StatusChanged;
      
      event(new StatusChanged($model, $oldStatus, $newStatus));
      
  3. Multi-Status Support:

    • Extend the package to support multiple status fields by creating a custom trait:
      trait HasMultipleStatuses
      {
          use HasStatuses;
      
          public function setStatus(string $field, ModelStatus $status): static
          {
              $this->{$field} = $status;
              return $this;
          }
      }
      
  4. Localization:

    • Add human-readable labels to enums for localization:
      enum PostStatus implements ModelStatus
      {
          case Draft;
          public function label(): string { return __('status.draft'); }
      }
      
    • Then use PostStatus::Published->label() in views.
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.
nasirkhan/laravel-sharekit
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony