Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Datagrid Bundle Laravel Package

fsi/datagrid-bundle

FSI DataGrid Bundle is a Symfony package for building flexible, configurable data grids. It supports columns, filters, sorting, pagination, actions, and exports, with Doctrine and Twig integration for quickly rendering admin-ready tables.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: the package is a Symfony bundle, not a Laravel package. It contains almost no grid logic itself — its description says it plainly: it registers the FSi DataGrid component's service and the Twig rendering functions. Everything interesting lives in the underlying fsi/datagrid component (DataGrid, Column\*, DataSource\*). There is no service provider, no facade, no config file that Laravel's package discovery would pick up.

So the decision fork is:

  • You want a Symfony-integrated grid → install fsi/datagrid-bundle and use the fsi_datagrid.factory service plus the Twig helpers.
  • You are building a Laravel app (the normal case for you) → install only fsi/datagrid, construct the factory yourself in a service provider, and write your own Blade renderer. That is maybe 60–100 lines of glue and avoids dragging Symfony DI into the app.

Minimal Symfony path:

composer require fsi/datagrid-bundle
// config/bundles.php (Symfony Flex often won't auto-register this one)
FSi\Bundle\DataGridBundle\FSiDataGridBundle::class => ['all' => true],
// Controller — autowire the factory (service id: fsi_datagrid.factory)
public function list(DataGridFactory $factory, UserRepository $users)
{
    $grid = $factory->createDataGrid('users');
    $grid->addColumn('id', 'number', ['sortable' => true]);
    $grid->addColumn('email', 'text', ['sortable' => true]);
    $grid->addColumn('createdAt', 'datetime', ['label' => 'Joined']);
    $grid->setData($users->createQueryBuilder('u'));

    return $this->render('user/list.html.twig', ['grid' => $grid]);
}
{{ datagrid_render(grid) }}
{# the bundle also ships a JS helper for ajax sorting/pagination — check Twig/ for the exact function names #}

Laravel equivalent skeleton:

// app/Providers/DataGridServiceProvider.php
$this->app->singleton(DataGridFactory::class, fn () => new DataGridFactory());
$grid = app(DataGridFactory::class)->createDataGrid('users');
$grid->addColumn('email', 'text', ['sortable' => true]);
// ... render with @include('partials.datagrid', ['grid' => $grid])

First use case to prove it out: a paginated, sortable table over one Doctrine entity, rendered server-side. If that works, the rest is column types and a custom data source.

Where to look first, in order: the fsi/datagrid README (that's where the real docs are), src/Resources/config/*.xml for the registered service ids, DependencyInjection/ for the extension, and Twig/ for the extension class that defines the actual function names. The bundle README is thin.

Implementation Patterns

Build grids in a dedicated factory, not in controllers. One class per grid (UserGrid, OrderGrid) that takes the DataGridFactory and returns a configured grid. This is the single biggest maintainability win and makes the grids unit-testable without HTTP.

Columns are typed and configured by array options. The component ships Text, Number, Date/DateTime, Boolean, and Actions column types. Options cover label, sortable, translation_domain, and value formatting. Register custom types by extending the column base class and teaching the factory about it.

Data sources are the integration seam. In Symfony you'll use the Doctrine ORM data source, which accepts a query builder. For Laravel you implement DataSourceInterface yourself over an Eloquent builder — this is the cleanest bridge and keeps the component ignorant of Eloquent:

final class EloquentDataSource implements DataSourceInterface
{
    public function __construct(private Builder $query) {}

    public function getData(): iterable { return $this->query->get(); }
    public function getTotalCount(): int { return $this->query->count(); }
}

Use the array/in-memory source for tests and for small static tables (enum lookups, config lists) where hitting the DB is pointless.

Pagination and sorting are your responsibility. The component gives you the hooks (setData, limit/offset, sort column + direction); it does not parse ?page= or ?sort= for you. In Laravel, read from the request in the controller, apply orderBy/skip/take to the builder before handing it to the data source, and pass the resolved page/limit into the grid. Keep it in one place — a small GridRequest value object that maps query params to (page, limit, sortColumn, direction) pays for itself immediately.

Actions columns take closures/URLs. For row actions ("edit", "delete"), use the actions column with a route/URL generator so links are built per row rather than concatenating strings in a template.

Rendering: the Twig helper is a thin wrapper around getColumns() / getData(). In Blade, write a single partial that iterates columns for the header and rows for the body, plus a pagination partial. It's boring, deliberately so, and it's the piece you'd be reimplementing anyway.

AJAX/JS path: the bundle can emit the JavaScript needed for client-driven sorting/pagination. If you go this route, expose a JSON endpoint that rebuilds the grid from request params and returns the rendered rows — don't try to compute the grid twice in different places.

Test the grid, not the page. Because the grid is a plain object, you can assert "column email is sortable and renders the right value" in a unit test with an array data source. This is the main reason to use a component like this instead of hand-rolled Blade tables.

Gotchas and Tips

  • Maintenance risk is real. Last release 2022-03-18, 18 stars, zero dependents. Treat it as "vendored with intent to fork." Pin the version, and check PHP 8.2/8.3 and Symfony compatibility before committing — the constraint set is likely stale.
  • Don't install the bundle in Laravel. Require fsi/datagrid directly. The bundle's only real value is DI registration and Twig functions, both of which you'd replace.
  • Function names are under-documented. The README doesn't reliably enumerate them; open the Twig extension class in Twig/ and confirm. Don't build a template around a guessed name.
  • No built-in pagination library integration. You won't get Pagerfanta or Laravel paginator objects out of the box; you manage limit/offset and total count manually. If getTotalCount() is wrong, the pager silently breaks — always verify it against the unpaginated query in a test.
  • Escaping is on you. Column values are stringified into templates; user-supplied data rendered raw is an XSS hole. Escape at render time in your Blade/Twig partial rather than trusting the column type.
  • Sorting params need whitelisting. Whatever maps ?sort= to a column name must reject unknown columns, or you get SQL errors (or worse) from arbitrary column injection into orderBy.
  • Symfony Flex auto-registration is unreliable for packages this old; register the bundle explicitly.
  • Doctrine coupling only applies to the ORM data source. The core DataGrid/Column classes are framework-agnostic — that's why the Eloquent bridge works. Don't assume the whole package is Doctrine-bound.
  • Debug by dumping grid state before render: columns registered, data source type, resolved limit/offset/sort. Nearly every "empty table" report is a data source returning an empty iterable or a limit of 0.
  • Extension points worth knowing: custom DataSourceInterface implementations, custom column types, and (in Symfony only) overriding the bundle's Twig templates under templates/bundles/FSiDataGridBundle/. In Laravel the extension point is simply your own renderer.
  • If the grid grows beyond sorting/pagination/filtering, stop extending this and evaluate a maintained alternative — the low release cadence means you'll own the code sooner rather than later.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource