contenir / contenir-resource-mezzio
Mezzio adapter for contenir/contenir-resource: workflow routing and navigation for Contenir resources, a middleware that resolves the routed resource and its page metadata, resource URLs and optional laminas-view helpers.
Package info
github.com/contenir/contenir-resource-mezzio
pkg:composer/contenir/contenir-resource-mezzio
Requires
- php: ~8.3.0 || ~8.4.0 || ~8.5.0
- contenir/contenir-db-model: ^2.0@RC
- contenir/contenir-metadata: ^2.0
- contenir/contenir-resource: ^2.0@RC
- contenir/contenir-workflow-mezzio: ^2.1
- laminas/laminas-cache: ^3.12
- laminas/laminas-servicemanager: ^3.22
- mezzio/mezzio: ^3.18
- mezzio/mezzio-router: ^3.17
- mezzio/mezzio-template: ^2.10
- psr/container: ^1.1 || ^2.0
- psr/http-message: ^1.1 || ^2.0
- psr/http-server-handler: ^1.0.2
- psr/http-server-middleware: ^1.0.2
Requires (Dev)
- infection/infection: ^0.34.1
- laminas/laminas-cache-storage-adapter-memory: ^2.3
- laminas/laminas-config-aggregator: ^1.15
- laminas/laminas-diactoros: ^3.3
- laminas/laminas-view: ^2.36
- mezzio/mezzio-fastroute: ^3.12
- php-db/phpdb-qa-tools: 0.1.x-dev
- php-db/phpdb-sqlite: 0.3.x-dev
- phpunit/phpunit: ^11.5.42
Suggests
- laminas/laminas-view: For the optional resource, resourceMeta, resourceUrl and resourceContent view helpers under mezzio/mezzio-laminasviewrenderer.
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-07 03:13:06 UTC
README
The Mezzio adapter for contenir/contenir-resource, so a Mezzio site that does not run the full Contenir CMS can serve Contenir resources (pages, articles, collections):
- routes and navigation built from the resource tree through contenir-workflow-mezzio;
- a PSR-15 middleware that resolves the routed resource, refuses unpublished ones, and attaches the resource and its page metadata to the request;
- resource URLs through the Mezzio router, and safe editor-entered links;
- section summaries rendered through
mezzio/mezzio-template; - optional laminas-view helpers (
resource,resourceMeta,resourceUrl,resourceContent) for mezzio-laminasviewrenderer sites.
The entities, repositories, resource manager and metadata builder live in contenir/contenir-resource and are framework neutral; this package is the Mezzio plumbing around them. It replaces the laminas-mvc parts of contenir/contenir-resource 1.x; see Coming from contenir-resource 1.x.
Requirements
- PHP 8.3, 8.4 or 8.5
- contenir/contenir-resource 2.x (with contenir/contenir-db-model 2.x), contenir/contenir-workflow-mezzio 2.1+
- mezzio/mezzio 3.18+, mezzio/mezzio-router, mezzio/mezzio-template
- laminas/laminas-view 2.36+ only for the optional view helpers
Install
2.0 is a release candidate (2.0.0-RC1): contenir-db-model 2 is itself at RC and builds on php-db/phpdb 0.6, which
has no stable release yet. Composer only honours stability flags in the root package, so a site needs these in its
own composer.json:
{
"require": {
"contenir/contenir-resource-mezzio": "^2.0@RC",
"contenir/contenir-db-model": "^2.0@RC",
"php-db/phpdb": "0.6.x-dev@dev"
}
}
Alternatively set "minimum-stability": "dev" with "prefer-stable": true in the site's composer.json and
require contenir/contenir-resource-mezzio normally.
With laminas-component-installer the config providers are added automatically. Otherwise register all of them:
// config/config.php $aggregator = new ConfigAggregator([ \PhpDb\ConfigProvider::class, \Contenir\Db\Model\ConfigProvider::class, \Contenir\Workflow\ConfigProvider::class, \Contenir\Resource\Core\ConfigProvider::class, // repositories, manager, metadata \Contenir\Resource\Mezzio\ConfigProvider::class, // middleware, strategy, URLs, view helpers // ... ]);
Wiring
1. Route resources through a workflow
// config/autoload/resource.global.php use Contenir\Resource\Mezzio\Workflow\ResourceStrategy; use Contenir\Workflow\Factory\WorkflowApplicationDelegatorFactory; use Mezzio\Application; return [ 'workflow_manager' => [ 'strategy' => ResourceStrategy::class, // repository defaults to ResourceTreeAdapter 'cache' => 'FilesystemCache', ], 'dependencies' => [ 'delegators' => [ Application::class => [WorkflowApplicationDelegatorFactory::class], ], ], 'contenir_resource' => [ 'base_url' => 'https://www.example.com', ], ];
Each resource is routed by the workflow plugin named in its workflow column (page when empty). The default
PageWorkflow has no handler, so register your own:
use Contenir\Workflow\Workflow\AbstractPageWorkflow; final class PageWorkflow extends AbstractPageWorkflow { protected ?string $middleware = \App\Handler\PageHandler::class; }
and add it to the WorkflowPluginManager (for example as the page alias). See Routing and navigation.
2. Pipe the middleware after routing
// config/pipeline.php $app->pipe(RouteMiddleware::class); $app->pipe(\Contenir\Resource\Mezzio\Middleware\ResourceMiddleware::class); // ... $app->pipe(DispatchMiddleware::class);
3. Use the resource in the handler
use Contenir\Resource\Core\Metadata\MetaTagRenderer; use Contenir\Resource\Mezzio\ResourceAttribute; final class PageHandler implements RequestHandlerInterface { public function __construct( private TemplateRendererInterface $templates, private MetaTagRenderer $meta, ) {} public function handle(ServerRequestInterface $request): ResponseInterface { $page = ResourceAttribute::require($request); return new HtmlResponse($this->templates->render('app::page', [ 'page' => $page, 'head' => $this->meta->render(ResourceAttribute::metadata($request)), // output unescaped in <head> ])); } }
What is in the package
| Class | Purpose |
|---|---|
Workflow\ResourceStrategy |
workflow-mezzio strategy: workflow from the workflow column; navigation label, visibility and lastmod from the resource |
Workflow\ResourceTreeAdapter |
workflow-mezzio resource adapter over ResourceRepository::findPageTree() |
Workflow\WorkflowResource |
A resource entity presented as a workflow-mezzio ResourceInterface |
Middleware\ResourceMiddleware |
Resolves the routed resource; 404s missing or unpublished ones; attaches resource and PageMetadata |
ResourceAttribute |
Reads the attached resource (resource(), require()) and metadata (metadata()) |
Url\ResourceUrlGenerator |
Resource links through the router, editor-entered links through ExternalUrl |
Content\TemplateSectionRenderer |
Renders section content with the template renderer, for ResourceSummary |
View\Helper\ResourceHelper, ResourceMetaHelper, ResourceUrlHelper, ResourceContentHelper |
Optional laminas-view helpers |
ConfigProvider, Container\*Factory |
Container wiring |
Every concrete class is final. The docs cover each area:
- Routing and navigation
- The resource middleware
- Metadata, templates and links
- laminas-view helpers
- Configuration
- Coming from contenir-resource 1.x (laminas-mvc)
Security
- Unpublished pages. The route cache can outlive a change in the admin. The middleware re-checks every routed resource and answers missing, pending, inactive or archived ones with the not-found handler; the page handler never sees them.
- Request input. Only an array
idroute default with aresourceIdkey is treated as a resource route, so a path placeholder calledidcan never trigger a lookup; ids other than positive integers never reach the database. - Host header. Set
contenir_resource.base_urlin production; otherwise canonical and Open Graph URLs use the request's host, which the client controls. Query strings never reach canonical or share URLs. - Links and images. Editor-entered links and share images are limited to safe schemes;
javascript:,data:and the like are dropped. - Escaping.
MetaTagRendererand the laminas-view head helpers escape everything; summaries and link pairs are plain text that templates must escape.
Development
The QA toolchain is contenir/contenir-qa-tools.
Mago is a standalone binary, installed separately (brew install mago).
composer check # everything below composer cs-check # mago format --check && mago lint composer static-analysis # mago analyze composer test # unit suite: no I/O composer test-integration # integration suite: a real Mezzio pipeline, ServiceManager and in-memory SQLite composer test-coverage # both suites, clover.xml for Codecov composer mutation-test # Infection over both suites (needs Xdebug or PCOV)
License
BSD-3-Clause. See LICENSE.md.