Domovoy API

Templates and Layouts

Domovoy's template system uses plain PHP classes with explicit dependency injection — no template language, no magic.

Template Interface

A template is a callable class implementing the Template marker interface:

  • Constructor parameters are service dependencies (wired by a DI container).
  • __invoke() parameters are the data contract (checked by PHPStan).
  • __invoke() returns a Node .
use Domovoy\Template\Template;
use Domovoy\VirtualDom\Contract\Node;
use function Domovoy\VirtualDom\Generated\{div, h3, span};

final readonly class ProductCard implements Template
{
    public function __construct(private PriceFormatter $formatter) {}

    public function __invoke(Product $product): Node
    {
        return div(className: 'card')(
            h3()($product->name),
            span(className: 'price')(
                $this->formatter->format($product->price),
            ),
        );
    }
}

PHPStan validates __invoke() signatures on concrete classes at max level, so data contract mismatches are caught at analysis time.

TemplateResolver (PSR-11)

Use TemplateResolver to pull template instances from any PSR-11 container:

use Domovoy\Template\TemplateResolver;

$resolver = new TemplateResolver($container);
$card = $resolver->resolve(ProductCard::class);
// $card is a fully wired ProductCard instance

The resolver preserves generic types, so resolve(ProductCard::class) returns ProductCard , not just Template .

Layout Inheritance with BlockRegistry

BlockRegistry is an immutable registry of named content blocks. A parent template defines block slots, and child templates override them.

Base Layout

use Domovoy\Template\BlockRegistry;
use Domovoy\Template\Template;
use Domovoy\VirtualDom\Contract\Node;
use function Domovoy\VirtualDom\Generated\{html, head, title, body, header, main, footer, nav, p};

final readonly class BaseLayout implements Template
{
    public function __invoke(string $pageTitle, BlockRegistry $blocks): Node
    {
        return html(lang: 'en')(
            head()(title()($pageTitle)),
            body()(
                header()($blocks->getOrDefault('nav', nav()())),
                main()($blocks->get('content')),
                footer()($blocks->getOrDefault('footer', p()('Default footer'))),
            ),
        );
    }
}

Child Layout

A child layout injects the parent and overrides blocks:

use function Domovoy\VirtualDom\Generated\{nav, a};

final readonly class AdminLayout implements Template
{
    public function __construct(private BaseLayout $base) {}

    public function __invoke(string $pageTitle, BlockRegistry $blocks): Node
    {
        return ($this->base)(
            "Admin — {$pageTitle}",
            $blocks->set('nav', nav()(
                a(href: '/admin')('Dashboard'),
                a(href: '/admin/users')('Users'),
            )),
        );
    }
}

Page Assembly

A page template assembles the layout with data:

use function Domovoy\VirtualDom\Generated\{div, h1};

final readonly class DashboardPage implements Template
{
    public function __construct(
        private AdminLayout $layout,
        private ProductCard $card,
    ) {}

    public function __invoke(ProductCollection $products): Node
    {
        $card = $this->card;

        return ($this->layout)(
            'Dashboard',
            BlockRegistry::create()
                ->set('content', div(className: 'dashboard')(
                    h1()('Product Dashboard'),
                    ...array_map(
                        static fn (Product $p): Node => $card($p),
                        $products->toArray(),
                    ),
                )),
        );
    }
}

BlockRegistry API

BlockRegistry is immutable — every mutation returns a new instance:

  • BlockRegistry::create() — empty registry
  • $reg->set('name', $node) — returns new registry with block added/replaced
  • $reg->get('name') — returns block or throws RuntimeException
  • $reg->getOrDefault('name', $fallback) — returns block or fallback node
  • $reg->has('name') — checks if block exists

Search results