Server-side routing and rendering bridge for blackcube/dcore

Installs: 2

Dependents: 0

Suggesters: 1

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/blackcube/ssr

dev-devel / 1.x-dev 2026-03-03 19:44 UTC

This package is auto-updated.

Last update: 2026-03-03 19:46:03 UTC


README

Server-side routing for dcore. Maps slugs to PHP handlers, injects SEO metadata, handles errors.

License Packagist Version

Installation

composer require blackcube/ssr

Requirements

  • blackcube/dcore — data layer (Content, Tag, Slug, Xeo)
  • PSR-7 (psr/http-message) and PSR-15 (psr/http-server-middleware)

How it works

  1. RoutingMiddleware matches the request URL against dcore slugs
  2. HandlerRegistry resolves the slug's route to a handler class
  3. The handler receives Content, Tag, Slug automatically via DI
  4. XeoInjection pushes SEO meta tags into the Yii3 view layer
Request → RoutingMiddleware → HandlerDescriptor → Handler(Content, Tag, …) → Response

Registering handlers

Via PHP attributes

use Blackcube\Ssr\Attributes\RoutingHandler;
use Psr\Http\Server\RequestHandlerInterface;

#[RoutingHandler(route: 'page')]
final class PageHandler implements RequestHandlerInterface
{
    public function __construct(
        private readonly Content $content,
        private readonly WebViewRenderer $viewRenderer,
    ) {}

    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        return $this->viewRenderer->render('page', ['content' => $this->content]);
    }
}

Enable attribute scanning in params:

'blackcube/ssr' => [
    'scanAttributes' => true,
    'scanAliases' => ['@app/Handlers'],
],

Via config

'blackcube/ssr' => [
    'configHandlers' => [
        'page' => App\Handlers\PageHandler::class,           // __invoke or RequestHandlerInterface
        'article' => [App\Handlers\Blog::class, 'article'],  // Class::method
    ],
],

Handler modes

The registry analyzes handler signatures and dispatches accordingly:

Mode Detection Injection
construct Implements RequestHandlerInterface CMS objects injected via constructor
invoke Has __invoke() CMS objects injected via method params
method [Class, 'method'] config CMS objects injected via method params

CMS types tracked: Content, Tag, Slug, Element, Content|Tag unions.

SEO injection (Xeo)

Enable automatic SEO meta injection:

// In your middleware pipeline
RoutingMiddleware::withXeo()

Requires yiisoft/yii-view-renderer and yiisoft/html (both in suggest).

XeoInjection reads the Xeo attached to the slug and injects:

Tag Source
<meta name="robots"> noindex / nofollow
<meta name="title"> Xeo title
<meta name="description"> Xeo description
<meta property="og:*"> Open Graph (title, description, image, type)
<meta name="twitter:card"> Twitter Card
<link rel="canonical"> Canonical slug

JSON-LD data is available via XeoInjection::getJsonLds(). An optional transformer callback allows reshaping the data:

RoutingMiddleware::withXeo(function (array $jsonLds): array {
    // Add @context, reshape FAQ, etc.
    return $jsonLds;
})

Error handling

Error handler attribute

use Blackcube\Ssr\Attributes\RoutingErrorHandler;

#[RoutingErrorHandler(route: 'error-404', code: 404)]
final class NotFoundHandler { /* ... */ }

#[RoutingErrorHandler(route: 'error-5xx', min: 500, max: 599)]
final class ServerErrorHandler { /* ... */ }

Error handler config

'configErrorHandlers' => [
    'error-404' => ['handler' => App\Handlers\NotFound::class, 'code' => 404],
    'error-5xx' => ['handler' => App\Handlers\ServerError::class, 'min' => 500, 'max' => 599],
],

Error dispatch chain

  • SsrFallbackHandler — replaces default 404 handler, dispatches to CMS error handler
  • SsrThrowableResponseFactory — catches exceptions, resolves status code, dispatches to CMS error handler or falls back to Yii3 default

Preview

PreviewContext bridges the dcore preview system with HTTP. Reads the JWT from cookie and preview state from session, enabling content preview with simulated dates.

Configuration

// config/params.php
return [
    'blackcube/ssr' => [
        'scanAttributes' => false,         // scan for #[RoutingHandler] attributes
        'scanAliases' => [],               // aliases to scan (e.g. '@app/Handlers')
        'configHandlers' => [],            // route => handler class or [class, method]
        'configErrorHandlers' => [],       // route => error handler config
    ],
];

Let's be honest

This is slug-based routing, not a router.

SSR does not replace your router. It intercepts requests that match dcore slugs and dispatches them to CMS handlers. Everything else passes through to the normal pipeline.

Tight coupling with dcore.

SSR depends on dcore's Slug, Content, Tag, HandlerDescriptor, Xeo. It is the rendering bridge for the Blackcube stack, not a standalone routing library. The core is PSR-7/PSR-15 — Yii3 view renderer is optional (in suggest).

License

BSD-3-Clause. See LICENSE.md.

Author

Philippe Gaultier philippe@blackcube.io