{"id":19311902,"url":"https://github.com/kyslik/laravel-filterable","last_synced_at":"2025-04-06T07:15:04.649Z","repository":{"id":38375208,"uuid":"111145226","full_name":"Kyslik/laravel-filterable","owner":"Kyslik","description":"Laravel 5/6/7 package to handle filtering by query-string","archived":false,"fork":false,"pushed_at":"2021-03-22T08:36:36.000Z","size":107,"stargazers_count":117,"open_issues_count":8,"forks_count":34,"subscribers_count":12,"default_branch":"L7","last_synced_at":"2024-09-21T08:58:47.329Z","etag":null,"topics":["filterable","filtering","laravel","laravel-package","laravel56","laravel57","laravel58","php"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Kyslik.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-11-17T19:58:45.000Z","updated_at":"2024-09-19T14:11:46.000Z","dependencies_parsed_at":"2022-08-25T01:40:12.981Z","dependency_job_id":null,"html_url":"https://github.com/Kyslik/laravel-filterable","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kyslik%2Flaravel-filterable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kyslik%2Flaravel-filterable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kyslik%2Flaravel-filterable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kyslik%2Flaravel-filterable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Kyslik","download_url":"https://codeload.github.com/Kyslik/laravel-filterable/tar.gz/refs/heads/L7","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247445682,"owners_count":20939961,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["filterable","filtering","laravel","laravel-package","laravel56","laravel57","laravel58","php"],"created_at":"2024-11-10T00:31:13.625Z","updated_at":"2025-04-06T07:15:04.580Z","avatar_url":"https://github.com/Kyslik.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Laravel Filterable\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/Kyslik/laravel-filterable.svg?style=flat-square)](https://packagist.org/packages/kyslik/laravel-filterable)\n[![Build Status](https://img.shields.io/travis/Kyslik/laravel-filterable/master.svg?style=flat-square)](https://travis-ci.org/Kyslik/laravel-filterable)\n[![Total Downloads](https://img.shields.io/packagist/dt/kyslik/laravel-filterable.svg?style=flat-square)](https://packagist.org/packages/kyslik/laravel-filterable)\n\nThis package allows you to easily handle database filtering through query strings. The idea is taken from one of the [Jeffrey's videos (behind the paywall)](https://laracasts.com/series/eloquent-techniques/episodes/4). One quick example might look like this: `/users?filter-username=~joe` will result in SQL query `select * from users where \"username\" like '%joe%'`.\n\n## Installation\n\nYou can install the package via composer:\n\n```bash\ncomposer require kyslik/laravel-filterable\n```\n\nIf you are using Laravel 7:  \n\n```bash\ncomposer require kyslik/laravel-filterable dev-L7\n```\n\nLaravel will discover the package by itself. If you feel old-school, disable auto-discovery and add `Kyslik\\LaravelFilterable\\FilterableServiceProvider::class` to the providers array in your `config/app.php`.\n\nYou may continue by publishing [configuration](./config/filterable.php) by issuing following artisan command `php artisan vendor:publish`.\n\n## Introduction\n\nPackage lets you to create \u0026\u0026 apply two kinds of filters **custom** and **generic**.\n\n### Custom filters\n\n**Custom** filters are just like in Jeffrey's video. You define a logic on a builder instance and package applies it via [local scope](https://laravel.com/docs/5.7/eloquent#local-scopes).\n\nLet's say a product requires displaying recently created records. You create a method `recent($minutes = null)` inside a filter class, which returns Builder instance:\n\n```php\npublic function recent($minutes = null): \\Illuminate\\Database\\Eloquent\\Builder\n{\n    $minutes = (is_numeric($minutes)) ? $minutes : 30;\n\n    return $this-\u003ebuilder-\u003ewhere('created_at', '\u003e=', Carbon\\Carbon::now()-\u003esubMinutes($minutes));\n}\n```\n\n\u003e **Note**: full example is shown [later on](https://github.com/Kyslik/laravel-filterable#example-with-generic-filters)\n\n### Generic filters\n\n**Generic** filters are those defined in [config file](./config/filterable.php). By default, the package supports filtering `timestamps`, `ranges`, `ins`, `booleans` and `strings`.\n\n```\n/?filter-created_at=t\u003e=1510952444\n/?filter-id=\u003e\u003c1,19\n/?filter-id=i=1,5,10,12\n/?filter-admin=b=yes\n/?filter-username=joe\n/?filter-username=~joe\n/?filter-username=~joe\u0026filter-admin=b=yes\u0026filter-created_at=t=1510952444\n```\n\n#### Default operator matrix for generic filters\n\n| **operator** |               **accepts**              | **description**       |\n|:------------:|:--------------------------------------:|-----------------------|\n|      `=`     |                `string`                | equal                 |\n|     `!=`     |                `string`                | not equal             |\n|      `\u003e`     |                `string`                | greater than          |\n|      `\u003c`     |                `string`                | less than             |\n|     `\u003e=`     |                `string`                | equal or greater than |\n|     `\u003c=`     |                `string`                | equal or less than    |\n|      `~`     |                `string`                | like                  |\n|     `!~`     |                `string`                | not like              |\n|     `\u003e\u003c`     |          comma separated list          | between               |\n|     `!\u003e\u003c`    |          comma separated list          | not between           |\n|     `i=`     |          comma separated list          | in                    |\n|     `i!=`    |          comma separated list          | not in                |\n|     `b=`     | `1`, `0`, `true`, `false`, `yes`, `no` | equal                 |\n|     `b!=`    | `1`, `0`, `true`, `false`, `yes`, `no` | not equal             |\n|     `t=`     |             UNIX timestamp             | equal                 |\n|     `t!=`    |             UNIX timestamp             | not equal             |\n|     `t\u003e`     |             UNIX timestamp             | greater than          |\n|     `t\u003c`     |             UNIX timestamp             | less than             |\n|     `t\u003e=`    |             UNIX timestamp             | equal or greater than |\n|     `t\u003c=`    |             UNIX timestamp             | equal or less than    |\n|     `t\u003e\u003c`    |             UNIX timestamp             | between               |\n|    `t!\u003e\u003c`    |             UNIX timestamp             | not between           |\n\n## Usage\n\nWhile using both **custom** or **generic** filters you must:\n\n1. have [local scope](https://laravel.com/docs/5.7/eloquent#local-scopes) on model with the signature `scopeFilter(Builder $query, FILTERNAME $filters)`\n2. have particular (`FILTERNAME`) filter class that extends one of:\n   - `Kyslik\\LaravelFilterable\\Generic\\Filter` class - allows usage of both **custom** \u0026 **generic** filters\n   - `Kyslik\\LaravelFilterable\\Filter` class - allows usage of only **custom** filters\n3. call a scope within a controller\n\n#### make:filter command\n\nYou can use the following command to create a new filter. \n```bash\nphp artisan make:filter SomeFilter\n```\n\nThis will create a new **Custom** filter in the **app/Filters** directory. To create a **Generic** filter just add the `--generic` (`-g`) flag to the command:\n```bash\nphp artisan make:filter SomeGenericFilter -g\n```\nLastly, you can override the default namespace by changing the **namespace** config value e.g.\n\n**config/filterable.php**\n```php\nreturn [\n    'namespace' =\u003e 'Http\\Filters',\n    ...\n];\n```\n\n### Example with custom filters\n\nLet's say you want to use filterable on `User` model. You will have to create the filter class `App/Filters/UserFilter.php` (`php artisan make:filter UserFilter`), specify `filterMap()` and **filter** method (`recent(...)`) with the custom logic.\n\n```php\n\u003c?php\nnamespace App\\Filters;\n\nuse Kyslik\\LaravelFilterable\\Filter;\n\nclass UserFilter extends Filter\n{\n    public function filterMap(): array\n    {\n        return ['recent' =\u003e ['recently', 'recent']];\n    }\n\n    public function recent($minutes = null)\n    {\n        $minutes = (is_numeric($minutes)) ? $minutes : 30;\n\n        return $this-\u003ebuilder-\u003ewhere('created_at', '\u003e=', \\Carbon\\Carbon::now()-\u003esubMinutes($minutes)-\u003etoDateTimeString());\n    }\n}\n```\n\n\u003e**Note**: `filterMap()` shall return an associative array where **key** is a method name and **value** is either alias or array of aliases\n\nNow add a [local scope](https://laravel.com/docs/5.7/eloquent#local-scopes) to the `User` model via [Filterable](https://github.com/Kyslik/laravel-filterable/blob/master/src/Filterable.php):\n\n```php\nuse Kyslik\\LaravelFilterable\\Filterable;\n\n...\nclass User extends Model\n{\n    use Filterable;\n    ...\n}\n```\n\nFinally, call the scope in a controller like so:\n\n```php\nuse App\\Filters\\UserFilter;\n...\npublic function index(User $user, UserFilter $filters)\n{\n    return $user-\u003efilter($filters)-\u003epaginate();\n}\n```\n\nNow end-user can visit `users?recent` or `users?recently` or `users?recent=25` and results will be filtered by `recent()` method defined in `UserFilter` class.\n\n### Example with generic filters\n\nLet's say you want to use generic filters on `User` model. You will have to create filter class `App/Filters/UserFilter.php` (`php artisan make:filter UserFilter -g`) and specify `$filterables` just like below:\n\n```php\n\u003c?php\nnamespace App\\Filters;\n\nuse Kyslik\\LaravelFilterable\\Generic\\Filter;\n\nclass UserFilter extends Filter\n{\n    protected $filterables = ['id', 'username', 'email', 'created_at', 'updated_at'];\n}\n```\n\nNext, you will have to add a [local scope](https://laravel.com/docs/5.7/eloquent#local-scopes) to the `User` model via [Filterable](https://github.com/Kyslik/laravel-filterable/blob/master/src/Filterable.php):\n\n```php\nuse Kyslik\\LaravelFilterable\\Filterable;\n\n...\nclass User extends Model\n{\n    use Filterable;\n    ...\n}\n```\n\nFinally, call the scope in a controller like so:\n\n```php\nuse App\\Filters\\UserFilter;\n...\npublic function index(User $user, UserFilter $filters)\n{\n    return $user-\u003efilter($filters)-\u003epaginate();\n}\n```\n\n\nNow you are ready to filter `User` model.\n\n\u003e**Note**: behind the scenes `...\\Generic\\Filter` class extends `Filter` class, therefore using **`...\\Generic\\Filter`** also enables you to apply custom filters defined within the filter class\n\n#### Additional configuration\n\nWhile using generic filters you may define which generics should be allowed. Define `settings()` method in a filter class, see below:\n\n```php\nuse Kyslik\\LaravelFilterable\\Generic\\Filter\n...\nclass UserFilter extends Filter\n{\n    protected $filterables = ['id', 'username', 'email', 'created_at', 'updated_at'];\n\n    protected function settings()\n    {\n        // global settings for this filter, pick either \"except\" or \"only\" logic\n        $this-\u003eonly(['=', '~', '!~']);\n        // $this-\u003eexcept(['!=']);\n\n        // settings applied only to some columns, these settings ignore the \"global\" settings above\n        $this-\u003efor(['username', 'id'])-\u003eonly(['!=', '\u003e=', '=', '~']);\n        $this-\u003efor(['id'])-\u003eonly(['=', '!=', '~']); // settings for \"id\" will be re-written\n    }\n}\n```\n\n### Additional features\n\n#### Default filtering\n\nIn case you need to apply a filter when no filter is applied yet (determined by what query-string contains at the given request), you can use the following code in the controller:\n\n```php\npublic function index(User $user, UserFilter $filter)\n{\n    // will redirect and \"apply\" the `recent` and `filter-id` filters \n    // if not a single filter from UserFilter is applied\n    $filter-\u003edefault(['recent' =\u003e now()-\u003etoDateTimeString(), 'filter-id' =\u003e '!=5']);\n\n    return $user-\u003efilter($filter)-\u003epaginate();\n}\n```\n\nEnd-user is going be redirected from `http://filters.test/users` to `http://filters.test/users?recent=2018-10-01 13:52:40\u0026filter-id=!=5`. \nIn case the filter that you specify as *default* does not exist `Kyslik\\LaravelFilterable\\Exceptions\\InvalidArgumentException` is thrown.\n\n\u003e **Caution**: be careful of **infinite redirects**\n\nYou can read more about the feature in the [original issue #10](https://github.com/Kyslik/laravel-filterable/issues/10).\n\n#### JoinSupport for filters\n\nTBA\n\nYou can read more about the feature in the [original PR #9](https://github.com/Kyslik/laravel-filterable/pull/9).\n\n## Testing\n\n``` bash\ncomposer test\n```\n\n## Changelog\n\nPlease see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.\n\n## Contributing\n\nPlease see [CONTRIBUTING](CONTRIBUTING.md) for details.\n\n## Security\n\nIf you discover any security related issues, please email martin.kiesel@gmail.com instead of using the issue tracker.\n\n## Credits\n\n- [kyslik](https://github.com/kyslik)\n- [All Contributors](../../contributors)\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyslik%2Flaravel-filterable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkyslik%2Flaravel-filterable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyslik%2Flaravel-filterable/lists"}