blackcube / ssr
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
Requires
- php: >=8.3
- blackcube/dcore: ^1.0
- psr/http-message: ^2.0
- psr/http-server-middleware: ^1.0
- yiisoft/aliases: ^3.1
- yiisoft/cache: ^3.2
- yiisoft/injector: ^1.2
- yiisoft/request-provider: ^1.3
- yiisoft/session: ^3.0
Requires (Dev)
- phpunit/phpunit: ^13.0
Suggests
- yiisoft/html: Required for XeoInjection
- yiisoft/yii-view-renderer: Required for XeoInjection (SEO meta/link tags)
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.
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
- RoutingMiddleware matches the request URL against dcore slugs
- HandlerRegistry resolves the slug's route to a handler class
- The handler receives
Content,Tag,Slugautomatically via DI - 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