lin3s/cms-kernel
Core kernel for the Lin3s CMS ecosystem, providing foundational abstractions and services to integrate content management into PHP applications. It helps bootstrap CMS features and structure content-driven sites with reusable components.
Pin the exact version — this remains a low-adoption, zero-dependency package, and v0.4.0 is the release you should be evaluating, not dev-master.
composer require lin3s/cms-kernel:0.4.*
Where to look first:
README.md and any docs/ folder — for a base "kernel" package the docs are the contract; the code is mostly abstractions meant to be extended, not used directly.composer.json — check require for the exact Symfony/Doctrine versions and note the v0.4.0 "less strict shared kernel dependency" change: the constraint on the shared Lin3s kernel was loosened, so Composer may now resolve a sibling package version this release was never tested against. Lock it down.lin3s-front-foundation, react-dates fix). Look for the package's CSS/JS/assets directory and its package.json before you assume this is a pure PHP library. It ships a login page and an admin UI you will inherit.Resources/config/*.yml or services.xml) — this is where the kernel wires repositories, factories, event listeners, and (new in 0.4.0) Tactician command handlers. Reading this is faster than reading every class.Model/, Domain/, or Entity/) — these are the classes you subclass.Register the bundle(s) in your kernel/bundles.php, then compile once and inspect what you actually got:
bin/console debug:container --tag=tactician.handler
bin/console debug:container --tag=<vendor tag>
First use case: stand up a single page type. Create your own entity extending the package's base page/model, map it with Doctrine using the same mapping driver the package uses, implement the required abstract methods, and render it through your app's controller — then save it through the command bus if you've opted into that. If persist → fetch via the package repository → render works end-to-end, the rest of the surface area (pages, blocks, menus) is that same extension point repeated.
Extend, don't instantiate. The kernel is a base layer. One entity per content type, each inheriting the kernel's base class and its lifecycle behavior. Keep subclasses thin — only the fields and validation your content type needs.
Write through commands, read through repositories. v0.4.0 adds Tactician command bus support. The idiomatic shape is: controller validates input → builds a command → dispatches on the bus → handler loads the entity via the package repository, mutates it, persists. Keep reads out of the bus; keep the kernel's repository as the read boundary. If your app is on Symfony Messenger, do not mix — either run Tactician alongside it or write a thin adapter in your own container so the kernel's handlers stay untouched.
Composition over inheritance for page content. Pages hold an ordered collection of blocks; blocks are reusable and reference-shared rather than field-duplicated. One block type renders identically wherever it is placed — that is the whole value proposition.
Repository as the read boundary. Inject the package repository (or your subclass) into controllers and services rather than querying with the EntityManager. This preserves locale/status/published filters the kernel applies and stops hand-written DQL bypassing them.
Let the Slug component own URLs. v0.4.0 improves slug behaviour. Generate slugs on create, persist them as data, and treat them as stable identifiers — do not regenerate on every save, or published URLs will churn. If you need per-locale slugs, follow whatever the package's slug/translation pairing does rather than adding a parallel scheme.
Template inheritance mirrors entity inheritance. One base Twig layout per content family, each concrete page type overriding blocks. Keep the kernel's block template naming conventions so new block types are drop-in.
Wire content types as services/tags. If the package exposes a registry or tagged-service mechanism for page/block types, register each type there instead of a switch in a controller.
Consume the shipped frontend, don't fork it. The admin/login styling and JS (foundation, date picker) ship with the package. Publish/copy the built assets into your pipeline. Do not point your build at their source package.json unless you enjoy resurrecting a 2017 Node toolchain — use the dist files.
Integrate at the edges. Admin forms in your form types, routing in your app, persistence and content modeling in the kernel. Decorate services in your container rather than editing vendor code.
require means composer update can silently pull a shared-kernel version the CMS was never tested against. Commit composer.lock, and add a constraint in your root composer.json if the package's own constraint is too loose.debug:container --tag=tactician.handler before debugging your business logic.lin3s-front-foundation. Your validation may now be silently absent — re-test forms, especially anything with server-side gaps.react-dates pinned to an old version. Budget for replacing the admin frontend with your own UI if you need a modern browser story — the PHP side can stay.AppKernel, YAML service configs, getName() bundles). On PHP 8+ you'll hit dynamic-property and return-type deprecations before real bugs. react-dates and foundation pins mean the JS side drifts too.bin/console cache:clear before debugging — stale compiled containers produce "service not found" errors unrelated to your code.debug:container --tag=..., debug:event-dispatcher, and (for 0.4.0) debug:container --tag=tactician.handler. Most "the package isn't doing anything" reports are missing bundle registration or a missing tag.How can I help you explore Laravel packages today?