PHPackages                             ericgansa/filter-manager-bundle - 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. [Database &amp; ORM](/categories/database)
4. /
5. ericgansa/filter-manager-bundle

ActiveSymfony-bundle[Database &amp; ORM](/categories/database)

ericgansa/filter-manager-bundle
===============================

Symfony bundle for dynamic filtering, pagination and user-scoped queries with Doctrine ORM

v1.0.1(1mo ago)011↓100%MITPHPPHP &gt;=8.2CI passing

Since Mar 13Pushed 1mo agoCompare

[ Source](https://github.com/Magikmagnum/FilterManager)[ Packagist](https://packagist.org/packages/ericgansa/filter-manager-bundle)[ RSS](/packages/ericgansa-filter-manager-bundle/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (14)Versions (3)Used By (0)

FilterManagerBundle
===================

[](#filtermanagerbundle)

Symfony bundle for dynamic filtering, pagination and user-scoped queries with Doctrine ORM.

Supports a friendly query string notation:

```
GET /api/articles?title[like]=Symfony&author->name=Alice&date[after]=2024-01-01&page=1&limit=20&scope=mine

```

Requirements
------------

[](#requirements)

- PHP 8.2+
- Symfony 6.4 or 7.x
- Doctrine ORM 2.15+ or 3.x

Security is optional. The bundle works without `symfony/security-bundle`. When SecurityBundle is not installed, user-scoped filtering (`mine`/`others`) is silently disabled.

---

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

[](#installation)

```
composer require ericgansa/filter-manager-bundle
```

Register the bundle in `config/bundles.php` (auto-registered via Symfony Flex):

```
EricGansa\FilterManagerBundle\FilterManagerBundle::class => ['all' => true],
```

---

Configuration
-------------

[](#configuration)

Create `config/packages/filter_manager.yaml`:

```
filter_manager:
    # Maximum items per page — prevents ?limit=99999 abuse. Default: 100
    max_limit: 100

    # Entity field linking to the owner user. Default: 'user'
    scope_field: user

    # Query string scope names — fully customizable
    scopes:
        mine: 'mine'       # ?scope=mine   → only current user's items
        others: 'others'   # ?scope=others → exclude current user's items
        all: 'all'         # ?scope=all    → no user filter (default)
```

---

Usage
-----

[](#usage)

### 1. In a Repository (via trait)

[](#1-in-a-repository-via-trait)

```
use EricGansa\FilterManagerBundle\Filter\FilterManagerTrait;

class ArticleRepository extends ServiceEntityRepository
{
    use FilterManagerTrait;
}
```

### 2. In a Controller

[](#2-in-a-controller)

```
use EricGansa\FilterManagerBundle\Filter\FilterManager;

class ArticleController extends AbstractController
{
    public function __construct(private readonly FilterManager $filterManager) {}

    #[Route('/api/articles', methods: ['GET'])]
    public function index(Request $request, ArticleRepository $repository): JsonResponse
    {
        $articles = $this->filterManager->mapRequestToRepository(
            $request,
            $repository,
            'findByFilterManager'  // method from FilterManagerTrait
        );

        return $this->json($articles);
    }
}
```

### 3. Manual usage (without the trait)

[](#3-manual-usage-without-the-trait)

```
$qb = $repository->createQueryBuilder('e');

FilterManager::applyFiltersToQueryBuilder($qb, $filters, 'e');
FilterManager::applyPaginationToQueryBuilder($qb, $pagination, 'e');

// With configured scope (uses bundle config)
$filterManager->applyScopeWithConfig($qb, $scope, $user, 'e');
```

---

Query String Reference
----------------------

[](#query-string-reference)

### Example Entity

[](#example-entity)

The following examples are based on this `Article` entity:

```
#[ORM\Entity(repositoryClass: ArticleRepository::class)]
class Article
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private int $id;

    #[ORM\Column(type: Types::TEXT)]
    private string $description;

    #[ORM\ManyToOne(targetEntity: Label::class)]
    private Label $label;

    #[ORM\ManyToOne(targetEntity: User::class)]
    private User $user;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
    private \DateTimeImmutable $createdAt;
}
```

All query string examples in this section filter against this entity. The `label` relation points to a `Label` entity with its own `label` string field. The `user` field is used by the scope system to determine ownership.

---

### Equality

[](#equality)

Filter results where a field exactly matches a value.

```
GET /api/articles?id=5
GET /api/articles?description=Gestion agile...

```

ExampleResult`?id=5`Returns the item whose `id` is exactly `5``?description=Gestion agile...`Returns items with that exact description---

### LIKE (partial match)

[](#like-partial-match)

Filter results where a field contains a substring. Two syntaxes are supported and produce identical results.

```
GET /api/articles?description=%Expert%
GET /api/articles?description[like]=Expert

```

SyntaxExampleNotesInline (with `%`)`?description=%Expert%`Use `%` as wildcard directly in the valueArray`?description[like]=Expert`Cleaner syntax, no need for `%`---

### Greater Than

[](#greater-than)

Filter results where a numeric (or date) field is strictly greater than a value. Two syntaxes are supported.

```
GET /api/articles?id=>5
GET /api/articles?id[after]=5

```

SyntaxExampleNotesInline`?id=>5`Prefix value with `>`Array`?id[after]=5`Uses the `[after]` key---

### Less Than

[](#less-than)

Filter results where a numeric (or date) field is strictly less than a value. Two syntaxes are supported.

```
GET /api/articles?id=` to separate the relation from the field name (e.g. `label->label`). **Do not use `.`** — PHP automatically converts `.` to `_` in query strings, which causes a Doctrine error.

```
GET /api/articles?label->label=Développeur PHP
GET /api/articles?label->label[like]=Développeur

```

ExampleNotes`?label->label=Développeur PHP`Exact match on the related field`?label->label[like]=Développeur`LIKE match on the related field---

### Date Filtering

[](#date-filtering)

Filter results by date using `[after]` and `[before]`. Values must be ISO 8601 date strings. The field must be of type `DateTimeImmutable` (or compatible).

```
GET /api/articles?createdAt[after]=2026-01-01
GET /api/articles?createdAt[before]=2020-01-01

```

ExampleNotes`?createdAt[after]=2026-01-01`Items created after January 1st 2026`?createdAt[before]=2020-01-01`Items created before January 1st 2020---

### Scope (User-based filtering)

[](#scope-user-based-filtering)

Restrict results based on ownership. Requires `symfony/security-bundle` to be installed and a logged-in user. The entity must have a field pointing to the owner (configured via `scope_field`).

```
GET /api/articles?scope=mine
GET /api/articles?scope=others
GET /api/articles?scope=all

```

ValueBehaviour`mine`Returns only items belonging to the currently authenticated user`others`Returns only items **not** belonging to the current user`all`No user filter applied (default behaviour)---

Chaining Filters
----------------

[](#chaining-filters)

All filters can be combined freely in a single query string. Each parameter is applied as an additional `AND` condition on the query.

```
GET /api/articles?label->label[like]=Développeur&id[from]=3&createdAt[after]=2026-01-01&scope=mine

```

This example returns items that:

- have a related label containing `"Développeur"`,
- have an `id` of `3` or more,
- were created after January 1st 2026,
- and belong to the currently authenticated user.

You can mix inline and array syntaxes freely:

```
GET /api/articles?id=>5&description[like]=Expert&scope=all

```

There is no limit to the number of filters that can be chained.

---

License
-------

[](#license)

MIT © Eric Gansa

###  Health Score

40

—

FairBetter than 87% of packages

Maintenance95

Actively maintained with recent releases

Popularity7

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

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 ~2 days

Total

2

Last Release

54d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/8cd976eef4917180a0bbee36c468b91c7a62d6fe4635b4788c32d04786288cbb?d=identicon)[ericGansa](/maintainers/ericGansa)

---

Tags

symfonybundleormdoctrinepaginationqueryfilter

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/ericgansa-filter-manager-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/ericgansa-filter-manager-bundle/health.svg)](https://phpackages.com/packages/ericgansa-filter-manager-bundle)
```

###  Alternatives

[sonata-project/doctrine-orm-admin-bundle

Integrate Doctrine ORM into the SonataAdminBundle

46117.7M154](/packages/sonata-project-doctrine-orm-admin-bundle)[artprima/query-filter-bundle

An easy way to filter requests in your Symfony 4/5/6 application (that uses Doctrine2 as ORM).

2829.6k](/packages/artprima-query-filter-bundle)[onurb/doctrine-yuml-bundle

Symfony Bundle to visualize the mapping of your entities with Yuml

4198.6k](/packages/onurb-doctrine-yuml-bundle)[prezent/doctrine-translatable-bundle

Integrate the doctrine-translatable extension in Symfony

14698.4k5](/packages/prezent-doctrine-translatable-bundle)

PHPackages © 2026

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