{"id":13796169,"url":"https://github.com/metaclass-nl/filter-bundle","last_synced_at":"2025-12-24T17:36:37.147Z","repository":{"id":37751395,"uuid":"369457260","full_name":"metaclass-nl/filter-bundle","owner":"metaclass-nl","description":"Filter bundle for API Platform, Filter Logic","archived":false,"fork":false,"pushed_at":"2024-01-12T13:40:56.000Z","size":106,"stargazers_count":47,"open_issues_count":5,"forks_count":9,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-05-19T03:09:43.039Z","etag":null,"topics":["api-platform","doctrine","doctrine-orm","filter","logic","wherefilter"],"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/metaclass-nl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2021-05-21T07:52:03.000Z","updated_at":"2024-06-25T13:39:37.083Z","dependencies_parsed_at":"2022-08-08T21:31:01.787Z","dependency_job_id":"da5f939c-02c9-485b-b1aa-8a136439aed5","html_url":"https://github.com/metaclass-nl/filter-bundle","commit_stats":{"total_commits":33,"total_committers":2,"mean_commits":16.5,"dds":0.09090909090909094,"last_synced_commit":"8c0efddcccfa2d4ee9c7884cd46e0f117643d527"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaclass-nl%2Ffilter-bundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaclass-nl%2Ffilter-bundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaclass-nl%2Ffilter-bundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metaclass-nl%2Ffilter-bundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/metaclass-nl","download_url":"https://codeload.github.com/metaclass-nl/filter-bundle/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225159848,"owners_count":17430191,"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":["api-platform","doctrine","doctrine-orm","filter","logic","wherefilter"],"created_at":"2024-08-03T23:01:07.028Z","updated_at":"2025-12-24T17:36:37.138Z","avatar_url":"https://github.com/metaclass-nl.png","language":"PHP","funding_links":[],"categories":["Table of Contents"],"sub_categories":["awesome-api-platform-bundles"],"readme":"Maybe obsolete as of API Platform 4.2? See [this issue](https://github.com/metaclass-nl/filter-bundle/issues/23).\n\nFilter logic for API Platform\n=============================\nCombines API Platform ORM Filters with AND, OR and NOT according to client request.\n- supports nested logic (like parentheses in SQL)\n- supports multiple criteria for the same property\n- existing requests keep working unmodified if not using \"and\", \"or\" or \"not\" as query parameters.\n- works with built-in filters of Api Platform, except for DateFilter\n  with EXCLUDE_NULL. A DateFilter subclass is provided to correct this.\n- For security reasons as of version 2.0 criteria from extensions and filters that\n  are not nested in \"and\", \"or\" or \"not\" are always combined through AND with the criteria\n  added by LogicFilter\n\nUsage\n-----\nOnce the FilterLogic class and service configuration have been installed in you app,\njust add it as the last ApiFilter annotation. Then make a request with filter parameters nested in and/or in the query string.\n\nFor example if you have:\n```php8\n#[ApiResource]\n#[ApiFilter(SearchFilter::class, properties: ['id' =\u003e 'exact', 'price' =\u003e 'exact', 'description' =\u003e 'partial'])]\n#[ApiFilter(FilterLogic::class)]\nclass Offer {\n// ...\n}\n```\nCalling the collection get operation with:\n```uri\n/offers/?or[price]=10\u0026or[description]=shirt\n```\nwill return all offers with a price being exactly 10 OR a description containing the word \"shirt\".\n\nNOT expressions are combined like the other expressions through the compound logic (and, or) they are nested in:\n```uri\n/offers/?or[not][price]=10\u0026or[not][description]=shirt\n```\nwill return (all offers with a price not being 10) OR (a description NOT containing the word \"shirt\").\nIf they are not nested in compound logic AND is used:\n\nYou can have nested logic and multiple criteria for the same property like this:\n```uri\n/offers/?and[price]=10\u0026and[][description]=shirt\u0026and[][description]=cotton\n```\nThe api will return all offers with a price being exactly 10 AND\n(a description containing the word \"shirt\" AND the word \"cotton\").\n\nExpressions that are nested in \"and\", \"or\" or \"not\" are always combined with normal\nexpressions by AND. For example:\n```uri\n/offers/?price=10\u0026not[description]=shirt\n```\nwill return all offers with a price being exactly 10 AND a description NOT containing the word \"shirt\".\n\n```uri\n/offers/?price=10\u0026or[][description]=shirt\u0026or[][description]=cotton\n```\nwill return all offers with a price being exactly 10 AND\n(a description containing the word \"shirt\" OR the word \"cotton\").\nSo this is the same as:\n```uri\n/offers/?and[price]=10\u0026and[or][][description]=shirt\u0026and[or][][description]=cotton\n```\nThis may be counterintuitive, but it is necessary because the querybuilder may also contain\nexpressions from extensions that limit access to the data for security and if those\nare combined through OR they can be bypassed by the client.\n\nIf you want them to be combined by or, move them to be nested in \"or\":\n```uri\n/offers/?or[price]=10\u0026or[][description]=shirt\u0026or[][description]=cotton\n```\nThe api will then return all offers with a price being exactly 10\nOR a description containing the word \"shirt\"\nOR a description containing the word \"cotton\".\n\n\nYou can in/exclude filters by class name by configuring classExp. For example:\n```php docblock\n* @ApiFilter(FilterLogic::class, arguments={\"classExp\"=\"/ApiPlatform\\\\Core\\\\Bridge\\\\Doctrine\\\\Orm\\\\Filter\\\\+/\"})\n```\nwill only apply API Platform ORM Filters in logic context.\n\nInstallation\n------------\nThis version is for Api Platform 4; and 3 \u003e= 3.2 with `metadata_backward_compatibility_layer` set to false\n```shell\ncomposer require metaclass-nl/filter-bundle \"^4.0\"\n```\n\nThen add the bundle to your api config/bundles.php:\n```php8\n    // (...)\n    Metaclass\\FilterBundle\\MetaclassFilterBundle::class =\u003e ['all' =\u003e true],\n];\n```\n\nIf you are using api-platform/core or Api Platform \u003c v4.0.8 and get ambiguous class\nresolution warning messages, please use Metaclass FilterBundle v3.4.\n\nNested properties workaround\n----------------------------\n\nThe built-in filters of Api Platform normally generate INNER JOINs. As a result\ncombining them with OR may not produce results as expected for properties\nnested over nullable and to many associations, see [this issue](https://github.com/metaclass-nl/filter-bundle/issues/2).\n\nAs a workaround FilterLogic can convert all inner joins into left joins:\n```php8\n#[ApiResource]\n#[ApiFilter(SearchFilter::class, properties: ['title' =\u003e 'partial', 'keywords.word' =\u003e 'exact'])]\n#[ApiFilter(FilterLogic::class, arguments: ['innerJoinsLeft' =\u003e true])]\nclass Article {\n// ...\n}\n```\n\u003cb\u003eSECURITY WARNING\u003c/b\u003e: do not use this option if the working of any of the extensions\nyou use relies on INNER JOINS selecting only rows with NOT NULL values!\n\nIn case you do not like FilterLogic messing with the joins you can make\nthe built-in filters of Api Platform generate left joins themselves by first adding\na left join and removing it later:\n```php8\n#[ApiResource]\n#[ApiFilter(AddFakeLeftJoin::class)]\n#[ApiFilter(SearchFilter::class, properties: ['title' =\u003e 'partial', 'keywords.word' =\u003e 'exact'])]\n#[ApiFilter(FilterLogic::class)]\n#[ApiFilter(RemoveFakeLeftJoin::class)]\nclass Article {\n// ...\n}\n```\n\u003cb\u003eSECURITY WARNING\u003c/b\u003e: Extensions that use ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Util\\QueryBuilderHelper::addJoinOnce\nor ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\PropertyHelperTrait::addJoinsForNestedProperty\nmay not have been intended to generate left joins instead of inner joins. Of course this would\ntechnically be their error, not yours, but still it is better to prevent an eventual breach of security\nthen having to deal with the consequences.\n\n\nWith one fo these workarounds the following will find Articles whose title contains 'pro'\nas well as those whose keywords contain one whose word is 'php'.\n```uri\n/articles/?or[title]=pro\u0026or[keywords.word]=php\n```\nWithout a workaround Articles without any keywords will not be found,\neven if their titles contain 'pro'.\n\nBoth workarounds do change the behavior of ExistsFilter =false with nested properties.\nNormally this filter only finds entities that reference at least one entity\nwhose nested property contains NULL, but with left joins it will also find entities\nwhose reference itself is empty or NULL. This does break backward compatibility.\nThis can be solved by extending ExistsFilter, but that is not included\nin this Bundle because IMHO the old behavior is not like one would expect given\nthe semantics of \"exists\" and therefore should be considered a bug unless it is\ndocumented explicitly to be intentional.\n\nLimitations\n-----------\nCombining filters through OR and nested logic may be a harder task for your\ndatabase and require different indexes. Except for small tables performance\ntesting and analysis is advisable prior to deployment.\n\nThe built-in filters of Api Platform IMHO contain a bug with respect to the JOINs\nthey generate. As a result, combining them with OR does not work as expected with properties\nnested over to-many and nullable associations. Workarounds are provided, but they\ndo change the behavior of ExistsFilter =false.\n\nAssumes that filters create \u003cb\u003esemantically complete expressions\u003c/b\u003e in the sense that\nexpressions added to the QueryBuilder through ::andWhere or ::orWhere do not depend\non one another so that the intended logic is not compromised if they are recombined\nwith the others by either Doctrine\\ORM\\Query\\Expr\\Andx or Doctrine\\ORM\\Query\\Expr\\Orx.\n\nMay Fail if a filter or extension uses QueryBuilder::where or ::add.\n\nYou are advised to check the code of all custom and third party Filters and\nnot to combine those that use QueryBuilder::where or ::add with FilterLogic\nor that produce complex logic that is not semantically complete. For an\nexample of semantically complete and incomplete expressions see [DateFilterTest](./tests/Filter/DateFilterTest.php).\n\nBe aware that new features added to existing filters (From API Platform or third parties)\nmay make them create semantically incomplete expressions or use ::where or ::add giving \u003cb\u003eunexpected results\nor incorrect SQL when combined through FilterLogic\u003c/b\u003e. Semantic versioning only requires minor new versions\nfor new features, so \u003cb\u003egiven the composer.json of this package composer will install them unless you\nlimit those packages to the minor versions you have tested with\u003c/b\u003e.\n\nCredits and License\n-------------------\nCopyright (c) [MetaClass](https://www.metaclass.nl/), Groningen, 2021. [MetaClass](https://www.metaclass.nl/) offers software development and support in the Netherlands for Symfony, API Platform, React.js and Next.js\n\n[MIT License](./LICENSE).\n\n[API Platform](https://api-platform.com/) is a product of [Les-Tilleuls.coop](https://les-tilleuls.coop)\ncreated by [Kévin Dunglas](https://dunglas.fr).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetaclass-nl%2Ffilter-bundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetaclass-nl%2Ffilter-bundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetaclass-nl%2Ffilter-bundle/lists"}