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 Purity Laravel Package

abbasudo/laravel-purity

Laravel Purity is an elegant filtering and sorting package for Laravel Eloquent. Add filter() to any query and let frontend users filter and sort results through simple URL query string parameters, with no extra boilerplate.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. Purity is a thin request-to-query translator layered on Eloquent. It introduces no tables, migrations, config file, queue workers, or external services; Post::filter() simply returns a mutated query builder. Blast radius is therefore small and reversible — you can remove the call and the application still compiles. It composes cleanly with existing local scopes, global scopes, policies, and API resources, and it fits the standard "thin controller, query in the model/scope" Laravel idiom that most teams already use.

The architectural caveat to flag explicitly: Purity reads the HTTP query string from inside the data layer. That is the entire value proposition (zero boilerplate), but it means your public filtering grammar (?filters[title][$contains]=…, ?sort=-created_at) becomes a de facto product contract owned partly by a third-party package. Decide up front that this grammar is versioned API surface, documented in your OpenAPI spec, not an implementation detail. If you ever replace Purity, you must preserve the wire format or version the endpoint.

Integration feasibility. High. Install is a single Composer require; enablement is opt-in per query. The real work is not technical — it is the allowlist design. Every model exposed to filtering needs an explicit $filterable/allowed-fields declaration (ideally via getFilterables() or equivalent), and every sortable column needs whitelisting. This is a per-model configuration task that scales linearly with the number of exposed entities, and it is the main driver of effort estimation. Budget roughly half a day per model for definition plus tests, not half a day for the whole rollout.

Technical risk.

  • Supply chain and bus factor. One primary maintainer, ~515 stars, and zero reported dependents — i.e., effectively no downstream ecosystem to absorb a breaking change or an abandonment. The release history is long and incremental (v1 through v3.3.9) with real bug-fix traffic, which is a positive signal on maintenance, but the concentration risk is real. Mitigation: vendor the package or pin an exact version and treat upgrades as planned work.
  • Injection surface via column names. Any package that turns user input into SQL identifiers warrants scrutiny. Whitelisting is the control; enforce it as a hard rule rather than a convention, and add a lint/CI check that fails if a model using filter() lacks an allowlist. There is history in the changelog of related fixes (unquoted column names in DefaultSort, a body-vs-query-string scoping fix, $notIn corrections) — good that they were fixed, informative that this class of bug recurs.
  • Driver divergence. Operator semantics for $contains differ across MySQL, PostgreSQL, MariaDB, and SQLite (case sensitivity, LIKE vs ILIKE). Multiple changelog entries show this being patched repeatedly. If you run different engines per environment, treat filter behavior as needing per-driver test coverage.
  • Performance invisibility. Arbitrary user-selected sort and filter combinations cannot all be indexed. A single ?sort=-some_unindexed_column on a large table is a table scan triggered by a client, not by your code. This is the largest production risk and it is not visible in code review.
  • Version currency. The releases show Laravel 11, 12, and 13 compatibility bumps landing, plus PHP version requirements. Pinning matters: a Laravel major upgrade may require a Purity major/minor bump in lockstep.

Key questions.

  1. Which models and endpoints are in scope, and who owns the allowlist for each?
  2. Do we expose filters on any table above ~1M rows, and if so what is the index strategy for the top-N sort/filter permutations?
  3. Is the query-string grammar already promised to any client, or can we still shape it?
  4. What is the support contract if the maintainer goes inactive — fork, vendor, or replace with a homegrown scope?
  5. Do we need relation-based sorting/filtering (supported since v3.2/3.3), and have we measured the join cost?
  6. Are we behind a cache/CDN, and do filtered URLs need cache-key normalization?

Integration Approach

Stack fit. Native fit for a Laravel API (REST or as a Livewire data source). It assumes Eloquent as the data access layer and does not interfere with authentication, authorization, validation, or serialization — those stay where they are. It is not a fit for raw-query/DB-facade code paths, for GraphQL where the query language is already the contract, or for endpoints where the client is another service whose query semantics you control directly.

Migration path. Low-risk, incremental, reversible:

  1. Add the dependency pinned to a specific version; commit the lockfile.
  2. Introduce a single config/contract location for allowlists so they are auditable in one place rather than scattered across models.
  3. Pilot on one low-traffic, read-only endpoint behind a feature flag.
  4. Extend model by model to the endpoints the product actually needs.
  5. Keep the legacy hand-rolled filter code in place until the pilot is validated, then delete.

There is no data migration and no downtime. Rollback is removing the filter() call from a query or reverting the Composer change; no schema state is created.

Compatibility. Verify against your exact PHP/Laravel pair before committing — the package tracks Laravel majors closely but not instantaneously, so a team mid-upgrade to the newest Laravel major should confirm the release that added support is the one they pin. Confirm database driver parity if you run MySQL in production and SQLite in tests; run the filter test suite against the production engine. Confirm behavior with relation-based sorting if you use it, since that generates joins that interact with existing select/with clauses.

Sequencing. Allowlist design and performance guardrails must land before the first user-facing endpoint, not after. Concretely: (1) define the public filter grammar and write it into the API docs; (2) build the allowlist contract and a test that asserts unfilterable columns are rejected; (3) pilot; (4) add query-count and slow-query instrumentation; (5) roll out per endpoint in order of ascending data volume, leaving the largest tables last so you have evidence before touching them.

Operational Impact

Maintenance. Low ongoing code maintenance (no config drift, no migrations, no background processes) but non-zero dependency maintenance: pin versions, review release notes on upgrade, and re-run driver-specific filter tests after any Laravel major. The allowlist itself is living configuration — it will drift as models gain columns, and without an ownership rule it silently becomes either over-permissive (security) or stale (product gaps). Assign a named owner.

Support. Support burden concentrates in two places: "why doesn't my filter work" (usually a missing allowlist entry, a renamed field, or an unlisted operator) and "this endpoint got slow" (usually an unindexed sort). Both are answerable with documentation, not engineering. Write a one-page internal runbook mapping query-string patterns to the allowlist entries that must exist, and instrument rejected-filter counts — a spike there is your fastest signal of a client/contract mismatch. The package's docs site is decent but you should not depend on upstream for internal guidance; the maintainer is a single person with no commercial support tier implied.

Scaling. Two independent axes. Request volume scales trivially — this is pure query-builder manipulation with negligible PHP overhead, no I/O, no shared state. Data volume is the real constraint: filter/sort permutations multiply, index coverage cannot follow, and offset pagination on filtered results degrades predictably. Practical guardrails: cap page size, prefer cursor pagination on high-volume endpoints, restrict sortable columns to indexed ones, and set a hard row-count or time threshold above which a given table is not exposed to arbitrary filtering. Where relation sorting is used, the generated joins can amplify cost — measure before enabling on large tables.

Failure modes.

  • Silent permissiveness — a model without an allowlist exposes columns nobody intended (e.g., internal flags, tenant IDs). Detected late, if at all. Mitigate with a CI assertion, not a code-review convention.
  • Slow query cascade — a client or crawler iterates sort permutations; the resulting scans saturate the DB. Mitigate with per-endpoint rate limiting and slow-query alerting keyed to filtered requests.
  • Operator/driver mismatch — a $contains behaves differently in staging (SQLite) than production (MySQL/PG), usually around case sensitivity. Tests must run on the production engine.
  • Upstream abandonment or breaking change — no downstream ecosystem to absorb it. Mitigate with an exact pin and a documented fork-or-replace fallback.
  • Contract drift — a client relies on a filter field that is later renamed or removed from the allowlist; the API returns unfiltered results rather than an error, which is the worst possible failure shape. Verify that rejections are loud.

Ramp-up. A mid-level Laravel developer is productive on Purity in under a day — the surface is filter(), sort(), and an allowlist declaration. The ramp-up cost is not the package; it is the two disciplines it demands: allowlist hygiene and query performance literacy. Budget a short team session on both, and require the first allowlist PR to be reviewed by whoever owns database performance. Plan for roughly one engineering day of setup plus per-model definition work, and treat that per-model figure as the honest estimate for the whole initiative.

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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
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