Core

Component Service Provider

Reusable UI component registry for breadcrumbs, pagination and metadata.

Responsibility

Registers component-level services for reusable UI data and rendering: ComponentRegistry, breadcrumb services, pagination services and meta services. The provider also reads custom component class mappings from config key components.

Registry

ComponentRegistry maps component names to classes and resolves them through the container. Built-in names are breadcrumb, pagination and meta; convenience methods breadcrumb(), pagination() and meta() return typed framework components.

use Lemonade\Framework\Component\ComponentRegistry;
use Lemonade\Framework\Component\Breadcrumb\BreadcrumbComponent;

$registry = $container->get(ComponentRegistry::class);

if ($registry->has('breadcrumb')) {
    $breadcrumb = $registry->get('breadcrumb', BreadcrumbComponent::class);
}

$all = $registry->all();

Custom components

Applications can add reusable component services with config key components. Keys are component names and values are non-empty class strings. The component class must exist and is resolved through the container when requested from the registry.

<?php

declare(strict_types=1);

use App\Component\ExampleComponent;

return [
    'example' => ExampleComponent::class,
];

Breadcrumbs

BreadcrumbComponent creates BreadcrumbTrail instances and renders them through BreadcrumbRenderer. A trail supports add(), prepend(), clear(), count() and items(). frontend() and admin() use configurable root labels/URLs; empty() starts without a root item.

$trail = $components
    ->breadcrumb()
    ->empty()
    ->add('Home', '/')
    ->add('Articles', '/articles')
    ->add('Article detail', null, active: true);

$html = $components->breadcrumb()->render($trail);

Breadcrumb config

Breadcrumb defaults use breadcrumbs.frontend.root_label, breadcrumbs.frontend.root_url, breadcrumbs.admin.root_label, breadcrumbs.admin.root_url and breadcrumbs.classes. Class config is normalized before being passed to BreadcrumbRenderer.

Pagination

PaginationComponent can paginate an array through fromArray() or a database QueryBuilder through fromQueryBuilder(). It returns PaginationResult, which exposes paginated items() and state(). render() accepts PaginationResult, PaginationState or null.

$pagination = $components->pagination()->fromArray(
    items: $rows,
    page: 1,
    perPage: 20,
    pageName: 'page',
    basePath: '/articles',
);

$items = $pagination->items();
$html = $components->pagination()->render($pagination);

Pagination config

Pagination services use the current ServerRequestInterface to resolve the current page and query parameters when not supplied explicitly. Config keys include pagination.default_per_page, pagination.max_per_page, pagination.visible_pages, pagination.show_first_last and pagination.classes. PaginationRenderer uses TranslatorInterface for pagination.first, pagination.prev, pagination.next and pagination.last labels when translations exist.

Metadata

MetaComponent builds and renders page metadata from MetaData. Defaults come from config and rendered entities include standard meta tags, Dublin Core tags, Open Graph/Facebook tags and Twitter tags through MetaFactory.

use Lemonade\Framework\Component\Meta\MetaData;

$meta = new MetaData(
    title: 'Article detail',
    description: 'Short page description.',
    canonical: 'https://example.test/articles/example',
);

$html = $components->meta()->render($meta);

Meta config

MetaComponent applies defaults from meta.website_name, meta.charset, meta.viewport, meta.rating and meta.title_separator. MetaData can also carry custom meta values, extra canonical query params and alternate links.

Controller usage

Controllers can inject ComponentRegistry or use the framework controller helper for components. Build component data in the controller and pass the resulting DTO/state objects or rendered HTML to a view according to the application template style.

use Lemonade\Framework\Component\ComponentRegistry;

final class ArticleController
{
    public function __construct(
        private readonly ComponentRegistry $components,
    ) {}

    public function detail(): ResponseInterface
    {
        $breadcrumbs = $this->components
            ->breadcrumb()
            ->empty()
            ->add('Home', '/')
            ->add('Article detail', null, active: true);

        // Pass $breadcrumbs to a template or render it before returning a response.
    }
}

View usage

Components can return data objects for templates or render small HTML fragments directly. The concrete page layout, CSS classes and final markup structure remain application/template responsibility.

<?= $components->breadcrumb()->render($breadcrumbs) ?>
<?= $components->pagination()->render($pagination) ?>
<?= $components->meta()->render($meta) ?>

Provider relations

ComponentServiceProvider supplies reusable component services. ViewServiceProvider renders templates and shares helpers; RoutingServiceProvider and localization can provide URLs/translations used around components; DatabaseServiceProvider is only involved when pagination uses QueryBuilder.

Provider boundary

Components are reusable UI/runtime helpers, not domain services. They should help controllers and views prepare breadcrumbs, pagination state or metadata, while business decisions and page-specific layout remain in application code.