cybercog/laravel-eloquent-flag
Add boolean flags to any Eloquent model with cybercog/laravel-eloquent-flag. Mark records as flagged, unflag or toggle them, and query flagged or unflagged rows using clean, expressive methods and local scopes—no extra boilerplate needed.
isX() check, a publish()/unpublish() mutator, and a query scope that hides inactive rows. This package collapses that into use HasPublishedFlag; — roughly 4 files and a test suite per flag you don't write. Decision: standardize on the package instead of a homegrown HasStatus trait, unless your flags need cross-entity logic.Kept). If a roadmap item is "let editors unpublish without deleting," this is a same-day feature, not a sprint.published_at, expired_at) give you scheduling and expiry for free and remain queryable. Push engineering to default to timestamp flags for anything user-facing where "when did this happen" will eventually be asked in a report.shouldApplyXxxScope(): bool. That makes "safe by default" vs. "explicit opt-in" a deliberate, per-model product decision rather than a framework accident — useful when admin tooling must see all rows while the public API must not.Adopt when:
published, publishedUndone) across features so listeners, notifications, and search indexing hook in predictably.Look elsewhere when:
spatie/laravel-model-states; stacking both is a smell.spatie/laravel-activitylog), but it does not store history itself.starts_at <= now < ends_at). Storing a duplicated boolean creates drift; compute it.To executives: This is a small, free (MIT), actively maintained library that removes a recurring category of boilerplate from our Laravel codebase. It lets us ship publishing, moderation, and account-status features faster and with fewer inconsistencies, because every flag behaves the same way and emits the same events. The risk profile is low: no runtime service, no vendor account, no data migration, and the code is small enough to fork if it ever stops being maintained. It is not a differentiator — it's cost avoidance. Expect it to save roughly a day of engineering per flag we'd otherwise hand-roll, plus the ongoing cost of keeping near-duplicate traits in sync.
To engineering: Trait-composable, declare(strict_types=1), final scope classes, tested across PHP 8.1–8.5 with Orchestra Testbench. You get isPublished() / publish() / undoPublish(), query macros (withNotPublished(), onlyNotPublished()), attribute casting handled in initialize*Helpers(), and model events for side effects. Global scopes are opt-in via shouldApplyXxxScope(), so nothing filters silently unless you ask it to. No service provider, no config to publish, no bootstrapping. Two caveats to own deliberately: choose Classic vs. Inverse scope direction per model as an explicit decision, and don't use this where a proper state machine or audit log is required — it composes with those tools, it doesn't replace them.
How can I help you explore Laravel packages today?