prezent/grid-bundle
prezent/grid-bundle is a Symfony bundle for defining and rendering reusable data grids with configurable columns, filters, sorting, and pagination. It helps PHP applications present tabular data cleanly, integrating with Symfony services and templates for flexible, maintainable grid configurations.
First, the reality check: prezent/grid-bundle is a Symfony bundle, not a Laravel package. There is no service provider, no config publish, no facade, and no Laravel autodiscovery. If you're evaluating this for a Laravel app, you do not install this package — you install the underlying library instead:
composer require prezent/prezent-grid
The bundle is essentially a thin Symfony DI layer that:
prezent.grid,GridFactory/registry to fetch grids by name,Where to look first (in the repo source):
src/DependencyInjection/ — how grids are collected and tagged (this tells you the extension pattern).src/Grid/ / the underlying prezent-grid package — GridInterface, AbstractGrid, Column, DataSource.tests/ — the most reliable "docs" for this low-traffic package.Minimal first use case (ported to Laravel): a paginated users table.
use Prezent\Grid\BaseGridType;
use Prezent\Grid\GridBuilder;
use Prezent\Grid\Extension\Core\Type\TextType;
class UsersGrid extends BaseGridType
{
public function buildGrid(GridBuilder $builder, array $options = []): void
{
$builder
->addColumn('id', TextType::class)
->addColumn('name', TextType::class)
->addColumn('email', TextType::class);
}
public function getBlockPrefix(): string
{
return 'users_grid';
}
}
Then build it through the GridFactory and pass it your rows (from Eloquent) in a Blade view. If you only need a simple table, stop here — Laravel's @foreach will get you there faster.
1. Define-then-render separation. Treat the grid class as a column/filter declaration, not as a query. The Symfony pattern is GridFactory + DataSource. In Laravel you'll typically:
$grid = $this->gridFactory->createGrid(UsersGrid::class, $options)
->createView(User::paginate(25));
return view('users.index', ['grid' => $grid]);
2. Data sources — the main integration point. prezent-grid ships with array and (usually) Doctrine-based sources. For Laravel you'll write your own DataSourceInterface implementation wrapping Builder/Eloquent\Builder:
class EloquentDataSource implements DataSourceInterface
{
public function __construct(private Builder $query) {}
public function getTotalItemCount(): int
{
return $this->query->count();
}
public function getItems(int $offset, int $limit): array
{
return $this->query->offset($offset)->limit($limit)->get()->all();
}
}
This is the cleanest seam — do not try to bend Doctrine's QueryBuilder source into Eloquent.
3. Filters and sorting via $options. Symfony bundles encourage passing request state through options (from ->query()). Build a small mapper: $options = ['page' => (int) request('page', 1), 'sort' => request('sort')] and let your grid class apply them in buildGrid() or a custom grid type.
4. Column types and customization. The bundle exposes a form-like type extension system (GridTypeExtension). Reach for a GridTypeExtension when you want to add a custom column type globally (e.g., a BadgeType column) rather than per-grid — mirroring Symfony's form extension pattern. In Laravel, register extensions manually through the factory.
5. Rendering. The bundle's Twig theme (Resources/views/) is the reference for the view layer. Port the grid.html.twig/grid_*.html.twig templates to Blade partials. Do not attempt to load Twig in Laravel just for this.
6. Service registration pattern → service provider. The Symfony bundle's tagged-service pattern translates cleanly to a ServiceProvider:
$this->app->singleton(GridFactory::class, fn ($app) => new GridFactory([
UsersGrid::class,
OrdersGrid::class,
]));
prezent/prezent-grid and port the wiring yourself. Budget an afternoon for the Laravel adapter.prezent/prezent-grid has more traction but is still niche.GridFactory is the bottleneck for extensibility. Grids must be registered up front in the Symfony bundle via tags. For a Laravel adapter, either keep a static registry or bind grid classes as singletons and resolve names from the container. Avoid instantiating grids ad hoc — you lose extensions (filters, custom column types) if bypassed.prezent-grid is stateless — it expects the caller to pass request state in $options. Combine with Laravel's ->withQueryString() for pagination links.getBlockPrefix). If a custom type isn't rendering, that's usually because the block prefix doesn't match the Blade/Twig partial name. Log the view blocks when debugging.dd($grid->createView()) to inspect column/filter metadata before rendering; (b) use the underlying test suite from the repo as copy-paste examples — the README is minimal; (c) enable Symfony's container debug if you're ever testing inside a Symfony app to verify the prezent.grid tag actually collected your service.DataSourceInterface (for Eloquent/API/paginated sources).BaseGridType subclasses (column bundles).GridTypeExtension (global column behaviors like date formatting).spatie/laravel-query-builder is a better fit. Reach for prezent-grid only if you want declarative grid definitions shared across many admin screens and are comfortable maintaining the bridge.How can I help you explore Laravel packages today?