th3mouk/cms-core-bundle
A CMS core bundle for PHP applications that provides the foundational models, services, and configuration for building content-managed sites. It aims to give developers reusable page and content primitives to extend, though the project is early-stage with limited adoption and sparse documentation, s...
The first step is a framework reality check: this is a Symfony bundle, not a Laravel package. There is no service provider, no config/publish.php, no package auto-discovery, and no Eloquent/Blade integration. A Laravel composer require will not wire anything up, and even if the dependency resolves, none of the bundle's classes will be registered. So "getting started" for a Laravel developer means treating the repo as reference material, not a dependency.
For a Symfony developer, the actual starting sequence is:
composer.json first. The bundle's stated purpose is "providing dependencies and basic configuration for the CMS Starter project," so the require/require-dev lists and the Symfony version constraint are the package. Read them before you read a single PHP file — that tells you what stack this was designed for (which Symfony LTS, which PHP version, which Doctrine ORM).main as read-only source.composer create-project symfony/skeleton /tmp/probe
cd /tmp/probe
composer require th3mouk/cms-core-bundle --dry-run
The --dry-run output is more useful than an actual install: it shows which Symfony packages must be downgraded to satisfy the bundle's pins. That output is usually the point at which you decide not to install it.Resources/config/ tree. If CMSCoreBundle.php registers a DI extension, that extension plus services.yaml/services.xml is where all behavior actually lives. Entities referenced from Resources/config/doctrine/ are where page/block/menu models are defined.config/bundles.php, import its routing, and let it wire up its default entities. Then define one content type and one template to prove the extension mechanism works on your Symfony version. If that fails due to a removed framework API, you've confirmed the archive risk in ten minutes and saved yourself a sprint.For anyone building a Laravel CMS, the productive use of this repo is a ten-minute skim of its dependency list as a checklist of "what does a minimal CMS actually need" — routing, ORM entities, admin/templating, navigation helpers — then closing the tab.
Because the bundle is a scaffold-plus-default-config, the day-to-day patterns are about extension, not usage. The patterns below describe how the bundle is designed to be shaped, which matters most if you are reading it as a reference for your own skeleton.
Extending content types via configuration. The bundle's selling point is "extensible content types via configurable templates." In practice this means a config node (likely under cms_core: in your Symfony config) maps a content-type key to a template and possibly a Doctrine entity class. Your integration sits on top: you register your content types and your templates, and the bundle dispatches by type. The pattern to internalize is type → template → renderer, which you can reimplement in a Laravel CMS as a polymorphic content table plus a view resolver.
Page & block persistence. Pages and blocks are Doctrine entities. Extension is typically done by:
Page/Block base entities, annotate the parent as @MappedSuperclass, and add your own columns.This is the pattern to look for first when auditing the code, because it determines how much is genuinely reusable versus how much is baked in.
Menu and navigation helpers. Expect a service that reads a repository of menu items and returns a tree. The integration point is usually a Twig extension or a service you inject into your controller to build a nav model. If you're reimplementing on Laravel, the equivalent is a Menu model with a MenuBuilder service resolved via the container — same shape, different wiring.
Routing and SEO metadata. "SEO-friendly routing" typically means a slug-based route that resolves a page and attaches title/meta/canonical to the response. The pattern is a catch-all route that looks up a slug in the page repository and either renders the matching template or 404s. This is the first thing to look at, because it dictates how the rest of the site's URLs are structured.
Integration with an existing Symfony app. The safe integration shape is:
config/bundles.php.config/packages/cms_core.yaml, then override only what you need.Workflow note for a team. The correct internal workflow is fork → vendor into a first-party skeleton → own the pins → never composer require the upstream. If you take anything from this repo, take the shape of the config tree and the entity relationships, not the package.
The archive status is the primary gotcha. Everything below is a downstream consequence of "no one is maintaining this."
symfony/* and php constraints are frozen. Expect composer why-not to point at a Symfony minor or a removed API. Do not spend time trying to force-resolve; the resolution failure is the answer.composer audit and composer outdated will flag entries you can't fix without forking them too.bin/console config:dump-reference cms_core (or whatever the extension is named) to confirm the config tree, and bin/console debug:container to confirm which services actually got registered from the bundle.Page and you also map Page in your app, metadata loading silently picks one. Extend via mapped superclass or override the configured class name; do not duplicate mappings./login went.Controller::get()/getDoctrine() calls that no longer exist, @Route annotation loader changes, and event subscriber signatures that no longer match. Grep for getDoctrine, get(), and KernelEvents constants before you invest in a fork.Resources/config/doctrine/ mappings (what the entity contract actually is).Resources/config/services.yaml) — these define the public API far more concretely than the README.Resources/views/ — these are the real interface for a CMS.replace/provide semantics in your fork's composer.json so the upstream package name cannot reappear transitively, and pin the fork to your own versioning scheme. Document the provenance in the fork's README; otherwise the next engineer will spend a day wondering why this abandoned-looking module exists in the tree.bin/console debug:container --tag=kernel.event_subscribers, then walk outward to debug:router, then debug:config <extension>. In a few minutes you'll know whether executable code is even present, which changes the effort estimate by an order of magnitude.Bottom line for a developer picking this up: use it as a reading exercise and a config checklist, not a runtime dependency. The cost of reading it is an afternoon; the cost of depending on it is unbounded and lands entirely on your team.
How can I help you explore Laravel packages today?