PHPackages                             blackcube/dcore - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Localization &amp; i18n](/categories/localization)
4. /
5. blackcube/dcore

ActiveLibrary[Localization &amp; i18n](/categories/localization)

blackcube/dcore
===============

CMS core data layer

1.0.0(1mo ago)015↓33.3%3BSD-3-ClausePHPPHP ^8.1

Since Apr 4Pushed 1mo agoCompare

[ Source](https://github.com/blackcubeio/dcore)[ Packagist](https://packagist.org/packages/blackcube/dcore)[ Docs](https://github.com/blackcubeio/dcore)[ RSS](/packages/blackcube-dcore/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (22)Versions (3)Used By (3)

Blackcube dcore
===============

[](#blackcube-dcore)

CMS data layer — models, trees, dynamic properties, SEO, translations.

[![License](https://camo.githubusercontent.com/6cb285b57819f8de0acfb34923298f4f569f962544e8fe35331da2d163f4e485/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4253442d2d332d2d436c617573652d626c75652e737667)](LICENSE.md)[![Packagist Version](https://camo.githubusercontent.com/d2c4a1e22cf05fd13e5aeb5802f8610fac0586b57f69b87d48a403e0979cec43/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f626c61636b637562652f64636f72652e737667)](https://packagist.org/packages/blackcube/dcore)

Installation
------------

[](#installation)

```
composer require blackcube/dcore
```

Requirements
------------

[](#requirements)

- MySQL/MariaDB (for JSON column and tree support)

Why dcore?
----------

[](#why-dcore)

ApproachProblemFull-stack CMSMonolith. You want a page? Take the whole engine.Headless CMS (SaaS)Vendor lock-in. Your data lives elsewhere.Raw ActiveRecord15 models, 8 pivots, tree management, JSON schema validation — from scratch?**dcore**None of the above**Your data stays yours.** MySQL tables, your server, your backups.

**Trees without recursion.** Content, Tag and Menu are tree-structured via [Hazeltree](https://github.com/blackcubeio/hazeltree) — one query, no cache.

**Dynamic properties without EAV.** JSON Schema validation, virtual columns, transparent queries via [Elastic](https://github.com/blackcubeio/elastic).

**SEO is built in.** Per-URL metadata (Xeo), global config (GlobalXeo), sitemap.xml, robots.txt — not bolted on after.

**Multilingual by design.** Translation groups link Contents across languages. Not an afterthought.

Capabilities per model
----------------------

[](#capabilities-per-model)

ModelTreeDynamic propertiesBlocsTagsAuthors`Content`yesyesyesyesyes`Tag`yesyesyesnoyes`Bloc`noyesnonono`Menu`yesnononono`GlobalXeo`noyesnononoQuick Start
-----------

[](#quick-start)

### 0. Bootstrap the database connection

[](#0-bootstrap-the-database-connection)

dcore needs a `Yiisoft\Db\Connection\ConnectionInterface` registered in your DI container, and `ConnectionProvider::set()` called at bootstrap.

```
// DI container
use Yiisoft\Db\Connection\ConnectionInterface;
use Yiisoft\Db\Mysql\Connection;
use Yiisoft\Db\Mysql\Driver;
use Yiisoft\Db\Cache\SchemaCache;
use Yiisoft\Cache\ArrayCache;

return [
    ConnectionInterface::class => static function (): ConnectionInterface {
        $driver = new Driver("mysql:host=localhost;dbname=mydb;port=3306", 'user', 'password');
        $driver->charset('UTF8MB4');
        return new Connection($driver, new SchemaCache(new ArrayCache()));
    },
];
```

```
// Bootstrap
use Psr\Container\ContainerInterface;
use Yiisoft\Db\Connection\ConnectionProvider;
use Yiisoft\Db\Connection\ConnectionInterface;

return [
    static function (ContainerInterface $container): void {
        ConnectionProvider::set($container->get(ConnectionInterface::class));
    },
];
```

### 1. Run migrations

[](#1-run-migrations)

```
php yii.php migrate:up
```

### 2. Create a content type

[](#2-create-a-content-type)

```
use Blackcube\Dcore\Models\Type;
use Blackcube\Dcore\Models\ElasticSchema;
use Blackcube\Dcore\Enums\ElasticSchemaKind;

$schema = new ElasticSchema();
$schema->setName('Article');
$schema->setSchema(json_encode([
    'type' => 'object',
    'properties' => [
        'subtitle' => ['type' => 'string'],
        'image' => ['type' => 'string'],
        'body' => ['type' => 'string'],
    ],
]));
$schema->setKind(ElasticSchemaKind::Page);
$schema->setActive(true);
$schema->save();

$type = new Type();
$type->setName('Article');
$type->setHandler('article');
$type->setContentAllowed(true);
$type->save();
```

### 3. Create content in a tree

[](#3-create-content-in-a-tree)

```
use Blackcube\Dcore\Models\Content;

$blog = new Content();
$blog->setName('Blog');
$blog->setLanguageId('en');
$blog->setTypeId($type->getId());
$blog->setElasticSchemaId($schema->getId());
$blog->save(); // root node

$article = new Content();
$article->setName('First Post');
$article->setLanguageId('en');
$article->setTypeId($type->getId());
$article->setElasticSchemaId($schema->getId());
$article->subtitle = 'Hello world';
$article->saveInto($blog); // child of Blog
```

### 4. Attach blocs

[](#4-attach-blocs)

```
use Blackcube\Dcore\Models\Bloc;

$bloc = new Bloc();
$bloc->setElasticSchemaId($blocSchema->getId());
$bloc->setActive(true);
$bloc->save();

$article->attachBloc($bloc);       // appends at last position
$article->attachBloc($bloc2, 1);   // inserts at position 1
$article->moveBlocUp($bloc2);      // reorder
```

### 5. Query with visibility scopes

[](#5-query-with-visibility-scopes)

```
// Published content in French, root nodes only
Content::query()
    ->language('fr')
    ->publishable()
    ->roots()
    ->all();

// Children of a node, active only
Content::query()
    ->forNode($blog)
    ->children()
    ->active()
    ->all();

// Filter on dynamic JSON properties
Content::query()
    ->available()
    ->andWhere(['subtitle' => 'Hello world'])
    ->all();
```

### 6. SEO

[](#6-seo)

```
use Blackcube\Dcore\Models\Xeo;
use Blackcube\Dcore\Models\Sitemap;

$xeo = new Xeo();
$xeo->setSlugId($slug->getId());
$xeo->setTitle('First Post — My Blog');
$xeo->setDescription('An introduction to dcore.');
$xeo->setOg(true);
$xeo->setOgType('article');
$xeo->setActive(true);
$xeo->save();

$sitemap = new Sitemap();
$sitemap->setSlugId($slug->getId());
$sitemap->setFrequency('weekly');
$sitemap->setPriority(0.8);
$sitemap->setActive(true);
$sitemap->save();
```

### 7. Translations

[](#7-translations)

```
$contentFr->linkTranslation($contentEn);

$translations = $contentFr->getTranslationsQuery()->all();
$english = $contentFr->getTranslationsQuery()
    ->andWhere(['languageId' => 'en'])
    ->one();
```

Models vs Entities
------------------

[](#models-vs-entities)

dcore provides two namespaces for each model:

NamespaceDefault scopeUse case`Blackcube\Dcore\Models\Content`noneAdmin, backoffice`Blackcube\Dcore\Entities\Content``->publishable()`Frontend, public renderingEntities extend Models and override `query()` to automatically filter by publishable status (active + dates + ancestors). Use Models when you need full access, Entities when you render for visitors.

```
// Backoffice — see everything
use Blackcube\Dcore\Models\Content;
Content::query()->all();

// Frontend — only published content
use Blackcube\Dcore\Entities\Content;
Content::query()->language('fr')->roots()->all();
// publishable() is already applied
```

Architecture
------------

[](#architecture)

### Models

[](#models)

ModelTableDescription`Content``contents`Editorial content. Tree-structured, typed, multilingual.`Tag``tags`Taxonomy. Tree-structured, typed.`Bloc``blocs`Reusable content brick. Carries dynamic properties.`Menu``menus`Navigation item. Tree-structured, linked to host and language.`Slug``slugs`URL (host + path). Can be a redirect.`Host``hosts`Domain. `id=1` = wildcard.`Type``types`Content/tag type. Carries SSR handler and allowed schemas.`Language``languages`Available language. String PK.`ElasticSchema``elasticSchemas`JSON Schema for dynamic properties.`Author``authors`Author (schema.org Person).`Xeo``xeos`Per-URL SEO metadata.`GlobalXeo``globalXeos`Global SEO per host + kind.`Sitemap``sitemaps`Per-URL sitemap configuration.`Parameter``parameters`Key-value parameters per domain.`TranslationGroup``translationGroups`Translation group linking Contents.### Services

[](#services)

ServiceRole`HandlerDescriptor`Path → SSR handler resolution. CMS routing entry point.`PreviewManager`HMAC-signed preview mode. Date simulation for pre-publication.`HazeltreeSlugGenerator`Automatic slug generation based on tree position.### HTTP Handlers

[](#http-handlers)

HandlerRouteRole`SitemapHandler``sitemap.xml`Generates the XML sitemap.`RobotsHandler``robots.txt`Generates robots.txt from GlobalXeo.`RedirectHandler`(slug redirect)Redirects according to Slug targetUrl/httpCode.Documentation
-------------

[](#documentation)

Detailed documentation is available in two languages:

- [English](docs/en/index.md)

Let's be honest
---------------

[](#lets-be-honest)

**This is a data layer, not a CMS.**

There is no admin panel, no page builder, no theme engine. dcore gives you models, queries, and handlers. You build the application around it.

**ActiveRecord.**

dcore depends on `yiisoft/active-record`. Any framework works as long as you provide a `Yiisoft\Db\Connection\ConnectionInterface` in the DI container.

License
-------

[](#license)

BSD-3-Clause. See [LICENSE.md](LICENSE.md).

Author
------

[](#author)

Philippe Gaultier

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance91

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

44d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/545714?v=4)[pgaultier](/maintainers/pgaultier)[@pgaultier](https://github.com/pgaultier)

---

Top Contributors

[![pgaultier](https://avatars.githubusercontent.com/u/545714?v=4)](https://github.com/pgaultier "pgaultier (2 commits)")

---

Tags

json-schemamultilingualtreecmsheadlessactive-recordseocontent management

###  Code Quality

TestsCodeception

### Embed Badge

![Health badge](/badges/blackcube-dcore/health.svg)

```
[![Health](https://phpackages.com/badges/blackcube-dcore/health.svg)](https://phpackages.com/packages/blackcube-dcore)
```

###  Alternatives

[typicms/base

A modular multilingual CMS built with Laravel, enabling developers to manage structured content like pages, news, events, and more.

1.6k20.3k](/packages/typicms-base)[asgardcms/platform

The AsgardCms application.

78860.8k](/packages/asgardcms-platform)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
