Skip to content

Releases: kettasoft/filterable

v2.15.0

09 Mar 09:42

Choose a tag to compare

What's Changed

Invokable Engine – Attribute Annotations

This release introduces a new attribute-based annotation system for the Invokable engine, allowing common transformations, validations, and behaviors to be declared directly on filter methods.

The goal is to reduce boilerplate, improve readability, and provide a structured pipeline for handling payload values.


New Features

Attribute Pipeline

Filter method attributes are now executed through a staged pipeline:

CONTROL → TRANSFORM → VALIDATE → BEHAVIOR

This ensures predictable execution order when combining multiple attributes.


New Attributes

Control

Attributes responsible for execution control.

  • Authorize — ensures the filter method is authorized before execution
  • Required — ensures the payload value exists
  • SkipIf — conditionally skips execution using Payload is* helpers (supports negation and repeatable usage)

Transform

Attributes that normalize or transform incoming values.

  • Trim — trims whitespace (left, right, both) with optional custom characters
  • Sanitize — applies sanitization rules (lowercase, uppercase, ucfirst, strip_tags, slug, etc.)
  • Cast — casts values to a specific type (int, float, bool, string, etc.)
  • Explode — splits strings into arrays using a delimiter
  • DefaultValue — provides a fallback value when none is provided
  • MapValue — maps incoming values to different values (supports strict mode)

Validate

Validation attributes executed after transformations.

  • Between — validates numeric range (min / max)
  • Regex — validates values against a regular expression
  • In — ensures the value exists in a defined set

Behavior

Attributes that modify query behavior.

  • Scope — applies an Eloquent scope to the query builder

Documentation

Documentation for the Invokable engine and annotations has been added:

  • Invokable engine overview
  • Attribute pipeline explanation
  • Individual documentation pages for each attribute
  • Annotations index page

Tests

A comprehensive test suite has been added covering:

  • Each attribute
  • Typical usage scenarios
  • Edge cases
  • Attribute interaction behavior

Example

#[Trim]
#[Sanitize('lowercase')]
#[MapValue(['active' => 1, 'inactive' => 0], strict: true)]
public function status(Payload $payload)
{
    $this->builder->where('status', '=', $payload->value);
}

Notes

  • No breaking changes.
  • Attributes are opt-in and only affect methods where they are used.

v2.14.1

28 Feb 23:33

Choose a tag to compare

v2.14.1 — Execution Lifecycle Fixes

This patch restores the intended filter execution lifecycle and improves
attribute behavior consistency.

Fixed

Attribute execution control

Control attributes are now able to properly halt filter method execution.

Previously, attributes designed to interrupt execution (such as
Required, authorization checks, or other control attributes)
were executed but did not prevent the filter method from running.

Execution flow now correctly respects control attributes.

Finalization lifecycle

The finally() hook is now executed when returning a query builder
through ShouldReturnQueryBuilder or $shouldReturnQueryBuilder.

Previously, finalization logic only ran when using the default
invoker return flow, leading to inconsistent behavior.

Notes

These changes restore the expected execution guarantees without
introducing breaking changes.

v2.14.0

26 Jan 15:27

Choose a tag to compare

Add HandleFluentReturn trait and implement builder dynamic method handling and change $builder type to \Illuminate\Database\Eloquent\Builder

v2.13.3

29 Dec 17:46

Choose a tag to compare

Relax version constraints for illuminate/database and illuminate/support to support multiple Laravel versions

Full Changelog: v2.13.2...v2.13.3

v2.13.2

29 Dec 17:25

Choose a tag to compare

Update composer.json and composer.lock for Laravel 12

Full Changelog: v2.13.1...v2.13.2

v2.13.1

04 Dec 13:25
7609b3f

Choose a tag to compare

Overview

This release updates all internal type hints from:

Illuminate\Database\Eloquent\Builder

to:

Illuminate\Contracts\Database\Eloquent\Builder

in order to provide full compatibility with all Eloquent builder implementations, including relationship builders such as HasMany, HasOne, BelongsTo, and others.

This ensures the package can handle any valid Eloquent query builder instance without throwing binding or instantiation conflicts.


Key Changes

1. Switched to Database Builder Contract

All classes now rely on the Illuminate\Contracts\Database\Eloquent\Builder interface instead of the concrete Illuminate\Database\Eloquent\Builder class.

This improves flexibility and aligns the package with Laravel’s contract-based design.

2. Relationship Builders Are Now Fully Supported

Previously, calling:

$hasMany = User::find(1)->posts();
Filterable::create()->setBuilder($hasMany);

resulted in a type mismatch error because HasMany does not extend the concrete Eloquent Builder class.

After this release, relationship builders and their variants work seamlessly.

3. Improved Developer Experience

Developers can now pass:

  • model query builders
  • relation builders
  • scoped queries
  • morph relations
  • and any builder-compatible object

without needing workarounds such as $relation->getQuery().


BC (Backward Compatibility)

This release does not introduce breaking changes.

Existing usage remains fully functional, and the package becomes more flexible and aligned with native Laravel behavior.


Upgrade Instructions

No special actions needed.
Simply update to the latest version:


Closing Notes

This release enhances interoperability and stability when working with complex Eloquent relationships, ensuring the package behaves consistently across all builder contexts.

v2.13.0

19 Nov 18:46
bdbd1e9

Choose a tag to compare

🚀 Improved Exception Handling

This release introduces a redesigned and extensible exception handler
for Filterable. The goal is to provide a more predictable, customizable,
and developer-friendly approach without adding any breaking changes.

✨ What's New

  • Added a new exceptions configuration section.
  • Introduced a pluggable exception handler class:
    • handler now accepts any class implementing
      Kettasoft\Filterable\Exceptions\Contracts\ExceptionHandlerInterface.
  • Added global strict mode to enforce throwing exceptions instead of skipping.
  • Unified exception flow across all filtering engines.
  • Simplified internal architecture for clean and consistent behavior.

⚙️ New Configuration

'exceptions' => [
    'handler' => Kettasoft\Filterable\Exceptions\Handlers\DefaultHandler::class,
    'strict' => env('FILTERABLE_EXCEPTION_STRICT', false),
]

🛠 Internal Improvements

  • Extracted exception logic out of engines into a central layer.
  • Cleaned up ~31 commits worth of restructuring and architectural refactoring.
  • No public API breaks.
  • Improved maintainability and added future flexibility for custom handlers.

🔮 Coming Next

  • Optional exception reporters.
  • Logging toggles.
  • Per-engine overrides.

v2.12.0

18 Nov 17:46
8b86b4d

Choose a tag to compare

What’s New?

This release brings a major expansion to the Payload API, focusing on improving readability, expressiveness, and developer ergonomics. New helpers make value checking, string manipulation, date handling, and extensibility dramatically smoother.

✨ New Features

Value Checking

  • in() / notIn() for membership checks
  • is() / isAny() for rule-based comparisons with negation
  • isEmptyString() for empty-string detection
  • isNotNullOrEmpty() for null-or-empty validation
  • regex() for validating values using regular expressions

String & Array Helpers

  • asSlug() to convert any value into a URL-friendly slug
  • explode() / split() for fast string-to-array transformation

Date & Time

  • isDate() for validating date strings
  • isTimestamp() for detecting valid UNIX timestamps
  • asCarbon() for converting values into Carbon instances

Extensibility

  • Added Macroable trait to allow dynamic runtime extension of the Payload class

🧪 Tests

A comprehensive test suite has been added and expanded to cover all existing and new helpers.

What's Changed

  • Add Applied Filters Tracking to Filterable Engine by @kettasoft in #34
  • Refactor Engine config access to unified pattern by @kettasoft in #35
  • Enhance Payload Utility & Add Comprehensive Value Helpers by @kettasoft in #36

Full Changelog: v2.11.0...v2.12.0

v2.11.0

12 Nov 18:02
3c7d022

Choose a tag to compare

Added

  • Introduced two new lifecycle hooks in the Filterable class:
    • initially(): Runs before any filters are applied, allowing pre-filter modifications to the query builder.
    • finally(): Runs after all filters have been applied, allowing post-filter adjustments or cleanup.

These hooks provide a clean and flexible way to manipulate the query builder.

Example usage:

class PostFilter extends Filterable
{
    protected function initially()
    {
        $this->builder->where('is_active', true);
    }

    protected function finally()
    {
        $this->builder->orderBy('created_at', 'desc');
    }
}

v2.10.0

12 Nov 17:51
962cf11

Choose a tag to compare

Filterable Caching Subsystem (v2.10.0)

This release introduces a full-featured caching subsystem for Filterable, designed to dramatically improve query performance while ensuring safe, consistent cache invalidation.

Key Features:

  • Deterministic Cache Keys — consistent keys for identical filter inputs.
  • Tagged Caching — bulk invalidation support for Redis/Memcached.
  • Scoped Caching — user, tenant, or custom scopes to prevent data leakage.
  • Cache Profiles — reusable configurations for environment-specific strategies.
  • Automatic Invalidation — observer clears affected caches on Eloquent model changes.
  • Invoker Integration — caches terminal-method results consistently.
  • Fluent APIHasFilterableCache trait with cache, cacheForever, cacheTags, scopeByUser, scopeByTenant, cacheProfile, cacheWhen/unless, flush.
  • Configuration & Docs — cache section in filterable.php and full documentation (getting-started, strategies, auto-invalidation, profiles, scoping, monitoring, API reference, examples).

Benefits:

  • Significant performance improvements for repeated filter queries (20x–200x).
  • Centralized, maintainable cache management.
  • Easy setup and profiling with detailed docs and examples.

Notes:

  • Tag-based invalidation requires Redis or Memcached.
  • Global cache prefix/version allows force-wide invalidation.
  • Ensure models are listed in filterable.php for auto-invalidation.