atannex/scopable
Scopable is a lightweight Laravel package that brings reusable, composable query scopes to Eloquent models. Define common filters once as scope classes and apply them across queries to keep filtering logic clean, consistent, and easy to maintain.
Architecture fit
atannex/scopable is a behavior layer over Eloquent models, not a subsystem: it adds declarative state scopes (published / scheduled / draft, active flags, schedule windows, expiry, highlights, limits, composites) plus matching PHP-side checks and mutators. That is the architecturally interesting part — it gives us a single source of truth for "is this row live?" across query filtering, API serialization, and in-memory guard clauses.where('published_at', '<=', now()) clauses, inconsistent draft handling between list endpoints, and PHP checks that drift from SQL filters. Consolidating those into one declarative vocabulary is a maintainability win independent of the vendor.Integration feasibility
composer require; no infrastructure, no services, no credentials. Integration cost is essentially engineering time for adoption and testing.published_at, scheduled_at, expires_at, is_active, is_highlighted). That single unknown determines whether this is a greenfield convenience or a retrofit project.Technical risk
Key questions
limits and composites express, with query examples?Stack fit
Migration path
Never combine a schema change with scope adoption in the same release.
Compatibility
scopePublished, scopeActive, or isPublished() methods on target models will conflict or silently shadow.toArray() consumers, since new mutators and accessors change payload shape.Sequencing
Maintenance
^1.0 constraint, a thin internal adapter, and a package owner who reviews minor bumps. The recurring cost is governance — keeping every model's state vocabulary consistent once the pattern is established.Support
Scaling
(state, published_at, expires_at) are required before data volume grows, and date-window scopes evaluated against now() inhibit query-cache reuse and can be function-wrapped (non-index-friendly) if implemented carelessly.isPublished() are called per row inside loops over large collections; prefer collection-level filtering via the scopes.createdThisWeek, publishedWithin) are convenient but easy to call in dashboards at scale — review their generated SQL before exposing them to reporting endpoints.Failure modes
Mitigations: standardize on UTC everywhere, add boundary-condition tests as a merge gate, alert on anomalous listing counts, feature-flag the rollout, and keep contract tests comparing new scopes against known-good queries for one release cycle.
Ramp-up
How can I help you explore Laravel packages today?