dandoetech / bff-metadata
Framework-agnostic BFF UI metadata core: derive frontend-ready Resource UI metadata from a central Resource Registry with override support.
Requires
- php: ^8.2
- dandoetech/resource-registry: ^0.1 || ^0.2
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.64
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.3
This package is auto-updated.
Last update: 2026-04-20 12:20:35 UTC
README
Pre-release — Architecture by senior tech lead, implementation largely AI-assisted with human review. Not fully reviewed. Architecture may change before v1.0.0.
Generate frontend-ready UI metadata from a Resource Registry. Derives table columns, form layouts, field widgets, and action buttons — consistently across resources, with per-project overrides. Framework-agnostic.
Installation
composer require dandoetech/bff-metadata
Requires dandoetech/resource-registry.
Quick Start
use DanDoeTech\BffMetadata\Builders\DefaultMetadataBuilder; // $resource is any ResourceDefinitionInterface (from registry or built manually) $builder = new DefaultMetadataBuilder(); $metadata = $builder->forResource($resource); echo json_encode($metadata->toArray(), JSON_PRETTY_PRINT);
Output:
{
"key": "product",
"label": "Product",
"fields": {
"name": { "name": "name", "widget": "text", "required": true },
"price": { "name": "price", "widget": "number", "required": true, "props": { "step": 0.01 } },
"category": { "name": "category", "widget": "relation", "props": { "targetResource": "category", "multiple": false } },
"category_name": { "name": "category_name", "widget": "text", "readOnly": true }
},
"table": {
"columns": ["name", "price", "category", "category_name"],
"defaultSort": "-created_at",
"density": "comfortable"
},
"create": { "layout": [["name", "price"], ["category"]] },
"update": { "layout": [["name", "price"], ["category"]] },
"actions": [
{ "name": "create", "kind": "primary" },
{ "name": "delete", "kind": "danger", "confirm": true }
]
}
Applying Overrides
Customize the generated metadata without modifying the resource definition:
use DanDoeTech\BffMetadata\Builders\OverrideApplier; $overrides = [ 'fields' => [ 'price' => ['label' => 'Price (EUR)', 'props' => ['step' => 0.5]], ], 'table' => ['columns' => ['name', 'price'], 'defaultSort' => '-price'], ]; $final = (new OverrideApplier())->apply($metadata, $overrides);
Laravel users: Use
dandoetech/laravel-bfffor REST endpoints, policy-based visibility, and caching decorators.
API Overview
Core
| Class | Purpose |
|---|---|
DefaultMetadataBuilder |
Implements MetadataProviderInterface — generates metadata from a resource definition |
OverrideApplier |
Applies per-project tweaks onto generated metadata |
I18nResolver |
Optional translation hook for labels and help text |
Metadata Value Objects
| Class | Contents |
|---|---|
ResourceUiMetadata |
Top-level container — fields, table, forms, actions, extensions. Has toArray() |
FieldUiMetadata |
Widget type, label, help, required, readOnly, props, options, order, width |
TableMetadata |
Column list, defaultSort, density |
FormMetadata |
2D layout grid (field names per row), submitOnEnter |
ActionUiMetadata |
Name, label, kind (primary/default/danger), confirm flag |
Contract
interface MetadataProviderInterface { public function forResource(ResourceDefinitionInterface $resource): ResourceUiMetadata; }
Implement this for decorators (policy filtering, caching, logging).
Widget Mapping
| FieldType | Widget |
|---|---|
String |
text |
Integer |
number |
Float |
number (props: step: 0.01) |
Boolean |
checkbox |
DateTime |
date |
Json |
json |
| Relations | relation (props: targetResource, multiple) |
Computed Fields
Computed fields from the registry are included as read-only fields in the table but excluded from form layouts, since they are derived values.
I18n
Pass a translator callable to resolve labels and help text:
$i18n = new I18nResolver(fn (string $key) => $translations[$key] ?? null); $builder = new DefaultMetadataBuilder(i18n: $i18n);
Translation keys follow the pattern resource.{key}.label, field.{key}.{name}.label, action.{key}.{name}.
Testing
composer install composer test # PHPUnit composer qa # cs:check + phpstan + test
License
MIT