mistralys/application-datagrids

PHP classes to abstract the rendering of HTML tables.

Maintainers

Package info

github.com/Mistralys/application-datagrids

pkg:composer/mistralys/application-datagrids

Statistics

Installs: 5

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

dev-main 2026-03-14 21:43 UTC

This package is auto-updated.

Last update: 2026-03-14 21:43:19 UTC


README

PHP classes to abstract the rendering of HTML tables, with switchable renderers and a straightforward fluid and chainable API.

NOTE: Work in progress, but the examples work already.

Requirements

Viewing the examples

  1. Clone the repository.
  2. Run composer install to install the dependencies.
  3. Open the examples folder through your webserver.

Each example uses a shared JsonFileStorage instance (created in examples/bootstrap.php) to persist per-grid settings. The examples/storage/ directory is created automatically on first use — no manual setup is required.

Usage

Creating a grid

Every DataGrid instance requires a string ID (strict kebab-case: ^[a-z][a-z0-9]*(-[a-z0-9]+)*$) and a storage handler that implements GridStorageInterface. The library ships a file-backed implementation, JsonFileStorage:

use AppUtils\Grids\DataGrid;
use AppUtils\Grids\Storage\Types\JsonFileStorage;

$storage = new JsonFileStorage('/path/to/storage/dir');
$grid = DataGrid::create('my-grid', $storage);

$grid->columns()->add('name', 'Name');
$grid->columns()->add('status', 'Status');

$grid->rows()->addArray(['name' => 'Alice', 'status' => 'Active']);
$grid->rows()->addArray(['name' => 'Bob',   'status' => 'Inactive']);

echo $grid;

The JsonFileStorage constructor creates the storage directory if it does not exist. One JsonFileStorage instance can be shared across all grids on a page; data is keyed by grid ID internally.

Per-grid settings (items per page)

Use $grid->settings() to read and write typed per-grid settings persisted via the storage handler. The first available setting is items per page for pagination:

// Read the stored value, falling back to 25 if nothing is persisted yet:
$itemsPerPage = $grid->settings()->getItemsPerPage(25);

// Build the pagination provider with the effective value:
$provider = new \AppUtils\Grids\Pagination\Types\ArrayPagination($allItems, $itemsPerPage);
$grid->pagination()->setProvider($provider);
$grid->rows()->addArrays($provider->getSlicedItems());

// Persist an updated preference (e.g. after a user submits a preference form):
$grid->settings()->setItemsPerPage(50);

Settings are stored per grid ID, so multiple grids on the same page are fully isolated. To use a custom storage backend (database, session, Redis, etc.), implement the two-method GridStorageInterface:

use AppUtils\Grids\Storage\GridStorageInterface;

class SessionStorage implements GridStorageInterface
{
    public function get(string $gridID, string $key, mixed $default = null): mixed
    {
        return $_SESSION['grids'][$gridID][$key] ?? $default;
    }

    public function set(string $gridID, string $key, mixed $value): void
    {
        $_SESSION['grids'][$gridID][$key] = $value;
    }
}

Built-in items-per-page selector

Call setItemsPerPageOptions() on the grid's pagination instance to enable an automatic dropdown selector rendered as part of the pagination row — no separate form or handler required:

use AppUtils\Grids\Pagination\Types\ArrayPagination;

$pagination = $grid->pagination();

// Define the available choices:
$pagination->setItemsPerPageOptions([10, 25, 50, 100]);

// Resolve the effective value — priority: $_GET['ipp'] → persisted setting → default:
$itemsPerPage = $pagination->resolveItemsPerPage(25);

// Build the provider with the resolved value:
$provider = new ArrayPagination($allItems, $itemsPerPage);
$pagination->setProvider($provider);
$grid->rows()->addArrays($provider->getSlicedItems());

echo $grid;  // selector appears automatically next to the page-jump input

The selected value is persisted via GridSettings so it survives across page loads. When the user picks a new value, $_GET['ipp'] is detected on the next request, validated against the configured options whitelist, persisted, and used for the current render.

Backward compatibility: grids that do not call setItemsPerPageOptions() are unaffected — the pagination row continues to be hidden on single-page results exactly as before.

Visibility rule: when at least one IPP option is configured, the pagination row is shown even when totalPages <= 1 (e.g. a zero-row grid), so users can always change the page size.

Bootstrap 5 renderer: the <select> is automatically wrapped in a d-flex align-items-center gap-2 mt-2 container and styled with form-select form-select-sm.

GET parameter name: defaults to ipp. Change it with $pagination->setItemsPerPageParam('per_page') if it conflicts with another parameter on the same page.