diff --git a/README.md b/README.md index 43c07e63..63610e0b 100644 --- a/README.md +++ b/README.md @@ -85,9 +85,13 @@ $posts = Post::filter(PostFilter::class)->paginate(); **4. Or bind the filter directly to the model** ```php +use App\Http\Filters\PostFilter; +use Illuminate\Database\Eloquent\Model; +use Kettasoft\Filterable\Traits\InteractsWithFilterable; + class Post extends Model { - use HasFilterable; + use InteractsWithFilterable; protected $filterable = PostFilter::class; } diff --git a/docs/features/auto-binding.md b/docs/features/auto-binding.md index 9d46935f..714b6e9a 100644 --- a/docs/features/auto-binding.md +++ b/docs/features/auto-binding.md @@ -12,11 +12,11 @@ Inside your Eloquent model, define a `$filterable` property and assign the class namespace App\Models; use Illuminate\Database\Eloquent\Model; -use Kettasoft\Filterable\Traits\HasFilterable; +use Kettasoft\Filterable\Traits\InteractsWithFilterable; class User extends Model { - use HasFilterable; + use InteractsWithFilterable; protected $filterable = \App\Http\Filters\UserFilter::class; } ``` @@ -29,6 +29,8 @@ $users = User::filter()->get(); The package will automatically resolve and use the UserFilter class defined in the model. +> **Upgrading:** The previous `HasFilterable` trait remains available as a deprecated compatibility wrapper. Existing models will continue to work, but new code should use `InteractsWithFilterable`. + ## 🧠 Notes - If no $filterable is set on the model, you will still need to pass the filter class manually to filter(). diff --git a/docs/features/auto-register-filterable-macro.md b/docs/features/auto-register-filterable-macro.md index ccff98db..8a558c8a 100644 --- a/docs/features/auto-register-filterable-macro.md +++ b/docs/features/auto-register-filterable-macro.md @@ -2,7 +2,7 @@ ## Overview -By default, to use the **`filter()`** macro on Eloquent models, you must use the HasFilterable trait in each model. However, if you prefer to automatically register the **`filter()`** method on all Eloquent builders without modifying individual models, you can use the **`AutoRegisterFilterableServiceProvider`**. +By default, to use the **`filter()`** macro on Eloquent models, you must use the InteractsWithFilterable trait in each model. However, if you prefer to automatically register the **`filter()`** method on all Eloquent builders without modifying individual models, you can use the **`AutoRegisterFilterableServiceProvider`**. ### ✅ How to Use @@ -17,12 +17,12 @@ By default, to use the **`filter()`** macro on Eloquent models, you must use the ``` 2. Remove the Trait (Optional) - You can now remove the HasFilterable trait from your Eloquent models: + You can now remove the InteractsWithFilterable trait from your Eloquent models: ```php class User extends Model { - // No need for HasFilterable trait + // No need for InteractsWithFilterable trait } ``` @@ -48,4 +48,4 @@ $users = User::filter()->get(); - ✅ You want zero setup per model. - ✅ You prefer centralized control over all query filtering. -- ❌ You want explicit opt-in per model using HasFilterable. +- ❌ You want explicit opt-in per model using InteractsWithFilterable. diff --git a/src/Traits/HasFilterable.php b/src/Traits/HasFilterable.php index 92660263..3c4cbf15 100644 --- a/src/Traits/HasFilterable.php +++ b/src/Traits/HasFilterable.php @@ -2,53 +2,13 @@ namespace Kettasoft\Filterable\Traits; -use Kettasoft\Filterable\Filterable; -use Illuminate\Contracts\Database\Eloquent\Builder; -use Kettasoft\Filterable\Support\FilterResolver; -use Kettasoft\Filterable\Exceptions\FilterClassNotResolvedException; -use Kettasoft\Filterable\Foundation\Contracts\QueryBuilderInterface; - /** - * Apply filters dynamically to Eloquent Query. - * - * This is not a typical Laravel Global Scope. + * @deprecated Use {@see InteractsWithFilterable} instead. * - * @method static \Kettasoft\Filterable\Foundation\Invoker|\Illuminate\Contracts\Database\Eloquent\Builder filter(\Kettasoft\Filterable\Filterable|string|null $filter = null) + * @method static \Kettasoft\Filterable\Foundation\Invoker|\Illuminate\Contracts\Database\Eloquent\Builder filter(\Kettasoft\Filterable\Filterable|string|array|null $filter = null) * @mixin \Illuminate\Database\Eloquent\Model */ trait HasFilterable { - /** - * Apply all relevant thread filters. - * @param \Illuminate\Contracts\Database\Eloquent\Builder $query - * @param \Kettasoft\Filterable\Filterable|string|null $filter - * @return \Illuminate\Contracts\Database\Eloquent\Builder - */ - public function scopeFilter(Builder $query, Filterable|string|array|null $filter = null): QueryBuilderInterface - { - return (new FilterResolver($query, $filter))->resolve(); - } - - /** - * Get defined filterable class from model. - * @throws \Kettasoft\Filterable\Exceptions\FilterClassNotResolvedException - */ - public function getFilterable() - { - if (! property_exists($this, 'filterable')) { - throw new FilterClassNotResolvedException(get_class($this)); - } - - return $this->filterable; - } - - /** - * Get the number of models to return per page. - * - * @return int - */ - public function getPerPage() - { - return config('filterable.paginate_limit') ?? request('perPage', parent::getPerPage()); - } + use InteractsWithFilterable; } diff --git a/src/Traits/InteractsWithFilterable.php b/src/Traits/InteractsWithFilterable.php new file mode 100644 index 00000000..547f26ff --- /dev/null +++ b/src/Traits/InteractsWithFilterable.php @@ -0,0 +1,54 @@ +resolve(); + } + + /** + * Get defined filterable class from model. + * @throws \Kettasoft\Filterable\Exceptions\FilterClassNotResolvedException + */ + public function getFilterable() + { + if (! property_exists($this, 'filterable')) { + throw new FilterClassNotResolvedException(get_class($this)); + } + + return $this->filterable; + } + + /** + * Get the number of models to return per page. + * + * @return int + */ + public function getPerPage() + { + return config('filterable.paginate_limit') ?? request('perPage', parent::getPerPage()); + } +} diff --git a/tests/Models/Post.php b/tests/Models/Post.php index 9578a798..5ba2a164 100644 --- a/tests/Models/Post.php +++ b/tests/Models/Post.php @@ -4,7 +4,7 @@ use Illuminate\Database\Eloquent\Model; use Kettasoft\Filterable\Tests\Models\Tag; -use Kettasoft\Filterable\Traits\HasFilterable; +use Kettasoft\Filterable\Traits\InteractsWithFilterable; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -12,7 +12,7 @@ class Post extends Model { - use HasFactory, HasFilterable; + use HasFactory, InteractsWithFilterable; protected $fillable = ['title', 'status', 'content', 'views', 'is_featured', 'description', 'tags']; diff --git a/tests/Models/User.php b/tests/Models/User.php index b41fcd36..c1bcf2ee 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -3,14 +3,14 @@ namespace Kettasoft\Filterable\Tests\Models; use Illuminate\Database\Eloquent\Model; -use Kettasoft\Filterable\Traits\HasFilterable; +use Kettasoft\Filterable\Traits\InteractsWithFilterable; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Factories\HasFactory; use Kettasoft\Filterable\Tests\Database\Factories\UserFactory; class User extends Model { - use HasFactory, HasFilterable; + use HasFactory, InteractsWithFilterable; protected $fillable = ['name', 'email', 'is_blocked', 'platform', 'password']; diff --git a/tests/Unit/Filterable/FilterableModelAutoBindingTest.php b/tests/Unit/Filterable/FilterableModelAutoBindingTest.php index a4baeb00..25282e56 100644 --- a/tests/Unit/Filterable/FilterableModelAutoBindingTest.php +++ b/tests/Unit/Filterable/FilterableModelAutoBindingTest.php @@ -5,6 +5,7 @@ use Illuminate\Database\Eloquent\Model; use Kettasoft\Filterable\Tests\TestCase; use Kettasoft\Filterable\Traits\HasFilterable; +use Kettasoft\Filterable\Traits\InteractsWithFilterable; use Illuminate\Contracts\Database\Query\Builder; use Kettasoft\Filterable\Tests\Http\Filters\PostFilter; use Kettasoft\Filterable\Exceptions\FilterClassNotResolvedException; @@ -14,7 +15,7 @@ class FilterableModelAutoBindingTest extends TestCase public function test_it_applies_filter_automatically_from_model_property() { $model = new class extends Model { - use HasFilterable; + use InteractsWithFilterable; protected $filterable = PostFilter::class; }; @@ -24,11 +25,21 @@ public function test_it_applies_filter_automatically_from_model_property() public function test_it_throws_exception_if_no_filter_class_and_no_model_property() { $model = new class extends Model { - use HasFilterable; + use InteractsWithFilterable; }; $this->expectException(FilterClassNotResolvedException::class); $model->filter(); } + + public function test_legacy_trait_remains_compatible() + { + $model = new class extends Model { + use HasFilterable; + protected $filterable = PostFilter::class; + }; + + $this->assertInstanceOf(Builder::class, $model->filter()); + } }