kachnitel / datasource-contracts
Interfaces and value objects defining the DataSource contract for admin-style list views
dev-master
2026-03-14 08:41 UTC
Requires
- php: >=8.1
Requires (Dev)
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^10.5|^11.0
This package is auto-updated.
Last update: 2026-03-14 19:24:51 UTC
README
Interfaces and value objects defining the DataSource contract for admin-style list views. Zero framework dependencies — pure PHP.
Installation
composer require kachnitel/datasource-contracts
Implementing a custom data source
use Kachnitel\DataSourceContracts\ColumnMetadata; use Kachnitel\DataSourceContracts\DataSourceInterface; use Kachnitel\DataSourceContracts\FilterMetadata; use Kachnitel\DataSourceContracts\FlatColumnGroupsTrait; use Kachnitel\DataSourceContracts\PaginatedResult; class ApiProductDataSource implements DataSourceInterface { use FlatColumnGroupsTrait; // satisfies getColumnGroups() for non-grouped sources public function getIdentifier(): string { return 'api-products'; } public function getLabel(): string { return 'API Products'; } public function getIcon(): ?string { return 'cloud'; } public function getColumns(): array { return [ 'id' => ColumnMetadata::create('id', 'ID', 'integer'), 'name' => ColumnMetadata::create('name'), 'status' => ColumnMetadata::create('status'), ]; } public function getFilters(): array { return [ 'name' => FilterMetadata::text('name', 'Name'), 'status' => FilterMetadata::enum('status', ['active', 'inactive']), ]; } public function getDefaultSortBy(): string { return 'id'; } public function getDefaultSortDirection(): string { return 'DESC'; } public function getDefaultItemsPerPage(): int { return 25; } public function query( string $search, array $filters, string $sortBy, string $sortDirection, int $page, int $itemsPerPage, ): PaginatedResult { // call your API or DB ... return new PaginatedResult(items: $results, totalItems: $total, currentPage: $page, itemsPerPage: $itemsPerPage); } public function supportsAction(string $action): bool { return in_array($action, ['index', 'show'], true); } public function find(string|int $id): ?object { /* ... */ } public function getIdField(): string { return 'id'; } public function getItemId(object $item): string|int { return $item->id; } public function getItemValue(object $item, string $field): mixed { return $item->{$field} ?? null; } }
Composite columns
use Kachnitel\DataSourceContracts\ColumnGroup; public function getColumnGroups(): array { return [ 'id', new ColumnGroup( id: 'name', label: 'Full Name', columns: [ 'firstName' => ColumnMetadata::create('firstName', 'First'), 'lastName' => ColumnMetadata::create('lastName', 'Last'), ], subLabels: ColumnGroup::SUB_LABELS_ICON, header: ColumnGroup::HEADER_COLLAPSIBLE, ), ]; }
Available value objects
| Class | Purpose |
|---|---|
ColumnMetadata |
Describes a column (name, label, type, sortable, template, group) |
ColumnGroup |
Groups columns into a composite table cell |
FilterMetadata |
Describes a filter widget with factory methods per type |
FilterEnumOptions |
Enum/select filter options (values list or enum class) |
PaginatedResult |
Query result container with pagination helpers |
PaginationInfo |
Slim pagination state for display templates |
Interfaces
| Interface | Purpose |
|---|---|
DataSourceInterface |
Main contract for any tabular data source |
DataSourceProviderInterface |
Yields multiple data sources from one service |
SearchAwareDataSourceInterface |
Optional: advertise which columns are globally searched |
Requirements
- PHP 8.1+
- No other dependencies