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

Entity List Bundle Laravel Package

nfqde/entity-list-bundle

nfqde/entity-list-bundle is a Symfony bundle for building reusable entity lists with configurable data sources, filters, sorting, pagination, and rendering helpers, simplifying admin and backend list screens.

View on GitHub
Deep Wiki
Context7

Getting Started

Decide your posture before installing anything. nfqde/entity-list-bundle is a Symfony bundle over Doctrine ORM — there is no service provider, no Eloquent adapter, and no Laravel config. It is archived with 0 stars and 0 dependents. Two legitimate day-to-day uses remain:

  1. Symfony + Doctrine app (legacy): adopt it as-is, pinned, and expect to own it.
  2. Laravel app: don't install it. Read it as a design reference and reimplement the abstraction with spatie/laravel-query-builder + Eloquent scopes. This is the recommended path for a Laravel developer.

If you are genuinely in a Symfony app:

composer require nfqde/entitylist-bundle
composer show nfqde/entitylist-bundle   # check resolved symfony/* and doctrine/orm versions FIRST

Register the bundle in config/bundles.php (Symfony 4+). If Composer pulls a Symfony 3/4-era dependency tree, stop — the package is not viable on a modern PHP/Symfony runtime without a fork.

Where to look first, in this order: the bundle's EntityList base/abstract class, the filter classes (annotation-driven), and the example list + controller in the repo's tests or docs. That trio defines the entire contract — you will rarely need to read the rest.

First use case: a paginated admin grid over one Doctrine entity with 2–3 column filters (e.g. User filtered by email substring and status, sorted by created date). Subclass the base list, declare the repository, add filterByX() methods, wire one controller action, and confirm the paging metadata in the response.

Laravel equivalent first use case — the same screen, same day, no fork:

// app/Lists/UserList.php
final class UserList
{
    public function query(Request $request): LengthAwarePaginator
    {
        return QueryBuilder::for(User::class)
            ->allowedFilters([AllowedFilter::partial('email'), AllowedFilter::exact('status')])
            ->allowedSorts(['created_at'])
            ->defaultSort('-created_at')
            ->paginate(min((int) $request->integer('per_page', 25), 100))
            ->withQueryString();
    }
}

That is the entire reusable core of the bundle — the rest is Symfony container wiring you would not use anyway.

Implementation Patterns

Subclass-and-declare (the bundle's model). One list class per screen. You supply the entity/repository and filter definitions; the bundle handles request parsing, paging, and serialization. Resist building a god-list; a class that filters users and orders and invoices becomes untestable within a sprint.

Filters are declarative and request-driven. Configure the filter on the list class (historically via annotation plus an optional form/filter type), add a filterByX(QueryBuilder $qb, $value) method, and the HTTP layer is handled for you. Day-to-day work is: add a property, add the annotation, add the method, ship.

Two output shapes, one controller action.

  • AJAX endpoint — returns JSON (rows + paging + applied filters) that a JS grid consumes. This is the bundle's intended shape and the common case for admin panels.
  • Server-rendered — same action renders a Twig template with the list object, degrading gracefully without JS.

Wrap the list in an application service. Do not inject the list directly into controllers. A UserListFactory (or UserList service) gives you a seam to swap the library out later — which matters a lot given the archived status.

// Symfony: the seam
final class UserListFactory
{
    public function create(Request $request): EntityListInterface
    {
        return new UserList($this->em->getRepository(User::class), $request);
    }
}

For Laravel on Doctrine (rare, but real). If you run laravel-doctrine/orm, wrap the bundle call in a Laravel service and normalize its output to an array/Collection. Feed it a Symfony Request explicitly, or bypass the HTTP layer entirely and drive the QueryBuilder yourself — never let the bundle's request assumptions leak into Illuminate\Http\Request.

Custom filters as classes, not conditionals. Register a custom filter class rather than stuffing branches into filterByX(). The latter is impossible to unit-test and becomes the first thing that breaks.

One integration test per list. Hit the controller and assert: row count for a given filter, paging metadata across pages 1/2/last, sort direction, and empty-result behavior. The bundle's own test suite will not protect you against a Doctrine upgrade.

Laravel-idiomatic building blocks when reimplementing:

Bundle concern Laravel equivalent
Declarative list definition Eloquent local scope or dedicated List class
Filter parameter allowlisting spatie/laravel-query-builder AllowedFilter
Sort allowlisting AllowedSort
Paging paginate() / cursorPaginator()
Fetch-joined display columns with() eager loading
Filter/sort metadata for the grid A toArray() contract on the list class

Gotchas and Tips

  • Archived means frozen. No security patches, no PHP 8.x or newer Doctrine fixes, no Symfony 6/7 guarantees. Pin exactly ("nfqde/entity-list-bundle": "x.y.*"), commit composer.lock, and write down the replacement plan on day one.
  • Annotation dependency. If filter metadata is annotation-based, doctrine/annotations deprecation and removal will bite. Any fork must convert annotations to PHP attributes before you touch PHP 8.2+.
  • Sort-field injection is the classic foot-gun. A request-supplied sort field reaching ORDER BY can error out or leak schema. Always validate against an explicit allowlist — never pass the raw parameter through.
  • COUNT(*) over joins lies. Paging totals computed on a query with joins/filters can over- or under-count. Verify totals against the exact filtered query, especially after you add fetch-joins for performance.
  • N+1 ships by default. The generic list query will not fetch-join your relations. Override the query-building hook to add leftJoin/addSelect for any column rendered in the grid, or production will find it for you.
  • Bound the page size. Clamp per_page to something sane (e.g. 100). Unbounded page size is a cheap denial-of-service against your database.
  • Namespace your filter params. Filters, sort, and paging share a flat query string. Use f[email]= style keys and document the contract, or you will collide with unrelated parameters.
  • Filter/count drift. If the count query and the data query apply filters inconsistently, page 1 looks right and the last page is empty. Apply filters through one code path only.
  • Config-time failure. If you do fork and port, DI/config errors surface at boot, not at the call site — a whole-service outage instead of one broken screen. Keep the fork's service definitions covered by a smoke test.
  • Extension points worth knowing: the base list class (override query building), custom filter classes, and the controller/response layer (swap JSON for server-rendered output). Those three cover almost every real requirement without touching the bundle internals.
  • Ramp-up reality for a Laravel team: the concept takes an afternoon; reading the code requires Doctrine and Symfony bundle fluency you should not acquire for this. Borrow the pattern, reimplement the code.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core