Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Content Bundle Laravel Package

opifer/content-bundle

Opifer ContentBundle is a Symfony CMS bundle for managing pages and reusable content blocks. It provides structured content types, template integration, and admin tooling to help teams build and maintain content-driven PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

This is not a Laravel package. It's a Symfony 2.x/3.0-era bundle (last subtree split 2016-01-13, MIT, archived) that ships the domain model and rendering for a page/block CMS. The admin UI lives in the sibling opifer/cms-bundle; this split gives you Content (a page with slug + alias), Template (a pointer to a Twig view), Block (a reusable content chunk) and ContentBlock (the ordered join between them).

Minimal path:

  1. Verify it will install. composer require opifer/content-bundle only resolves inside a Symfony ^2.7/^3.0 app. If it fails, run composer why-not opifer/content-bundle — the answer is usually symfony/symfony or doctrine/orm. There is no Laravel integration route here without building your own bridge for Doctrine + Form + Twig; practically, don't.
  2. Register the bundle in app/AppKernel.php (new Opifer\ContentBundle\OpiferContentBundle()) and import its routing (resource: "@OpiferContentBundle/Resources/config/routing.yml") under whatever prefix you want.
  3. Dump the config reference — bin/console config:dump-reference opifer_content — before writing any YAML. The tree carries the class parameters (content_class, block_class, template_class, etc.) that you must point at your own entities.
  4. Create concrete entities extending the bundle's models (e.g. AppBundle\Entity\Content extends Opifer\ContentBundle\Model\Content), map them with Doctrine annotations, and wire the FQCNs into opifer_content. Then doctrine:schema:update --force.

Where to look first, in order:

  • Model/Content.php, Model/Block.php, Model/Template.php — the actual data contract.
  • ContentManager.php / BlockManager.php — the two services (opifer.content.content_manager, opifer.content.block_manager) you'll call from your own code.
  • Controller/ContentController.php — the reference rendering pipeline to copy or override.
  • Resources/config/services.xml and DependencyInjection/Configuration.php — the only source of truth for service IDs and config keys.

First useful thing to build: seed one Template row (name + Twig view path), create a Content with slug home, and render it from your own controller:

$content = $this->get('opifer.content.content_manager')
    ->getRepository()
    ->findOneBy(['slug' => $slug, 'active' => true]);

return $this->render($content->getTemplate()->getView(), ['content' => $content]);

That's the whole loop: slug → active content → template view → blocks.

Implementation Patterns

Entity inheritance is mandatory, not optional. The bundle's models are mapped superclasses; you cannot use them directly. Create Content, Block, Template, ContentBlock in your app, map them, and register the class names in opifer_content. If the bundle exposes resolve_target_entities, point those at your classes too so associations (e.g. a page's template) resolve correctly.

Query through the manager, not the entity manager. ContentManager centralizes repository creation and any slug/alias lookups. Calling $em->getRepository(Content::class) directly works but bypasses whatever filters the manager applies, and it's the first thing to break if you later swap the class.

Model a block type as a trio. Each block kind is three artifacts:

  • an entity subclass (TextBlock extends Block) holding the payload (value, media, url, …);
  • a Symfony FormType that edits those fields — this is what the admin uses to configure the block;
  • a Twig partial that renders it on the frontend.

Shared fields (title, name, active) live on Block; never re-declare them in the subclass. Register block types the way the bundle's compiler pass expects (check DependencyInjection/Compiler/ for the tag name) — an unregistered block type silently never appears in the editor.

Compose pages through ContentBlock, not a plain collection. Ordering is a position integer on the join entity. To append a block:

$content->addBlock($block);      // creates the ContentBlock join
$em->persist($content);
$em->flush();

Reordering means renumbering the position values yourself and flushing once; there is no ordering service.

Prefer copying the controller over fighting it. Subclass ContentController, override the action, and register your route before the bundle's. You keep the bundle's 404/inactive handling and gain full control over variables passed to the view.

Seed templates via fixtures. Template rows are database config that point at Twig file names. Committing a fixture that creates them (with explicit view strings) is the only way to keep a multi-environment install in sync, since the admin UI is in a different package.

No autowiring. services.xml is explicit Symfony 2 style. Consume the managers by ID ($this->get('opifer.content.content_manager')) or inject them by ID in your own service definition. Don't expect __construct(ContentManager $m) to resolve on its own.

Cache deliberately. Nothing purges HTTP/proxy caches when content changes. Either key the cache on content + block IDs, or add a Doctrine postUpdate/postPersist listener that clears the page's cache entry. This is the single biggest pattern omission in the bundle.

Gotchas and Tips

  • Abandoned since 2016. No security patches, PHP 5.5–7.0 idioms, no Symfony 4+ compatibility. If you inherit a project using it, budget for a fork-and-maintain decision rather than an upgrade path.
  • Read-only subtree split. PRs against this repository go nowhere — the source lives in the monorepo. If you need a patch, fork, and pin it via a repositories entry (type: vcs) plus a replace for the original name; don't expect upstream merges.
  • "Class X was not found in the chain configured namespaces" almost always means a *_class config value is missing or points at the abstract model instead of your concrete entity. Confirm with bin/console doctrine:mapping:info.
  • Mapped-superclass traps: you can't redeclare inherited fields or associations. To retarget an inherited association (e.g. to your own Media entity) use @ORM\AssociationOverride, not a new property.
  • Template typos are runtime failures. A bad view string on a Template row surfaces as a Twig LoaderError at render time, not at save time. Validate the view exists in your fixture/admin save path.
  • Slug and alias collisions fail silently — you get a 404, not an exception. If you rely on alias for secondary URLs, add a uniqueness check in your own code.
  • Raw HTML blocks are raw. Some block types pass user content straight into Twig with |raw. If editors aren't fully trusted, sanitize in the block's Twig partial or before persist.
  • Block ordering drifts. Duplicate or skipped position values render in database order, which looks random after a few edits. Renumber on every save if you build your own editor.
  • Debug with the container, not the docs: bin/console debug:container opifer.content lists the actual services (the docs and README are stale), bin/console debug:router | grep -i content shows what routing you really imported, and config:dump-reference opifer_content is the only accurate config schema.
  • Override services carefully. If the manager's class isn't parameterized, write a compiler pass using setDefinition or decorate rather than editing the bundle's XML — a composer update (if the repo is still reachable) would overwrite it.
  • Smoke-test after any change: load one Content, render each Template's view with a dummy content variable. The bundle's own test coverage is thin, and a failing template only shows up on the exact page that uses it.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect