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

exolnet/laravel-status

Exolnet Laravel Status adds flexible, database-backed status management to Laravel Eloquent models. Define available statuses, assign them to records, and track changes through a simple trait, making it easy to model workflows and record state across your application.

View on GitHub
Deep Wiki
Context7

Getting Started

exolnet/laravel-status gives Eloquent models a first-class status field plus the plumbing around it (allowed values, transitions, scopes, and typically a history/audit trail). It is the kind of package you reach for when a status string column starts accumulating if statements in controllers.

Version floor first. As of v2.14.0 the package no longer supports Laravel 11 — you need Laravel 12 (and the PHP version that implies). Before anything else, confirm composer.json:

composer require exolnet/laravel-status:^2.14
composer why-not exolnet/laravel-status ^2.14   # if it refuses to resolve

If you are still on Laravel 11, pin ^2.13 and plan the framework upgrade separately — do not try to mix.

Then:

  1. Publish and run the migrations (the package ships a status/history table in most configurations):
    php artisan vendor:publish --provider="Exolnet\Status\StatusServiceProvider"
    php artisan migrate
    
  2. Publish the config if you need to change table names, the status column, or history behaviour.
  3. Add the package trait to the model that owns the status.
  4. Define your statuses (enum or status classes, depending on your version) — start with three or four real values, not a speculative twenty.

First use case: an Article with draft → review → published → archived. Wire the trait, add the cast, then replace a $article->status = 'published'; $article->save(); with a guarded transition. That single swap is where the package starts paying for itself.

Implementation Patterns

Cast the status, don't compare strings. Whether you use a PHP enum or the package's status class, cast it on the model so $article->status is always a typed object. String comparisons scattered across views and policies are the main source of "why is this row invisible" bugs.

Express transitions as data, not controller logic. Define which statuses may move to which, then funnel writes through a single method/service. Controllers, Filament actions, and Artisan commands should all call the same transition entry point so guards and history stay consistent.

Use scopes for list screens. Article::whereStatus(Status::Published) (or the package scope) keeps filters composable and index-friendly. Combine with withCount/with for admin tables rather than loading statuses per row.

History as an audit trail, not a UI feature. The status history table is your forensic record. Treat it as append-only; never backfill or delete from it in application code. When someone asks "who unpublished this at 3am", that table is the answer.

Gate side effects on the transition, not the save. Notifications, search-index updates, and webhooks belong in an observer or a dedicated listener fired on status change — not in booted() model hooks that also fire on unrelated saves. This keeps bulk operations from spamming Slack.

Test the transitions, not the trait. Your test suite should assert your domain rules (draft cannot jump to archived), not re-verify the package's own behaviour. Use factories with named states (->published()) so fixtures read as intent.

Integration points worth knowing: authorization policies keyed on status (canPublish), scheduled commands that expire content (whereStatus(...)->where('published_at', '<', now())), and API resources that expose a status string plus a can_transition_to map so the frontend doesn't hardcode the state machine.

Gotchas and Tips

The Laravel 11 drop is the headline. v2.14.0 removes Laravel 11 support and bumps dependencies. Consequences to check before upgrading:

  • Your composer.lock must move to Laravel 12 first or resolution will fail confusingly.
  • Transitive constraints matter: a package still pinning illuminate/support ^11 will block the upgrade even though it has nothing to do with statuses. Run composer why-not laravel/framework ^12 to find the real culprit.
  • Update your CI matrix in the same PR — a green build on Laravel 11 tells you nothing about v2.14.
  • Read the composer.json diff of the release, not just the changelog. "Update dependencies" often hides a PHP minor-version bump or a major in a support library.

Refresh after transition. Status guards frequently read the in-memory model. After a transition that writes through a query builder or a service, call $model->refresh() before branching on $model->status, or you will act on a stale value.

Mass assignment. Keep the status column out of $fillable unless you genuinely want it settable from request payloads. Status should change through transitions, not Article::create($request->all()).

Migration publishing collisions. If you published the migrations under an older version and later publish again, you can end up with two migration files touching the same table. Check database/migrations for duplicates and diff against the package stub before running in production.

Config caching. Changes to the published config require php artisan config:clear in local dev and a cache rebuild on deploy. Status definitions read from config at boot are a classic "works locally, wrong in staging" trap.

N+1 on history. Rendering a timeline for a list of models will fire one query per row. Eager-load the history relation, or paginate the timeline separately with a dedicated endpoint.

Extension points. When the built-in transitions aren't enough, prefer subclassing the status class or registering a custom guard over editing vendor files — and keep a note of which methods you override, because a minor release can change the surrounding flow.

Debugging. Enable query logging and look at the actual UPDATE plus the history insert. Most "the status didn't change" reports are a failed guard swallowing an exception, or a transaction rolled back around the side effect rather than the status write.

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin