PHPackages                             survos/api-grid-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. [API Development](/categories/api)
4. /
5. survos/api-grid-bundle

ActiveSymfony-bundle[API Development](/categories/api)

survos/api-grid-bundle
======================

incorporate DatatablesNet, using twig and stimulus, twig\_component requires ^2.2

2.0.182(1mo ago)24.8k↓37.5%[2 issues](https://github.com/survos/SurvosApiGridBundle/issues)MITPHPPHP ^8.4

Since Sep 19Pushed 1mo ago2 watchersCompare

[ Source](https://github.com/survos/SurvosApiGridBundle)[ Packagist](https://packagist.org/packages/survos/api-grid-bundle)[ GitHub Sponsors](https://github.com/kbond)[ RSS](/packages/survos-api-grid-bundle/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (59)Versions (799)Used By (0)

Survos API Grid Bundle
======================

[](#survos-api-grid-bundle)

Render a spreadsheet-like, server-driven DataTables.net grid from an API Platform collection endpoint.

This bundle used to be central across multiple projects. Today the primary goal is simple Doctrine browsing (sorting, searching, filtering) using a single Twig component.

Meilisearch support exists, but the recommended starting point is Doctrine + API Platform.

Install
-------

[](#install)

```
composer req survos/api-grid-bundle
```

Quick Start (Doctrine)
----------------------

[](#quick-start-doctrine)

Doctrine setup
--------------

[](#doctrine-setup)

This bundle is designed to point DataTables at an API Platform collection endpoint. It uses Hydra JSON-LD and a custom paginator that accepts `limit` and `offset`.

### 1) Add QueryBuilder helper to your repository

[](#1-add-querybuilder-helper-to-your-repository)

This enables facet counts for SearchPanes.

```
use Survos\CoreBundle\Traits\QueryBuilderHelperInterface;
use Survos\CoreBundle\Traits\QueryBuilderHelperTrait;

class OfficialRepository extends ServiceEntityRepository implements QueryBuilderHelperInterface
{
    use QueryBuilderHelperTrait;
}
```

### 2) Define columns

[](#2-define-columns)

```
{% set columns = [
    'code',
    'description',
    {name: 'countryCode', sortable: true, browsable: true, searchable: true},
    {name: 'privacyPolicy', browsable: true},
    {name: 'projectLocale', browsable: true},
] %}
```

By default, `sortable`, `browsable`, and `searchable` are false.

### 3) Add filters to the resource

[](#3-add-filters-to-the-resource)

```
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use Survos\ApiGrid\Api\Filter\MultiFieldSearchFilter;
use Survos\ApiGrid\Api\Filter\FacetsFieldSearchFilter;

#[ApiFilter(MultiFieldSearchFilter::class, properties: ['name', 'code'])]
#[ApiFilter(FacetsFieldSearchFilter::class, properties: ['gender', 'state'])]
#[ApiFilter(OrderFilter::class, properties: ['id', 'countryCode'])]
```

### 4) Choose the API route

[](#4-choose-the-api-route)

If your resource has a single collection operation, the grid can infer it. If there are multiple collection operations, pass the `apiRoute` (operation name) explicitly.

```

```

To discover operation names, run:

```
bin/console debug:router | grep api_
```

Or bypass discovery entirely and pass a URL:

```

```

### 5) Pagination settings

[](#5-pagination-settings)

Datatables uses `limit` and `offset`. Ensure API Platform allows client pagination:

```
api_platform:
  collection:
    pagination:
      client_items_per_page: true
      client_enabled: true
```

The recommended approach is:

- pass the entity class from your controller (avoid class strings in Twig)
- pass an explicit API Platform collection URL (`apiGetCollectionUrl`)

### 1) Add a named collection operation constant

[](#1-add-a-named-collection-operation-constant)

Define a route name constant on your ApiResource (this keeps things easy to reason about):

```
// src/Entity/Video.php

use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\ApiResource;

#[ApiResource]
#[GetCollection(name: self::DOCTRINE_ROUTE)]
class Video
{
    public const DOCTRINE_ROUTE = 'api-video';
}
```

### 2) Compute the collection URL in your controller

[](#2-compute-the-collection-url-in-your-controller)

```
// src/Controller/VideoController.php

use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\IriConverterInterface;
use App\Entity\Video;

#[Route(path: '/video/browse', name: 'video_browse', methods: ['GET'])]
public function browse(IriConverterInterface $iriConverter): Response
{
    $apiGetCollectionUrl = $iriConverter->getIriFromResource(
        Video::class,
        operation: new GetCollection(name: Video::DOCTRINE_ROUTE)
    );

    return $this->render('video/browse.html.twig', [
        'class' => Video::class,
        'apiGetCollectionUrl' => $apiGetCollectionUrl,
    ]);
}
```

### 3) Render the grid in Twig

[](#3-render-the-grid-in-twig)

```
{# templates/video/browse.html.twig #}

{% set columns = [
    col('youtubeId'),
    col(name: 'year', sortable: true, browsable: true),
    col(name: 'title', searchable: true, sortable: true),
] %}

```

Notes:

- `browsable: true` marks a field as a SearchPanes facet.
- `:caller="_self"` enables inline `` templates for custom rendering.

EasyAdmin / Sidebar Layouts: ColumnControl
------------------------------------------

[](#easyadmin--sidebar-layouts-columncontrol)

SearchPanes are great, but the left-hand facet sidebar can clash with admin layouts that already have a sidebar (e.g. EasyAdmin).

Enable DataTables ColumnControl instead:

```

```

How it works:

- `browsable: true` columns become ColumnControl `searchList` dropdowns.
- Selections are sent back as `facet_filter[]` so the existing Doctrine filter path is reused.

Backend Setup
-------------

[](#backend-setup)

### Search (global search box)

[](#search-global-search-box)

The JS grid sends a global query as `?search=...`. Enable it with:

```
use ApiPlatform\Metadata\ApiFilter;
use Survos\ApiGridBundle\Api\Filter\MultiFieldSearchFilter;

#[ApiFilter(MultiFieldSearchFilter::class, properties: ['title', 'description'])]
```

### Sorting

[](#sorting)

DataTables sends ordering as `order[field]=asc|desc`, so add API Platform's `OrderFilter`:

```
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;

#[ApiFilter(OrderFilter::class, properties: ['title', 'year'])]
```

### Facets / SearchPanes (Doctrine)

[](#facets--searchpanes-doctrine)

SearchPanes filtering uses `facet_filter[]` (e.g. `school,in,Lincoln|Roosevelt`). Add a filter that understands that parameter.

If you use `Survos\MeiliBundle\Api\Filter\FacetsFieldSearchFilter` in your project, it works fine for Doctrine too.

To generate facet counts for Doctrine SearchPanes, your repository should support counts:

```
use Survos\CoreBundle\Traits\QueryBuilderHelperInterface;
use Survos\CoreBundle\Traits\QueryBuilderHelperTrait;

class VideoRepository extends ServiceEntityRepository implements QueryBuilderHelperInterface
{
    use QueryBuilderHelperTrait;
}
```

Implementation Notes
--------------------

[](#implementation-notes)

See `docs/implementation.md` for how the Twig component, Stimulus controller, API Platform normalizer, and pagination extension fit together.

Dev only
--------

[](#dev-only)

```
composer config repositories.survos_grid_bundle '{"type": "vcs", "url": "git@github.com:survos/SurvosApiGridBundle.git"}'
```

###  Health Score

51

—

FairBetter than 96% of packages

Maintenance70

Regular maintenance activity

Popularity25

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity84

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 100% 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 ~1 days

Total

798

Last Release

50d ago

Major Versions

1.6.9 → 2.0.1102026-02-06

PHP version history (4 changes)v1.2.4PHP ^8.1

1.5.361PHP ^8.2

1.5.396PHP ^8.3

2.0.110PHP ^8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/21b39551f92ed4143772c622f9e571589c5a72c96ab3c53fe67489ce0d83e806?d=identicon)[tacman1123](/maintainers/tacman1123)

---

Top Contributors

[![tacman](https://avatars.githubusercontent.com/u/619585?v=4)](https://github.com/tacman "tacman (23 commits)")

---

Tags

symfony-uxSymfony Bundle

###  Code Quality

Static AnalysisPHPStan, Rector

Type Coverage Yes

### Embed Badge

![Health badge](/badges/survos-api-grid-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/survos-api-grid-bundle/health.svg)](https://phpackages.com/packages/survos-api-grid-bundle)
```

###  Alternatives

[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.4k5.6M651](/packages/sylius-sylius)[prestashop/prestashop

PrestaShop is an Open Source e-commerce platform, committed to providing the best shopping cart experience for both merchants and customers.

9.0k15.4k](/packages/prestashop-prestashop)[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k16.7M310](/packages/easycorp-easyadmin-bundle)[contao/core-bundle

Contao Open Source CMS

1231.6M2.4k](/packages/contao-core-bundle)[ec-cube/ec-cube

EC-CUBE EC open platform.

78527.0k1](/packages/ec-cube-ec-cube)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.3M152](/packages/sulu-sulu)

PHPackages © 2026

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