ibrand/laravel-active
Laravel package for managing active/inactive status on Eloquent models. Adds an activation flag with query scopes, toggle helpers, and filters so you can quickly enable, disable, or query only active records for products, users, categories, and similar entities.
Architecture fit. ibrand/laravel-active is a micro-package that implements the well-known "active flag" pattern: a boolean (is_active or similar) column, a model trait providing activate()/deactivate() helpers, and a global scope that transparently filters inactive rows from queries. Architecturally this is a decorator on Eloquent, not a platform component. It introduces no new infrastructure, no service provider surface beyond a trait and possibly a migration stub, and no runtime dependencies beyond Laravel's Eloquent. That means fit is easy to assess: it fits any Laravel application that has soft state on domain entities (catalogs, CMS content, feature flags per tenant, user accounts, promotions) and has no fit in event-sourced, CQRS, or multi-warehouse architectures where visibility is a query-time concern owned by a read model rather than a model-level scope.
Integration feasibility. Mechanically trivial — composer require ibrand/laravel-active, import the trait on a model, add the column. The real feasibility question is not "can we install it" but "should we install it." With 3 stars and 0 dependents, there is no ecosystem signal that the package's semantics have been battle-tested across Laravel versions. Before any commitment I would need to read the source end-to-end (likely <200 LOC) to confirm: which Laravel/PHP versions the composer.json allows, whether the global scope is applied in boot vs. a base model, whether it respects withoutGlobalScope(), and whether activate()/deactivate() fire model events or write directly via query builder (the latter would bypass observers, cache invalidation, and audit logging).
Technical risk. The blast radius is unusually favorable for a third-party dependency: because the package is a thin trait, the cost of removal is a find-and-replace plus a 30–50 line in-house reimplementation. That said, the risks are real and specific:
joined tables or withCount subqueries; the behavior of count(), exists(), and relationship existence queries needs explicit verification.is_active alone is a poor index; on large tables the optimizer will ignore it unless combined into a composite.Key questions for the maintainer / source review:
SoftDeletes, HasUuids, or existing global scopes?whereHas?activate/deactivate event-firing and mass-assignment safe?is_active configurable per model, or hard-coded to a column name?Stack fit. Best suited to a conventional Laravel monolith or a Laravel API service with a relational database, where entities have a binary publish/enable state. It is a poor fit for multi-tenant SaaS where "active" differs per tenant (you need per-tenant scoping, not a global boolean) and for anything where deactivation is a lifecycle event requiring audit trails — in that case you want an explicit status enum plus domain events, not a boolean flag.
Migration path. My recommendation as TPM: do not take a runtime dependency on this package. Vendor the source (copy the trait into app/Models/Concerns/) or reimplement it. The rationale is asymmetric risk: the package saves perhaps half a day of engineering, but introduces an unmaintained supply-chain artifact and a global-scope behavior you must own anyway. If the team insists on Composer-managed code for consistency, use a VCS fork under the org's namespace so upgrades and patches are controlled.
If adoption proceeds, the schema migration should be additive and reversible: add the column with a default of false (or true for backfill correctness), backfill, then enable the trait on models in a separate deploy. Never combine the schema change and the scope enablement in one release.
Compatibility. Verify against the pinned Laravel and PHP versions in each service's composer.json before anything else. If the package's constraint is ^8.0|^9.0 and the fleet is on Laravel 11, the decision is made for you. Also check whether it depends on illuminate/support at a version that would force a framework downgrade — that is disqualifying.
Sequencing.
where is_active predicate, and what the query plan looks like with and without a composite index.withoutGlobalScope, admin queries, reporting jobs, and artisan commands can all see inactive rows deliberately. Document the escape hatch in the team wiki.Maintenance. Assume you own the code from day one. Budget: near-zero ongoing effort if vendored (it is dormant code), but a real tail risk at each Laravel major upgrade, where a global scope's interaction with query builder changes must be re-validated. If adopted via Composer, assign explicit ownership — otherwise no one notices when it breaks.
Support. There is no community to escalate to. 3 stars and 0 dependents means no Stack Overflow corpus, no GitHub issue history to mine, and no third-party blog posts describing edge cases. Every question becomes an internal investigation. This is the dominant operational cost and it is entirely front-loaded.
Scaling. Negligible CPU, but two concrete database concerns:
(tenant_id, is_active, created_at)) so the scope predicate is satisfied by an index prefix.Failure modes to design against:
withoutGlobalScope explicitly and render an "inactive" badge.deactivate() fires model events wired to cache invalidation; if it writes via the query builder, it will not.update(['is_active' => false]) bypasses the trait entirely and leaves no event trail. Mitigation: enforce through a service layer, not ad-hoc updates.whereHas on an inactive parent returns nothing, which may silently break authorization checks that resolve permissions through related active records.Ramp-up. For an engineer already fluent in Eloquent, adoption is under a day: read the trait, add the column, add the trait to a model, verify. The hidden ramp-up cost is conceptual, not mechanical — new engineers must learn that a global scope is silently rewriting their queries, and that knowledge is tribal unless documented. A short ADR (architecture decision record) plus a wiki page listing which models carry the trait, and the sanctioned way to bypass it, is worth more than the package itself. Given the tiny surface area, the strongest TPM recommendation is to treat this repository as a reference implementation to copy, not a dependency to adopt — capture the pattern, own the twelve lines of code, and keep the supply chain clean.
How can I help you explore Laravel packages today?