contenir / contenir-resource
Contenir resources on contenir-db-model 2: attribute-mapped resource, collection and type entities, repositories, the page tree, page metadata, summaries and link normalisation. Framework neutral.
Requires
- php: ~8.3.0 || ~8.4.0 || ~8.5.0
- contenir/contenir-db-model: ^2.0.0-rc5
- contenir/contenir-metadata: ^2.0
- psr/container: ^1.1 || ^2.0
Requires (Dev)
- contenir/contenir-preview: 0.1.x-dev
- contenir/contenir-qa-tools: 0.1.x-dev
- infection/infection: ^0.34.1
- laminas/laminas-servicemanager: ^3.22 || ^4.0
- php-db/phpdb-sqlite: ^0.2.0 || 0.3.x-dev
- phpunit/phpunit: ^11.5.42
Suggests
- contenir/contenir-preview: Lets a CMS preview show a resource's unsaved values (see docs/previews.md)
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-23 06:25:32 UTC
README
The framework-neutral core for Contenir resources (the pages, articles and other content rows of a Contenir site), built on contenir-db-model 2:
- attribute-mapped entities for the
resource,resource_collectionandresource_typetables; - repositories, including the page tree that routes and navigation are built from;
- a resource manager with the lookups sites use (by id, slug, workflow, type);
- page metadata (title, canonical URL, description, Open Graph and Twitter tags) from
contenir-metadata's
MetadataInterface, with a renderer-agnostic HTML renderer; - plain-text summaries and safe normalisation of editor-entered links.
It has no framework dependency: no Mezzio, PSR-7/PSR-15, laminas-mvc or routing. Use it through an adapter:
- Mezzio: contenir/contenir-resource-mezzio adds workflow routing and navigation, a middleware that resolves the routed resource, URL generation and optional laminas-view helpers.
- laminas-mvc: a 2.x adapter will be published as
contenir/contenir-resource-laminas-mvc. Until then laminas-mvc sites stay on the 1.x line of this package (the1.xbranch andv1.*tags).
Version 2.0 is a rewrite and is not compatible with 1.x; see UPGRADE.md.
Requirements
- PHP 8.3, 8.4 or 8.5
- contenir/contenir-db-model 2.x and contenir/contenir-metadata 2.x
- Any PSR-11 container, for the optional factories
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": "^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 normally.
With laminas-component-installer the
Contenir\Resource\Core\ConfigProvider is added to your configuration automatically. It registers its services
under dependencies; contenir-db-model's own ConfigProvider supplies the EntityManager.
Quick start
use Contenir\Resource\Core\Metadata\MetaTagRenderer; use Contenir\Resource\Core\Metadata\PageMetadataBuilder; use Contenir\Resource\Core\ResourceManagerInterface; $resources = $container->get(ResourceManagerInterface::class); $page = $resources->findActiveBySlug('about'); $metadata = $container->get(PageMetadataBuilder::class)->build($page, 'https://www.example.com/about'); echo $container->get(MetaTagRenderer::class)->render($metadata); // <title>, canonical link, meta tags
Configuration
Everything is optional and lives under contenir_resource:
return [ 'contenir_resource' => [ // Entity classes; each must extend the matching abstract entity. 'resource_entity' => Contenir\Resource\Core\Entity\ResourceEntity::class, 'resource_collection_entity' => Contenir\Resource\Core\Entity\ResourceCollectionEntity::class, 'resource_type_entity' => Contenir\Resource\Core\Entity\ResourceTypeEntity::class, // The site's base URL for canonical URLs. Set it in production: without it the // request's own origin (from the client-controlled Host header) is used. 'base_url' => 'https://www.example.com', // Base URL for relative share-image paths; defaults to base_url, then the request origin. 'image_base_url' => 'https://cdn.example.com', 'description_length' => 160, 'summary_length' => 249, // Service name of a SectionRendererInterface, used to summarise section content. 'section_renderer' => null, ], ];
A key that is present with a value of the wrong type is a ConfigurationException, never silently ignored.
Public API
| Class | Purpose |
|---|---|
Entity\AbstractResourceEntity, Entity\ResourceEntity |
Resource rows; metadata, navigation and routing accessors |
Entity\AbstractResourceCollectionEntity, Entity\ResourceCollectionEntity |
Collection rows |
Entity\AbstractResourceTypeEntity, Entity\ResourceTypeEntity |
Resource type rows |
Entity\ResourceStatus |
The active column: pending, active, inactive, archived |
Repository\ResourceRepository |
Finders and findPageTree() |
Repository\ResourceCollectionRepository, Repository\ResourceTypeRepository |
Finders |
ResourceManagerInterface, ResourceManager |
Lookups by id, slug, workflow, type; collections by type |
Metadata\PageMetadataBuilder, Metadata\PageMetadata |
The head metadata of one page |
Metadata\MetaTagRenderer |
Escaped HTML for any template engine |
Metadata\MetaText |
Plain-text cleaning, summaries and keywords |
Metadata\ImageUrlResolverInterface, Metadata\PathImageUrlResolver |
Share image URLs |
Content\ResourceSummary, Content\SectionAwareInterface, Content\SectionRendererInterface |
Plain-text summaries |
Url\ExternalUrl, Url\ResourceLink |
Safe editor-entered links |
ConfigProvider, Container\*Factory |
Container wiring |
Every concrete class is final; the abstract entities and the interfaces are the extension points.
The docs folder covers each area:
- Entities
- Repositories and the resource manager
- Page metadata
- Summaries and links
- Configuration and container
- CMS previews
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: in-memory SQLite, real EntityManager and ServiceManager 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.