PHPackages                             lmc/api-filter - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. lmc/api-filter

ActiveLibrary[API Development](/categories/api)

lmc/api-filter
==============

Parser/builder for filters from API query parameters.

3.0.0(5y ago)84.1k3MITPHPPHP ^8.0CI failing

Since Aug 28Pushed 4y ago4 watchersCompare

[ Source](https://github.com/lmc-eu/api-filter)[ Packagist](https://packagist.org/packages/lmc/api-filter)[ RSS](/packages/lmc-api-filter/feed)WikiDiscussions master Synced 2d ago

READMEChangelog (3)Dependencies (12)Versions (7)Used By (0)

API Filter
==========

[](#api-filter)

[![Latest Stable Version](https://camo.githubusercontent.com/1d3b589cebc1b7b8cd528e1f4232ffc748d82a784e42f65520d3f7fd7ab1c943/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6c6d632f6170692d66696c7465722e737667)](https://packagist.org/packages/lmc/api-filter)[![Build Status](https://camo.githubusercontent.com/a0d0062ffcc2dbd9a289d119d1cb2b09ab0aaa5ee751cea8cf5dd504b590347c/68747470733a2f2f7472617669732d63692e636f6d2f6c6d632d65752f6170692d66696c7465722e7376673f6272616e63683d6d6173746572)](https://travis-ci.com/lmc-eu/api-filter)[![Coverage Status](https://camo.githubusercontent.com/a0673e6ba33ad3d936b02a9aff58db159f346cb4b0b17bfdfd22869651a255e7/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f6c6d632d65752f6170692d66696c7465722f62616467652e7376673f6272616e63683d6d6173746572)](https://coveralls.io/github/lmc-eu/api-filter?branch=master)

Parser/builder for filters from API query parameters.

It is just a parser/builder for filters, it is not a place for business logic so it should be wrapped by your class if you want to be more strict about filters. Same if you want different settings per entity/table, it should be done by a specific wrapper around this library.

Table of Contents
-----------------

[](#table-of-contents)

- [Installation](#installation)
- [Usage](#usage)
    - [Initialization](#initialization)
    - [With Doctrine Query Builder](#with-doctrine-query-builder-applicator)
    - [With simple SQL](#with-sql-applicator)
- [Supported filters](#supported-filters)
    - [Equals](#equals---eq-)
    - [Not Equals](#not-equals---neq-)
    - [Greater than](#greater-than---gt-)
    - [Greater than or Equals](#greater-than-or-equals---gte-)
    - [Lower than](#lower-than---lt-)
    - [Lower than or Equals](#lower-than-or-equals---lte-)
    - [IN](#in)
- [Tuples in filters](#tuples-in-filters)
- [Examples](#examples)
    - [IN + EQ](#in--eq-filter)
    - [GT + LT *(between)*](#gt--lt-filter-between)
    - [EQ `Tuple`](#eq-with-tuple)
- [Functions in filters](#functions-in-filters)
    - [Example for fullName function](#example-for-fullname-function)
    - [Function parameters definition](#function-parameters-definition)
        - [By string](#defined-as-string)
        - [By array](#defined-as-array)
        - [By object](#defined-as-object)
        - [Combinations](#combinations)
    - [Register and Execute function](#register-and-execute-function)
- [Exceptions and error handling](#exceptions-and-error-handling)
- [Development](#development)

Installation
------------

[](#installation)

```
composer require lmc/api-filter
```

Usage
-----

[](#usage)

For example lets have query parameters from following request

```
GET http://host/endpoint/?field=value
```

### Initialization

[](#initialization)

```
// in DI container/factory
$apiFilter = new ApiFilter();
$apiFilter->registerApplicator(...);  // optional, when you want to use non-standard implementation

// in service/controller/...
$filters = $apiFilter->parseFilters($request->query->all());

// [
//     0 => Lmc\ApiFilter\Filter\FilterWithOperator {
//         private $title    => 'eq'
//         private $operator => '='
//         private $column   => 'field'
//         private $value    => Lmc\ApiFilter\Entity\Value {
//             private $value => 'value'
//         }
//     }
// ]
```

### With Doctrine `Query Builder Applicator`

[](#with-doctrine-query-builder-applicator)

- requires `doctrine/orm` installed
- applying filters uses **cloned** `QueryBuilder` -&gt; original `QueryBuilder` is **untouched**

#### Example

[](#example)

```
// in EntityRepository/Model
$queryBuilder = $this->createQueryBuilder('alias');
$queryBuilder = $apiFilter->applyFilters($filters, $queryBuilder);

// or one by one
foreach ($filters as $filter) {
    $queryBuilder = $apiFilter->applyFilter($filter, $queryBuilder);
}

// get prepared values for applied filters
$preparedValues = $apiFilter->getPreparedValues($filters, $queryBuilder); // ['field_eq' => 'value']

// get query
$queryBuilder
    ->setParameters($preparedValues)
    ->getQuery();
```

#### Shorter example (*same as ☝*)

[](#shorter-example-same-as-)

```
// in EntityRepository/Model
$queryBuilder = $this->createQueryBuilder('alias');

$apiFilter
    ->applyFilters($filters, $queryBuilder)                                     // query builder with applied filters
    ->setParameters($apiFilter->getPreparedValues($filters, $queryBuilder)) // ['field_eq' => 'value']
    ->getQuery();
```

### With `SQL Applicator`

[](#with-sql-applicator)

- ❗it is just a **naive implementation** and should be used carefully❗
- it still might be used on simple `SQL`s without `ORDER BY`, `GROUP BY` etc. because it simply adds filters as a `WHERE` conditions

`SQL Applicator` must be registered explicitly

```
// in DI container
$apiFilter->registerApplicator(new SqlApplicator(), Priority::MEDIUM);
```

#### Example

[](#example-1)

```
// in Model/EntityRepository
$sql = 'SELECT * FROM table';
$sql = $apiFilter->applyFilters($filters, $sql); // "SELECT * FROM table WHERE 1 AND field = :field_eq"

// or one by one
foreach ($filters as $filter) {
    $sql = $apiFilter->applyFilter($filter, $sql);
}

// get prepared values for applied filters
$preparedValues = $apiFilter->getPreparedValues($filters, $sql); // ['field_eq' => 'value']

// execute query
$stmt = $connection->prepare($sql);
$stmt->execute($preparedValues);
```

#### Shorter example (*same as ☝*)

[](#shorter-example-same-as--1)

```
// in EntityRepository/Model
$sql = 'SELECT * FROM table';
$stmt = $connection->prepare($apiFilter->applyFilters($filters, $sql)); // SELECT * FROM table WHERE 1 AND field = :field_eq
$stmt->execute($apiFilter->getPreparedValues($filters, $sql));      // ['field_eq' => 'value']
```

Supported filters
-----------------

[](#supported-filters)

### Equals - EQ (=)

[](#equals---eq-)

```
GET http://host/endpoint/?field[eq]=value
GET http://host/endpoint/?field=value
```

*Both examples ☝ are equal*

### Not Equals - NEQ (!=)

[](#not-equals---neq-)

```
GET http://host/endpoint/?field[neq]=value
```

### Greater Than - GT (&gt;)

[](#greater-than---gt-)

```
GET http://host/endpoint/?field[gt]=value
```

### Greater Than Or Equals - GTE (&gt;=)

[](#greater-than-or-equals---gte-)

```
GET http://host/endpoint/?field[gte]=value
```

### Lower Than - LT (&lt;)

[](#lower-than---lt-)

```
GET http://host/endpoint/?field[lt]=value
```

### Lower Than Or Equals - LTE (&lt;=)

[](#lower-than-or-equals---lte-)

```
GET http://host/endpoint/?field[lte]=value
```

### IN

[](#in)

```
GET http://host/endpoint/?type[in][]=one&type[in][]=two
```

- `Tuples` are not allowed in `IN` filter

### Function

[](#function)

```
GET http://host/endpoint?fullName=(Jon,Snow)
```

- there is much more options and possibilities with `functions` which you can see [here](#functions-in-filters)

`Tuples` in filters
-------------------

[](#tuples-in-filters)

`Tuples`

- are important in filters if you have some values, which **must** be sent together
- are composed of two or more values (*`Tuple` of one value is just a value*)
- items **must** be in `(` `)` and separated by `,`
    - `array` in `Tuple` **must** be in `[` `]` and items separated by `;`
- it is advised NOT to use a *space* between values because of the *URL* specific behavior
- for more information about `Tuples` see

### Column with `Tuple`

[](#column-with-tuple)

Columns declared by `Tuple` behaves the same as a single value but its value must be a `Tuple` as well. Columns can contain a filter specification for each value.

- default filter is `EQ` for a single value and `IN` for an array of values (*in `Tuple`*)

### Values with `Tuple`

[](#values-with-tuple)

Values in the `Tuple` must have the same number of items as is the number of columns. Values can contain a filter specification for all values in a `Tuple`.

❗**NOTE**: A filter specification **must not** be in both columns and values.

### Usage

[](#usage-1)

```
GET http://host/endpoint/?(first,second)[eq]=(one,two)
```

☝ means that you have two columns `first` and `second` and they must be sent together. Column `first` must `equal` the value `"one"` and column `second` must `equal` the value `"two"`.

Examples
--------

[](#examples)

❗For simplicity of examples, they are shown on the [`SQL Applicator`](#with-sql-applicator) which is NOT auto-registered❗

### `IN` + `EQ` filter

[](#in--eq-filter)

```
GET http://host/person/?type[in][]=student&type[in][]=admin&name=Tom
```

```
$parameters = $request->query->all();
// [
//     "type" => [
//         "in" => [
//             0 => "student"
//             1 => "admin"
//         ]
//     ],
//     "name" => "Tom"
// ]

$filters = $apiFilter->parseFilters($parameters);
$sql = 'SELECT * FROM person';

foreach ($filters as $filter) {
    $sql = $apiFilter->applyFilter($filter, $sql);

    // 0. SELECT * FROM person WHERE 1 AND type IN (:type_in_0, :type_in_1)
    // 1. SELECT * FROM person WHERE 1 AND type IN (:type_in_0, :type_in_1) AND name = :name_eq
}

$preparedValues = $apiFilter->getPreparedValues($filters, $sql);
// [
//     'type_in_0' => 'student',
//     'type_in_1' => 'admin',
//     'name_eq'   => 'Tom',
// ]
```

### `GT` + `LT` filter (*between*)

[](#gt--lt-filter-between)

```
GET http://host/person/?age[gt]=18&age[lt]=30
```

```
$parameters = $request->query->all();
// [
//     "age" => [
//         "gt" => 18
//         "lt" => 30
//     ],
// ]

$filters = $apiFilter->parseFilters($parameters);
$sql = 'SELECT * FROM person';

$sql = $apiFilter->applyFilters($filters, $sql); // SELECT * FROM person WHERE 1 AND age > :age_gt AND age < :age_lt
$preparedValues = $apiFilter->getPreparedValues($filters, $sql); // ['age_gt' => 18, 'age_lt' => 30]
```

### `EQ` with `Tuple`

[](#eq-with-tuple)

```
GET http://host/person/?(firstname,surname)=(John,Snow)
```

```
$parameters = $request->query->all(); // ["(firstname,surname)" => "(John,Snow)"]

$sql = 'SELECT * FROM person';
$filters = $apiFilter->parseFilters($parameters);
// [
//     0 => Lmc\ApiFilter\Filter\FilterWithOperator {
//         private $title    => "eq"
//         private $operator => "="
//         private $column   => "firstname"
//         private $value    => Lmc\ApiFilter\Entity\Value {
//             private $value => "John"
//         }
//     },
//     1 => Lmc\ApiFilter\Filter\FilterWithOperator {
//         private $title    => "eq"
//         private $operator => "="
//         private $column   => "surname"
//         private $value    => Lmc\ApiFilter\Entity\Value {
//             private $value => "Snow"
//         }
//     }
// ]

$sql = $apiFilter->applyFilters($filters, $sql); // SELECT * FROM person WHERE 1 AND firstname = :firstname_eq AND surname = :surname_eq
$preparedValues = $apiFilter->getPreparedValues($filters, $sql); // ['firstname_eq' => 'John', 'surname_eq' => 'Snow']
```

### More Examples

[](#more-examples)

#### Equals (*implicit and explicit*)

[](#equals-implicit-and-explicit)

```
GET http://host/person/?fullName=Jon Snow
GET http://host/person/?fullName[eq]=Jon Snow
```

Result:

```
-   column: fullName
    filters: eq
    value: Jon Snow
```

#### Multiple filters (*implicit and explicit*)

[](#multiple-filters-implicit-and-explicit)

By single values

```
GET http://host/person/?firstName=Jon&surname=Snow
GET http://host/person/?firstName[eq]=Jon&surname[eq]=Snow
```

By Tuples

```
GET http://host/person/?(firstName,surname)=(Jon,Snow)
GET http://host/person/?(firstName,surname)[eq]=(Jon,Snow)
GET http://host/person/?(firstName[eq],surname[eq])=(Jon,Snow)
```

Result:

```
-   column: firstName
    filters: eq
    value: Jon

-   column: surname
    filters: eq
    value: Snow
```

#### Multiple filters

[](#multiple-filters)

You can mix all types of filters (*tuples, explicit, implicit*).

##### *Perfect wife* by generic filters

[](#perfect-wife-by-generic-filters)

By single values

```
GET http://host/person/?age[gte]=18&age[lt]=30&category[in][]=serious&category[in][]=marriage&sense-of-humor=true
```

By Tuples

```
GET http://host/person/?(age[gte],age[lt],category,sense-of-humor)=(18,30,[serious;marriage],true)
```

Result:

```
-   column: age
    filters: gte
    value: 18

-   column: age
    filters: lt
    value: 30

-   column: category
    filters: in
    value: [ serious, marriage ]

-   column: sense-of-humor
    filters: eq
    value: true
```

##### *Want to see movies* by generic filters

[](#want-to-see-movies-by-generic-filters)

By single values

```
GET http://host/movie/?year[gte]=2018&rating[gte]=80&genre[in][]=action&genre[in][]=fantasy
```

By Tuples

```
GET http://host/movie/?(year[gte],rating[gte],genre)=(2018,80,[action;fantasy])
```

Result:

```
-   column: year
    filters: gte
    value: 2018

-   column: rating
    filters: gte
    value: 80

-   column: genre
    filters: in
    value: [ action, fantasy ]
```

Functions in filters
--------------------

[](#functions-in-filters)

With function you can handle all kinds of problems, which might be problematic with just a simple filters like `eq`, etc.

### Example for `fullName` function

[](#example-for-fullname-function)

Let's see how to work with functions and what is required to do. We will show it right on the example.

#### Expected api

[](#expected-api)

```
GET http://host/endpoint?fullName=(Jon,Snow)
```

☝️ example above shows what we want to offer to our consumers. It's easy and explicit enough.

It may even hide some inner differences, for example with simple filters, database column must have same name as field in filter, but with function, we can change it.

Let's say that in database we have something like:

```
type Person = {
    first_name: string
    lastname: string
}
```

#### Initialization

[](#initialization-1)

First of all, you have to define functions you want to use.

```
// in DI container/factory
$apiFilter = new ApiFilter();

$apiFilter->declareFunction(
    'fullName',
    [
        new ParameterDefinition('firstName', 'eq', 'first_name'),   // parameter name and field name are different, so we need to define it
        'lastname`,              // parameter name and field name are the same and we use the implicit `eq` filter, so it is defined simply
    ]
);
```

Method `declareFunction` will create a function with filters based on parameters.
*There is also `registerFunction` method, which allows you to pass any function you want. This may be useful when you dont need filter functionality at all or have some custom storage, etc.*

#### Parsing and applying filters

[](#parsing-and-applying-filters)

Now when request with `?fullName=(Jon,Snow)` come, `ApiFilter` can parse it to:

```
// in service/controller/...
$sql = 'SELECT * FROM person';

$filters = $apiFilter->parseFilters($request->query->all());
// [
//      0 => Lmc\ApiFilter\Filter\FilterFunction {
//        private $title  => 'function'
//        private $column => 'fullName'
//        private $value  => Lmc\ApiFilter\Entity\Value {
//          private $value => Closure
//        }
//      },
//
//      1 => Lmc\ApiFilter\Filter\FunctionParameter {
//        private $title => 'function_parameter'
//        private $column => 'firstName'
//        private $value => Lmc\ApiFilter\Entity\Value {
//          private $value => 'Jon'
//        }
//      },
//
//      2 => Lmc\ApiFilter\Filter\FunctionParameter {
//        private $title => 'function_parameter'
//        private $column => 'lastname'
//        private $value => Lmc\ApiFilter\Entity\Value {
//          private $value => 'Snow'
//        }
//      }
// ]

$appliedSql = $apiFilter->applyFilters($filters, $sql);
// SELECT * FROM person WHERE first_name = :firstName_function_parameter AND lastname = :lastname_function_parameter

$preparedValues = $apiFilter->getPreparedValues($filters, $sql);
// [
//      'firstName_function_parameter' => 'Jon',
//      'lastname_function_parameter' => 'Snow',
// ]
```

#### Supported function usage

[](#supported-function-usage)

All examples below results the same. We have that many options, so we can allow as many different consumers as possible.

```
### Explicit function call
GET http://host/endpoint?fullName=(Jon,Snow)

### Explicit function call with values
GET http://host/endpoint?function=fullName&firstName=Jon&lastname=Snow

### Implicit function call by values
GET http://host/endpoint?firstName=Jon&lastname=Snow

### Explicit function call by tuple
GET http://host/endpoint?(function,firstName,surname)=(fullName, Jon, Snow)

### Implicit function call by tuple
GET http://host/endpoint?(firstName,surname)=(Jon, Snow)

### Explicit function call by filter parameter
GET http://host/endpoint?filter[]=(fullName,Jon,Snow)
```

### Function Parameters Definition

[](#function-parameters-definition)

To `declare` or `register` function, you have to define its parameters. There are many ways/needs to do it.

#### Defined as string

[](#defined-as-string)

This is the easiest way to do it. You just define a name.

It means:

- you want `eq` filter (*or `IN` for array*) and the column name and parameter name are the same
- the value for this parameter is mandatory

```
$apiFilter->declareFunction('fullName', ['firstName', 'surname']);
```

#### Defined as array

[](#defined-as-array)

This allows you to pass more options for a paramater.

##### Only one item

[](#only-one-item)

If you declare it just by giving the only item, it is the same as definition by string above.

```
$apiFilter->declareFunction('fullName', [['firstName'], ['surname']]);
```

##### More than one item

[](#more-than-one-item)

It means

- `firstName` parameter uses `eq` filter, has `first_name` column in storage and is mandatory
- `surname` parameter uses `eq` filter, has `lastname` column in storage and its value is `Snow` (*which will always be used and no value can override it*)

```
$apiFilter->declareFunction('fullName', [
    ['firstName', 'eq', 'first_name'],
    ['surname', 'eq', 'lastname', 'Snow']
]);
```

#### Defined as object

[](#defined-as-object)

This allows you to pass same options as with the array, but explicitly defined object. (*It even has some special constructor methods to simplify creation*)

```
$apiFilter->declareFunction('fullName', [
    new ParameterDefinition('firstName', 'eq', 'first_name'),
    new ParameterDefinition('surname', 'eq', 'lastname, new Value('Snow'))
]);
```

#### Combinations

[](#combinations)

All options can be combined to best suite the parameter.

##### Declaration

[](#declaration)

```
$apiFilter->declareFunction('fullNameGrownMan', [
    ['firstName', 'eq', 'first_name'],
    'surname',
    ['age', 'gte', 'age', 18],
    ParameterDefinition::equalToDefaultValue('gender', new Value('male')),
]);
```

##### Usage

[](#usage-2)

```
GET http://endpoint/host?fullNameGrownMan=(Jon,Snow)
```

### Register and Execute function

[](#register-and-execute-function)

Example below is just for explicit demonstration, you should probably never allow execute SQL queries like this.

#### Usage in PHP

[](#usage-in-php)

```
// in DI container/factory
$apiFilter = new ApiFilter();

$apiFilter->registerFunction(
    'sql',
    ['query'],
    function (\PDO $client, FunctionParameter $query): \PDOStatement {
        return $client->query($query->getValue()->getValue());
    }
);

// in service/controller/...
$statement = $apiFilter->executeFunction('sql', $queryParameters, $client);    // \PDOStatement

$statement->execute();
// fetch result, etc...
```

#### Usage of the API

[](#usage-of-the-api)

All examples below results the same. We have that many options, so we can allow as many different consumers as possible.

```
### Explicit function call
GET http://endpoint/host?sql=SELECT * FROM person

### Explicit function call with values
GET http://host/endpoint?function=sql&query=SELECT * FROM person

### Implicit function call by values
GET http://host/endpoint?query=SELECT * FROM person

### Explicit function call by tuple
GET http://host/endpoint?(function,query)=(sql, SELECT * FROM person)

### Explicit function call by filter parameter
GET http://host/endpoint?filter[]=(sql, SELECT * FROM person)
```

Exceptions and error handling
-----------------------------

[](#exceptions-and-error-handling)

*Known* exceptions occurring inside ApiFilter implements `Lmc\ApiFilter\Exception\ApiFilterExceptionInterface`. The exception tree is:

ExceptionThrown whenApiFilterExceptionInterfaceCommon interface of all ApiFilter exceptions└ InvalidArgumentExceptionBase exception for assertion failed└ UnknownFilterExceptionUnknown filter is used in query parameters└ UnsupportedFilterableExceptionThis exception will be thrown when no *applicator* supports given *filterable*.└ UnsupportedFilterExceptionThis exception should not be thrown on the client side. It is meant for developing an ApiFilter library - to ensure all Filter types are supported.└ TupleExceptionCommon exception for all problems with a `Tuple`. It also implements `MF\Collection\Exception\TupleExceptionInterface` which might be thrown inside parsing.Please note if you register a custom *applicator* to the ApiFilter (via `$apiFilter->registerApplicator()`), it may throw other exceptions which might not implement `ApiFilterExceptionInterface`.

Development
-----------

[](#development)

### Install

[](#install)

```
composer install
```

### Tests

[](#tests)

```
composer all
```

Todo
----

[](#todo)

- defineAllowed: (*this should be on DI level*)
    - Fields (columns)
    - Filters
    - Values
- add more examples:
    - different configuration per entity/table

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity25

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity72

Established project with proven stability

 Bus Factor1

Top contributor holds 94.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~196 days

Recently: every ~91 days

Total

6

Last Release

1883d ago

Major Versions

1.1.0 → 2.0.02020-05-06

2.2.0 → 3.0.02021-05-06

PHP version history (4 changes)1.0.0PHP ^7.1

2.0.0PHP ^7.3

2.2.0PHP ^7.4

3.0.0PHP ^8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/a3e1e022cb274083d701b31cb634779f7f4a4e6464fa56a3d0b55f7f4a2487b9?d=identicon)[OndraM](/maintainers/OndraM)

![](https://www.gravatar.com/avatar/2bdf0b9957c08a48e70a52fce74fc4f1add30b12d442450d5e2b48854fc98b21?d=identicon)[MortalFlesh](/maintainers/MortalFlesh)

---

Top Contributors

[![MortalFlesh](https://avatars.githubusercontent.com/u/6317184?v=4)](https://github.com/MortalFlesh "MortalFlesh (153 commits)")[![OndraM](https://avatars.githubusercontent.com/u/793041?v=4)](https://github.com/OndraM "OndraM (5 commits)")[![legendik](https://avatars.githubusercontent.com/u/2327491?v=4)](https://github.com/legendik "legendik (4 commits)")

---

Tags

apiapi-filterfilterjson-apiphpquerystring

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/lmc-api-filter/health.svg)

```
[![Health](https://phpackages.com/badges/lmc-api-filter/health.svg)](https://phpackages.com/packages/lmc-api-filter)
```

###  Alternatives

[flix-tech/confluent-schema-registry-api

A PHP 7.4+ library to consume the Confluent Schema Registry REST API.

484.4M3](/packages/flix-tech-confluent-schema-registry-api)[dfridrich/ares

Communication with ARES (Czech business register)

24401.8k2](/packages/dfridrich-ares)[taluu/behapi

Test your remote api locally through Behat

3212.6k](/packages/taluu-behapi)[lmc/matej-client

API Client for Matej recommendation engine

1164.4k](/packages/lmc-matej-client)[armetiz/airtable-php

Manipulate Airtable API using PHP

209.2k](/packages/armetiz-airtable-php)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
