PHPackages                             flytachi/winter-mui-data-grid - 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. [Search &amp; Filtering](/categories/search)
4. /
5. flytachi/winter-mui-data-grid

ActiveLibrary[Search &amp; Filtering](/categories/search)

flytachi/winter-mui-data-grid
=============================

Server-side MUI DataGrid adapter for Winter Framework (K2) — declarative schema: pagination, filtering, sorting and column whitelisting out of the box.

v2.0.0(1mo ago)050↓75.8%MITPHPPHP &gt;=8.4

Since Mar 31Pushed 1mo agoCompare

[ Source](https://github.com/Flytachi/winter-mui-data-grid)[ Packagist](https://packagist.org/packages/flytachi/winter-mui-data-grid)[ Docs](https://winterframe.net)[ RSS](/packages/flytachi-winter-mui-data-grid/feed)WikiDiscussions main Synced 4w ago

READMEChangelog (2)Dependencies (6)Versions (6)Used By (0)

Winter MUI Data Grid
====================

[](#winter-mui-data-grid)

[![Latest Version on Packagist](https://camo.githubusercontent.com/579ebe594b37820f5177f48443f083664c66bba1cf1dfb054d3476f767c4a9aa/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f666c7974616368692f77696e7465722d6d75692d646174612d677269642e737667)](https://packagist.org/packages/flytachi/winter-mui-data-grid)[![Software License](https://camo.githubusercontent.com/074b89bca64d3edc93a1db6c7e3b1636b874540ba91d66367c0e5e354c56d0ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e737667)](LICENSE)[![PHP](https://camo.githubusercontent.com/9c2f8ad80d34105266a94c4c06234f8ed18c968d3595039c2d9a7becd1e71c8b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344382e342d626c75652e737667)](https://www.php.net)

Server-side adapter that connects [MUI X DataGrid](https://mui.com/x/react-data-grid/)to the [Winter Framework](https://winterframe.net) (K2).

You declare a **column schema** — which fields may be filtered and sorted, and how they map to SQL. The library takes the grid's request (page, sort model, filter model), enforces that schema as a whitelist, builds a parameterized query on top of your repository, and returns a `{ rowCount, rows }` payload the DataGrid understands. SQL-injection safe by construction.

```
$schema = GridSchema::make(
    GridColumn::for('title',      'a.title')->filterable(FilterType::String)->sortable(),
    GridColumn::for('views',      'a.views')->filterable(FilterType::Number)->sortable(),
    GridColumn::for('authorName', 'au.name')->filterable(FilterType::String)->sortable(),
)->defaultOrder('a.created_at DESC');

return MuiGrid::wrap($repo, $request, $schema)->toArray();
```

---

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

[](#requirements)

- PHP &gt;= 8.4
- [flytachi/winter-kernel](https://packagist.org/packages/flytachi/winter-kernel) ^3.0

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

[](#installation)

```
composer require flytachi/winter-mui-data-grid
```

---

How it works (60 seconds)
-------------------------

[](#how-it-works-60-seconds)

A grid request has three moving parts: **pagination**, **sorting** and **filtering**. This library handles all three around a query you build yourself:

```
   ┌─────────────────────── your code ───────────────────────┐
   │ build repo: SELECT + JOINs + base WHERE                  │
   │ declare GridSchema: field → SQL, filter type, sortable   │
   └──────────────────────────┬──────────────────────────────┘
                              │  MuiGrid::wrap(repo, request, schema, mapper?)
   ┌──────────────────────────▼──────────────────────────────┐
   │ library:                                                 │
   │  • validate filters against the schema (whitelist)       │
   │  • append WHERE (filters) + ORDER BY (sort) to your repo  │
   │  • run COUNT + paginated SELECT                           │
   │  • map each row (optional) → MuiGridResponse{rowCount,rows}│
   └─────────────────────────────────────────────────────────┘

```

The schema is the contract: a field the frontend references that you did **not**declare is rejected (for filtering) or ignored (for sorting). Operators are gated by each column's `FilterType`, so a text operator can't be sent against a numeric column.

---

Quick start
-----------

[](#quick-start)

A minimal "list articles" endpoint. Two tables: `articles a` joined to `authors au`.

### 1. Request

[](#1-request)

Extend `MuiGridRequest`. The grid envelope (`page`, `pageSize`, `sortModel`, `filterModel`) is hydrated for you by the K2 request layer — add only your own domain filters:

```
use Flytachi\Winter\K2\Http\Request\Validation\ListOf;
use Flytachi\Winter\K2\Http\Request\Validation\Valid;
use Flytachi\Winter\MuiDataGrid\Entity\MGFilterModel;
use Flytachi\Winter\MuiDataGrid\Entity\MGSortItem;
use Flytachi\Winter\MuiDataGrid\MuiGridRequest;

class ArticleGridRequest extends MuiGridRequest
{
    public function __construct(
        public ?int $authorId = null,            // a domain filter of your own

        int $page = 0,
        int $pageSize = 20,
        #[ListOf(MGSortItem::class)] array $sortModel = [],
        #[Valid] MGFilterModel $filterModel = new MGFilterModel(),
    ) {
        parent::__construct($page, $pageSize, $sortModel, $filterModel);
    }
}
```

### 2. Service

[](#2-service)

You own the query; the library overlays the grid concerns:

```
use Flytachi\Winter\Cdo\Qb;
use Flytachi\Winter\MuiDataGrid\MuiGrid;
use Flytachi\Winter\MuiDataGrid\MuiGridResponse;
use Flytachi\Winter\MuiDataGrid\Schema\FilterType;
use Flytachi\Winter\MuiDataGrid\Schema\GridColumn;
use Flytachi\Winter\MuiDataGrid\Schema\GridSchema;

class ArticleService
{
    public function grid(ArticleGridRequest $request): MuiGridResponse
    {
        $repo = ArticleRepository::instance('a')
            ->select('a.id, a.title, a.views, a.created_at, au.name author_name')
            ->joinLeft(AuthorRepository::instance('au'), 'au.id = a.author_id')
            ->where(Qb::eq('a.is_published', true));

        if ($request->authorId) {
            $repo->andWhere(Qb::eq('a.author_id', $request->authorId));
        }

        $schema = GridSchema::make(
            GridColumn::for('title',      'a.title')->filterable(FilterType::String)->sortable(),
            GridColumn::for('views',      'a.views')->filterable(FilterType::Number)->sortable(),
            GridColumn::for('authorName', 'au.name')->filterable(FilterType::String)->sortable(),
            GridColumn::for('createdAt',  'a.created_at')->filterable(FilterType::Date)->sortable(),
        )->defaultOrder('a.created_at DESC');

        return MuiGrid::wrap($repo, $request, $schema);
    }
}
```

### 3. Controller

[](#3-controller)

```
#[PostMapping]
public function grid(
    #[RequestJson, Valid] ArticleGridRequest $request
): ResponseEntity {
    return ResponseEntity::ok(
        $this->service->grid($request)->toArray()
    );
}
```

### 4. The request the frontend sends

[](#4-the-request-the-frontend-sends)

```
{
  "page": 0,
  "pageSize": 25,
  "sortModel": [{ "field": "views", "sort": "desc" }],
  "filterModel": {
    "logicOperator": "and",
    "items": [
      { "field": "title",      "operator": "contains", "value": "winter" },
      { "field": "authorName", "operator": "equals",   "value": "Ada" }
    ]
  }
}
```

### 5. The response

[](#5-the-response)

```
{
  "rowCount": 134,
  "rows": [
    { "id": 12, "title": "Winter internals", "views": 9001, "author_name": "Ada" }
  ]
}
```

`rowCount` is the total matching the filter (for the grid's pager); `rows` is the current page.

---

Documentation
-------------

[](#documentation)

GuideWhat's inside[Getting started](docs/01-getting-started.md)End-to-end walkthrough, request/response shape, frontend wiring.[Schema &amp; columns](docs/02-schema.md)`GridSchema`, `GridColumn`, mapping fields to SQL, whitelisting.[Filtering](docs/03-filtering.md)`FilterType`, operator gating, per-column overrides, AND/OR logic.[Sorting](docs/04-sorting.md)Sort model, custom ORDER BY expressions, default order.[Requests &amp; responses](docs/05-requests-and-responses.md)Extending `MuiGridRequest`, the entity DTOs, `MuiGridResponse`.[Recipes](docs/06-recipes.md)Joins, subquery search, mappers, category-tree / EXISTS patterns.---

At a glance
-----------

[](#at-a-glance)

```
// Entry point
MuiGrid::wrap(
    RepositoryViewInterface $repo,     // your pre-built query (SELECT/JOIN/base WHERE)
    MuiGridRequest          $request,  // the grid request DTO
    GridSchema              $schema,   // the filter/sort whitelist  (required)
    ?callable               $mapper = null,  // optional fn(object $row): mixed
): MuiGridResponse;                    // { rowCount, rows }  (JsonSerializable)
```

```
// Schema building blocks
GridColumn::for('muiField', 'sql.column')
    ->filterable(FilterType::String)         // allow filtering, gate operators by type
    ->sortable()                             // allow sorting by sql.column
    ->sortable('lower(sql.column)')          // ...or by a custom expression
    ->filterUsing(fn(MGFilterItem $i): ?Qb => …);  // per-column operator override

GridSchema::make(GridColumn …)->defaultOrder('sql ASC');
```

`FilterType`Allowed operators`String`contains, notContains, startsWith, endsWith, equals, is, not, =, !=, isAnyOf, isEmpty, isNotEmpty`Number`equals, is, not, =, !=, &gt;, &gt;=, &lt;, &lt;=, isAnyOf, isEmpty, isNotEmpty`Boolean`is, equals, =, isEmpty, isNotEmpty`Date`is, not, equals, =, !=, after, onOrAfter, before, onOrBefore, isEmpty, isNotEmpty---

License
-------

[](#license)

MIT — [Flytachi](https://github.com/flytachi)

###  Health Score

44

—

FairBetter than 91% of packages

Maintenance94

Actively maintained with recent releases

Popularity11

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

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

Total

5

Last Release

31d ago

Major Versions

v1.0.3 → v2.0.02026-05-31

PHP version history (2 changes)v1.0.0PHP &gt;=8.3

v2.0.0PHP &gt;=8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/861b81dd97c8ddfa919522d2a4e17626120bd3e3d7464857cc03784676bc74a8?d=identicon)[Flytachi](/maintainers/Flytachi)

---

Top Contributors

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

---

Tags

paginationfiltersortdatagridwinterserver-sidemui

###  Code Quality

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/flytachi-winter-mui-data-grid/health.svg)

```
[![Health](https://phpackages.com/badges/flytachi-winter-mui-data-grid/health.svg)](https://phpackages.com/packages/flytachi-winter-mui-data-grid)
```

###  Alternatives

[kitpages/data-grid-bundle

Symfony DataGridBundle

7781.0k1](/packages/kitpages-data-grid-bundle)

PHPackages © 2026

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