{"id":22125710,"url":"https://github.com/czim/laravel-filter","last_synced_at":"2025-04-06T10:15:11.667Z","repository":{"id":56960939,"uuid":"41874604","full_name":"czim/laravel-filter","owner":"czim","description":"Configurable and modular approach to query Filters for Laravel","archived":false,"fork":false,"pushed_at":"2024-07-30T13:26:52.000Z","size":154,"stargazers_count":88,"open_issues_count":1,"forks_count":12,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-30T09:07:30.193Z","etag":null,"topics":["filter","filtering","laravel","laravel-filter","query-builder"],"latest_commit_sha":null,"homepage":null,"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/czim.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-09-03T17:44:45.000Z","updated_at":"2024-10-10T13:18:30.000Z","dependencies_parsed_at":"2024-06-18T18:25:54.398Z","dependency_job_id":"b20dc5d3-e388-4437-8e5f-370bdba28f73","html_url":"https://github.com/czim/laravel-filter","commit_stats":{"total_commits":95,"total_committers":6,"mean_commits":"15.833333333333334","dds":0.4736842105263158,"last_synced_commit":"24bce1db5bc749c5aec9db0d1f16c31f64b7a8db"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czim%2Flaravel-filter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czim%2Flaravel-filter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czim%2Flaravel-filter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czim%2Flaravel-filter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/czim","download_url":"https://codeload.github.com/czim/laravel-filter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247464226,"owners_count":20942970,"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":["filter","filtering","laravel","laravel-filter","query-builder"],"created_at":"2024-12-01T16:37:16.752Z","updated_at":"2025-04-06T10:15:11.628Z","avatar_url":"https://github.com/czim.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Laravel Filter\n\n[![Latest Version on Packagist][ico-version]][link-packagist]\n[![Software License][ico-license]](LICENSE.md)\n[![Build Status](https://travis-ci.org/czim/laravel-filter.svg?branch=master)](https://travis-ci.org/czim/laravel-filter)\n[![Latest Stable Version](http://img.shields.io/packagist/v/czim/laravel-filter.svg)](https://packagist.org/packages/czim/laravel-filter)\n[![SensioLabsInsight](https://insight.sensiolabs.com/projects/d7fa4bf3-4f79-4095-9dda-abb3611d9a1c/mini.png)](https://insight.sensiolabs.com/projects/d7fa4bf3-4f79-4095-9dda-abb3611d9a1c)\n\n\nConfigurable and modular Filter setup for Laravel.\nThis is intended to make it easy to search for and filter by records using a typical web shop filter.\nFor example, if you want to filter a catalog of products by product attributes, brand names, product lines and so forth.\n\nThe standard Filter class provided is set up to apply filters to a given (Eloquent) query builder.\nAdditionally a CountableFilter extension of the class is provided for offering typical counts for determining what alternative filter settings should be displayed to visitors.\n\nThis is not a ready-to-use package, but a framework you can extend for your own specific applications.\n\n## Version Compatibility\n\n| Laravel       | PHP  | Package |\n|:--------------|:-----|:--------|\n| 5.8 and below | 7.0+ | 1.1     |\n| 6.0 to 7.0    | 7.1+ | 2.0     |\n| 6.0 to 8.0    | 7.2+ | 3.1     |\n| 9.0           | 8.1+ | 4.0     |\n| 10 and up     | 8.1+ | 5.0     |\n\n## Changelog\n\n[Changelog here](CHANGELOG.md).\n\n## Install\n\nVia Composer\n\n``` bash\n$ composer require czim/laravel-filter\n```\n\n## Basic Usage\n\nMake a class that extends `Czim\\FilterData` and set the protected properties for validation rules `$rules` and the default values for these attributes `$defaults`.\nNote that `$defaults` are used as the main means to detect which filter parameters need to be applied to the query, so make sure all filter parameters you want to implement are present in it.\n\nSimply extend the (abstract) filter class of your choice, either `Czim\\Filter\\Filter` or `Czim\\Filter\\CountableFilter`.\n\nEach has abstract methods that must be provided for the class to work. Once they are all set (see below), you can simply apply filter settings to a query:\n\n``` php\n    $filterValues = [ 'attributename' =\u003e 'value', ... ];\n\n    $filter = new SomeFilter($filterValues);\n\n    // get an Eloquent builder query for a model\n    $query = SomeEloquentModel::query();\n\n    // apply the filter to the query\n    $filteredQuery = $filter-\u003eapply($query);\n\n    // normal get() call on the now filtered query\n    $results = $filteredQuery-\u003eget();\n```\n\nA `CountableFilter` has an additional method that may be called:\n\n``` php\n    $countResults = $filter-\u003ecount();\n```\n\nYou can find more about countable filters below.\n\n\n## Filter Data\n\nYou may pass any array or Arrayable data directly into the filter, and it will create a `FilterData` object for you.\nIf you do not have the `$filterDataClass` property overridden, however, your filter will do nothing (because no attributes and defaults are set for it, the FilterData will always be empty).\nIn your extension of the `Filter` class, override the property like so in order to be able to let the Filter create it automatically:\n\n``` php\n    class YourFilter extends \\Czim\\Filter\\Filter\n    {\n        protected $filterDataClass = \\Your\\FilterDataClass::class;\n\n        ...\n    }\n```\n\nYour `FilterData` class should then look something like this:\n\n``` php\n    class FilterDataClass extends \\Czim\\Filter\\FilterData\n    {\n        // Validation rules for filter attributes passed in\n        protected $rules = [\n            'name'   =\u003e 'string|required',\n            'brands' =\u003e 'array|each:integer',\n            'before' =\u003e 'date',\n            'active' =\u003e 'boolean',\n        ];\n\n        // Default values and the parameter names accessible to the Filter class\n        // If (optional) filter attributes are not provided, these defaults will be used:\n        protected $defaults = [\n            'name'   =\u003e null,\n            'brands' =\u003e [],\n            'before' =\u003e null,\n            'active' =\u003e true,\n        ];\n    }\n```\n\nFilter validation rules are optional. If no rules are provided, validation always passes.\nDefaults are *required*, and define which parameter keys are applied by the filter.\n\nThen, passing array(able) data into the constructor of your filter will automatically instantiate that FilterData class for you.\nIf it is an (unmodified) extension of `Czim\\FilterData`, it will also validate the data and throw an exception if the data does not match the `$rules` defined in your Data class.\n\nAlternatively, you can make your own implementation of the provided `FilterDataInterface` and pass it into the Filter directly.\n\n``` php\n    $filter = new YourFilter( new YourFilterData($someData) );\n```\n\nAll it needs to do is implement the interface; if you pass in data this way, the data will be set without any further checks or validation, unless you handle it in your FilterData implementation yourself.\n\n\n## Filters\n\nBasic Filters take a query and apply filter parameters to it, before handing it back.\n(Note that the query object passed in will be modified; it is not cloned in the Filter before making modifications).\n\nFor example, if you'd do the following:\n\n``` php\n    $query = SomeModel::where('some_column', 1);\n\n    $query = (new YourFilter([ 'name' =\u003e 'random' ]))-\u003eapply($query);\n\n    echo $query-\u003etoSql();\n```\n\nYou might expect the result to be something like `select * from some_models where some_column = 1 and name LIKE '%random%'`.\n\n\nWhat a filter exactly does with the filter data you pass into its constructor must be defined in your implementation.\nThis may be done in two main ways, which can be freely combined:\n\n*   By defining *strategies* (overriding the public `strategies()` method)\n*   By overriding the `applyParameter()` method as a fallback option\n\n*Important*: filter logic is only invoked if the parameter's provided value is **not empty**.\nRegardless of the method you choose to make your filter application, it will *only* be applied if: `! empty($value) || $value === false`.\n\n\n### Strategies and ParameterFilters\n\nYou can define strategies for each filter parameter by adding a strategies method to your filter as follows:\n\n``` php\n    protected function strategies(): array\n    {\n        return [\n            // as a ParameterFilter instance\n            'parameter_name_here' =\u003e new \\Czim\\Filter\\ParameterFilters\\SimpleString(),\n\n            // as a ParameterFilter class string\n            'another_parameter'   =\u003e \\Czim\\Filter\\ParameterFilters\\SimpleString::class,\n\n            // as an anonymous function\n            'yet_another'         =\u003e function($name, $value, $query) {\n                                        return $query-\u003ewhere('some_column', '\u003e', $value);\n                                     },\n\n            // as an array (passable to call_user_func())\n            'and_another'         =\u003e [ $this, 'someMethodYouDefined' ],\n        ];\n    }\n```\n\nIf filter data is passed into the class with the same keyname as a strategy, that strategy method will be invoked.\nAs shown above, there are different ways to provide a callable method for filters, but all methods mean passing data to a function that takes these parameters:\n\n``` php\n    /**\n     * @param string          $name     the keyname of the parameter/strategy\n     * @param mixed           $value    the value for this parameter set in the filter data\n     * @param EloquentBuilder $query\n     * @param FilterInterface $filter   the filter from which the strategy was invoked\n     */\n    public function apply(string $name, $value, $query);\n```\n\nA `ParameterFilter` is a class (any that implements the `ParameterFilterInterface`) which may be set as a filter strategy.\nThe `apply()` method on this class will be called when the filter is applied.\nIf the ParameterFilter is given as a string for the strategy, it will be instantiated when the filter is applied.\n\nStrategies may also be defined as closures or arrays (so long as they may be fed into a `call_user_func()`).\nThe method called by this will receive the four parameters noted above.\n\nOnly if no strategy has been defined for a parameter, the callback method `applyParameter()` will be called on the filter itself.\nBy default, an exception will occur.\n\nSome common ParameterFilters are included in this package:\n\n* `SimpleInteger`: for looking up (integer) values with an optional operator ('=' by default)\n* `SimpleString`: for looking up string values, with a *LIKE % + value + %* match by default\n* `SimpleTranslatedString`: (uses `JoinKey::Translations` as the join key)\n\n\n### The fallback option: applyParameter()\n\nIf you prefer, you can also use the fallback method to handle any or all of the appliccable parameters.\nSimply add the following method to your filter class:\n\n``` php\n    protected function applyParameter(string $name, $value, $query)\n    {\n        switch ($name) {\n\n            case 'parameter_name_here':\n\n                // your implementation of the filter ...\n                return $query;\n\n            ...\n        }\n\n        // as a safeguard, you can call the parent method,\n        // which will throw exceptions for unhandled parameters\n        parent::applyParameter($name, $value, $query);\n    }\n```\n\nYou can freely combine this approach with the strategy definitions mentioned above.\nThe only limitation is that when there is a strategy defined for a parameter, the `applyParameter()` fallback will not be called for it.\n\n\n## Countable Filters\n\nThe `CountableFilter` is an extension of the normal filter that helps write special filters for, say, web shops where it makes sense to show relevant alternatives based on the current filter choices.\n\nTake a product catalog, for instance, where you're filtering based on a particular brand name and a price range.\nIn the filter options shown, you may want to display other brands that your visitor can filter on, but *only* the brands for which your have products in the chosen price range.\nThe idea is to prevent your visitors from selecting a different brand only to find that there are no results.\n\n`CountableFilters` help you to do this, by using currently set filters to generate counts for alternative options.\nSay you have brand X, Y and Z, and are filtering products only for brand X and only in a given price range.\nThe countable filter makes it easy to get a list of how many products also have matches for the price range of brand Y and Z.\n\nTo set up a `CountableFilter`, set up the `Filter` as normal, but additionally configure `$countables` and `countStrategies()`.\nThe counting strategies are similarly configurable/implementable as filtering strategies.\n\nThe return value for `CountableFilter::count()` is an instance of `Czim\\CountableResults`, which is basically a standard Laravel `Collection` instance.\n\n\n### Counting Strategies\n\nStrategies may be defined for the effects of `count()` per parameter for your CountableFilter, in the same way as normal filter strategies.\n\n``` php\n    protected function countStrategies(): array\n    {\n        return [\n            'parameter_name_here' =\u003e new \\Czim\\Filter\\ParameterCounters\\SimpleInteger(),\n            ...\n        ];\n    }\n```\n\nThe same methods for defining strategies are available as with the `strategies()` methods above: instances (of ParameterCounters in this case), strings, closures and arrays.\n\nThe fallback for parameters without defined strategies is `countParameter()`:\n\n``` php\n    /**\n     * @param string          $parameter countable name\n     * @param EloquentBuilder $query\n     */\n    protected function countParameter(string $parameter, $query)\n    {\n        // your implementation for each $parameter name\n    }\n```\n\n\n### ParameterCounters\n\nJust like ParameterFilters for `Filter`, ParameterCounters can be used as 'plugins' for your `CountableFilter`.\n\n``` php\n\n    protected function countStrategies(): array\n    {\n        return [\n            'parameter_name_here' =\u003e new ParameterCounters\\YourParameterCounter()\n        ];\n    }\n```\n\nParameterCounters must implement the `ParameterCounterInterface`, featuring this method:\n\n``` php\n    /**\n     * @param string                   $name\n     * @param EloquentBuilder          $query\n     * @param CountableFilterInterface $filter\n     */\n    public function count(string $name, $query, CountableFilterInterface $filter);\n```\n\n## Settings and Extra stuff\n\n### Joins\n\nWhen joining tables for filter parameters, it may occur that different parameters require the same join(s).\nIn order to prevent duplicate joining of tables, the Filter class has a built in helper for working with joins.\n\n``` php\n    // within your applyParameter implementation\n    // the first parameter is a keyname you define, see the JoinKey enum provided\n    // the second parameter is an array of parameters that is passed on directly\n    //     to Laravel's query builder join() method.\n    $this-\u003eaddJoin('keyname_for_your_join', [ 'table', 'column_a', '=', 'column_b' ]);\n\n    // or within a ParameterFilter apply() method, call it on the filter\n    $filter-\u003eaddJoin( ... , [ ... ]);\n```\n\nJoins so added are automatically applied to the filter after all parameters are applied.\n\n\n### Global Filter Settings\n\nSometimes it may be useful to let filter-wide settings affect the way your filter works.\nYou can set these through a setter directly on the filter class, `setSetting()`.\nAlternatively, you can define a filter parameter strategy as `Filter::SETTING`, and it will be loaded as a setting before the filter is applied.\n\n``` php\n    // in your Filter class:\n    protected function strategies(): array\n    {\n        return [\n            ...\n\n            'global_setting_name' =\u003e static::SETTING\n        ];\n    }\n```\n\nWhen a setting has been set in either way, you can check it with the `setting()` method.\nNote that the ParameterFilter/ParameterCounter also receives the `$filter` itself as a parameter and the method is public.\n\nIf a setting has not been defined, the `setting()` method for it will return `null`.\n\n\n## Examples\n\nHere are [some examples](EXAMPLES.md) of using the Filter and CountableFilter classes.\n\n\n## Contributing\n\nPlease see [CONTRIBUTING](CONTRIBUTING.md) for details.\n\n\n## Credits\n\n- [Coen Zimmerman][link-author]\n- [All Contributors][link-contributors]\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n\n[ico-version]: https://img.shields.io/packagist/v/czim/laravel-filter.svg?style=flat-square\n[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square\n[ico-downloads]: https://img.shields.io/packagist/dt/czim/laravel-filter.svg?style=flat-square\n\n[link-packagist]: https://packagist.org/packages/czim/laravel-filter\n[link-downloads]: https://packagist.org/packages/czim/laravel-filter\n[link-author]: https://github.com/czim\n[link-contributors]: ../../contributors\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fczim%2Flaravel-filter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fczim%2Flaravel-filter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fczim%2Flaravel-filter/lists"}