bernskiold/laravel-activatable
A Laravel package that adds activatable behavior to Eloquent models. Easily activate or deactivate records, query only active or inactive entries with built-in scopes, and keep model status handling clean and consistent across your application.
Install the package via Composer and check the README's quick-start before anything else — for a 1.0.0 with only a changelog link, the README and src/ are your only real documentation.
composer require bernskiold/laravel-activatable
If the package ships a config and migration (typical for activation-style packages that persist an activated_at / is_active column), publish and run them:
php artisan vendor:publish --tag="activatable-config"
php artisan vendor:publish --tag="activatable-migrations"
php artisan migrate
Then add the trait to any model that needs an on/off lifecycle:
use Bernskiold\Activatable\Concerns\Activatable;
class Account extends Model
{
use Activatable;
}
First use case: gate access without deleting rows. Instead of soft-deleting a user or team, deactivate it — the record survives for auditing, relations stay intact, and reactivation is a single call. Start by verifying the trait's public API in src/Concerns/Activatable.php (method names, scope names, event names) since these are the surface you'll build on.
Query scoping. Use the package's active scope as your default read path rather than filtering in PHP. Wrap it in a local scope or repository method so call sites don't depend on the package's exact scope name:
public function scopeVisible(Builder $q): Builder
{
return $q->active(); // whatever the trait exposes
}
Route gating. Pair activation with a small middleware that rejects requests from deactivated principals. Keep it separate from auth so you can distinguish "not logged in" (401) from "deactivated" (403) — clients care about the difference.
Authorization vs. activation. Activation is a lifecycle flag, not a permission. Enforce it in a Gate::before or policy check in addition to your role logic, not instead of it. Models that are deactivated should fail closed everywhere.
Scheduled lifecycle. If the package supports timestamp-based activation, drive transitions from a scheduled command (php artisan schedule:run) rather than at read time. Read-time checks make list queries unpredictable and unindexable.
Admin toggles. Expose activate/deactivate as explicit actions in Filament/Nova rather than a boolean form field — you get an audit trail and avoid a raw is_active update bypassing the package's events.
Events as integration points. Listen for the activation/deactivation events to invalidate caches, revoke tokens, notify the account owner, or kick off cleanup jobs. This is the cleanest way to add behavior without forking the package.
Factory states. Add ->inactive() / ->active() states to factories immediately; nearly every test will need one.
all() and get() calls.find() lookups too. Use withoutGlobalScope(...) deliberately and document where you do.$this->user->isActive() or a fresh query) rather than trusting the serialized model.is_active column means a stray $request->all() in an update can activate or deactivate anyone. Keep it out of $fillable and flip it only through the package's methods.saved or updated observers, you'll get duplicate side effects on transitions. Pick one layer.src/ as the spec. Method names, the nullable-vs-boolean storage choice, and whether scopes are global are the three details that most affect how this integrates, and none are documented in the 1.0.0 notes.How can I help you explore Laravel packages today?