Download the PHP package ghaliano/easyadmin-grouping-bundle without Composer

On this page you can find all versions of the php package ghaliano/easyadmin-grouping-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package easyadmin-grouping-bundle

ghaliano/easyadmin-grouping-bundle

A grouping layer for EasyAdmin index pages. Adds a "grouped view" mode that groups rows by one or more criteria. Two display variants:

The bundle is framework code only — no entity changes required.

Requirements

Installation

If Symfony Flex doesn't auto-register the bundle, add it manually to config/bundles.php:

Publish the static assets (run once after install and on each update):

Quick start

Open the index page: a "Grouped view" button appears in the action bar. Click it and the rows are sorted by department, with a header row between each department block.

Grouping strategies

A strategy maps an entity to one or more group keys. Two built-in strategies, plus a custom strategy slot for anything else.

By property path

Reads a Symfony PropertyAccessor path on the entity. Dotted paths traverse associations. Returns null for missing or empty values (the row falls into a configurable "Uncategorized" bucket).

By callable

For computed values, complex enums, or method calls.

The callable may return:

Multi-level (nested)

Chain calls to nest groups. The first strategy is the outer group.

Each level renders its own header row with distinct indentation and colour. Clicking a header collapses the entire subtree.

Custom strategy

When neither groupByProperty() nor groupByCallback() fits — for example you want to group by month from a date field, by first letter for an A–Z directory, or by a computed score bucket — implement Ghaliano\EasyAdminGrouping\Domain\GroupingStrategy directly:

The interface contract is intentionally minimal so you can plug in any extraction logic without surprises. A step-by-step tutorial with three worked examples (month grouping, first-letter directory, multi-valued tags) is in docs/custom-strategies.md.

Action UI: buttons or dropdown

Two ways to expose the "switch to grouped view" affordance.

Separate buttons (one per variant)

The controller's configureGrouping() reads the groupBy query param to choose which strategy chain to build.

Single dropdown

One button opens a small menu listing all variants. Lighter in the action bar when you have more than two variants.

The dropdown requires the bundle's small action JS to be loaded on every admin page. Add it to your DashboardController:

Reading groupBy from the URL in configureGrouping():

Disabling column sort on grouping fields

Clicking a column header to sort a field that already drives the grouping just flips the group order — confusing for users. Disable the column sort with the property name shown in EA's <th data-column="...">:

The header label stays visible but the link is removed and the cursor becomes default. Other columns remain sortable.

Configuration reference

Method Effect
groupByProperty($path, $label) Group by Symfony property path
groupByCallback($fn, $label) Group by callable
groupBy(GroupingStrategy) Group by custom strategy
collapsedByDefault(bool) Initial collapsed state
showCounts(bool) Show item count per group header
uncategorizedLabel(string) Bucket label for null keys
sortGroupsBy(SORT_ALPHA \| SORT_COUNT_DESC) Group ordering
withGroupSorter(GroupSorter) Custom group sorter
itemLabelFromProperty($path) Item label in tree view
itemLabelFromCallback($fn) Item label in tree view
rootGroupsPerPage(int) Tree view pagination size
itemLinkAction(?string) EA action a row click navigates to (null = read-only)
disableSortFor(string[]) Disable column sort for these EA field names

How the table view works

The trait sets the index template to one that extends EA's crud/index.html.twig — or the controller's overridden template if there is one, so custom modals and content_footer blocks survive.

The template overrides the entity_row_attributes block to emit a data-easyadmin-group-keys attribute on each <tr>. After the page loads, grouped-table.js:

  1. Reads the keys from each row.
  2. Sorts rows by keys (stable, multi-level, direction inherited from EA's current ?sort=DESC).
  3. Inserts header <tr> elements between groups.
  4. Binds collapse and expand handlers, persisting state in localStorage keyed by URL path.

EA's pagination is preserved. Grouping operates within the current page: if a group spans pages you will see partial groups, which the labels make obvious.

How the tree view works

The trait bypasses EA's paginator entirely. It runs the same createIndexQueryBuilder() to honour filters and search, fetches all matching entities, then:

  1. Builds a GroupNode tree using the configured strategies and group sorter.
  2. Paginates the root groups (configurable via rootGroupsPerPage).
  3. Renders grouped_index.html.twig with <details> nodes.

Tree view fetches the entire matching set in one query. It is fine up to a few thousand rows; past that, prefer the table view.

Design decisions

Some of the choices behind the code that aren't obvious from the API alone. They are listed here so contributors can argue with them with context, not in the dark.

Strategy as an interface, not a class hierarchy. PropertyPathStrategy and CallableStrategy share nothing structurally — one calls PropertyAccessor, the other invokes a closure. Forcing them under an abstract parent would have been ceremonial. The interface exposes only extractKey() and levelLabel(); implementations are free to do whatever fits.

null means "unclassified", an array means "belongs to multiple groups". Those semantics live in the interface PHPDoc, not in special-case wrapper classes. It is explicit, and lets users write their own strategy without surprises. The bucket routing and item duplication logic stays in one place: GroupTreeBuilder::buildLevel().

Fluent builder over immutable config. EA's own DSL is fluent (Crud::new()->setX()->setY()); admin developers expect that idiom. GroupingConfig is mutable, but its lifecycle is short: created in configureGrouping(), consumed by the trait, discarded. The bookkeeping cost of an immutable withX() builder would not have bought anything here.

Tree view and table view coexist. After the pivot to the table view, we could have dropped the tree view. It stayed: it is a different UX, useful for compact browsing of hierarchical reference data (think a tree of legal codes). Both modes share the entire Domain and Application layers — that is the payoff of the separation.

Decoration over replacement. This is the most impactful decision. The alternative would have been recreating an index template from scratch, duplicating actions, filters, sort, and re-syncing on every EA release. Decorating ({% extends '@!EasyAdmin/crud/index.html.twig' %} plus a handful of targeted block overrides) is what Twig was designed for.

Client-side post-processing instead of a server-side sort. In table mode, rows arrive paginated by EA. Sorting them by group keys server-side would mean bypassing pagination and loading everything into memory — which is what tree mode does, and precisely why it does not scale. Table mode sorts the current page in JS. Trade-off: a group spanning two pages appears in two pieces. Documented honestly in Limitations. The compromise prioritises performance and clean integration with EA's pagination.

Collapse state in localStorage, not in the URL or cookies. A URL-encoded state would be shareable but blows up past 20 groups. A cookie would round-trip to the server on every request for no reason. localStorage is client-only, keyed by window.location.pathname — each CRUD gets its own state.

Limitations

Running the tests

The test suite covers the domain (strategies, sorting, group nodes) and the application service (GroupTreeBuilder, GroupingConfig). It does not boot Symfony — pure unit tests.

License

MIT.


All versions of easyadmin-grouping-bundle with dependencies

PHP Build Version
Package Version
Requires php Version >=8.2
symfony/framework-bundle Version ^7.0
symfony/property-access Version ^7.0
easycorp/easyadmin-bundle Version ^4.25
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package ghaliano/easyadmin-grouping-bundle contains the following files

Loading the files please wait ...