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

integrated/content-bundle

integrated/content-bundle is a Laravel package that bundles content management capabilities into a single integration, helping you organize, store, and serve structured content using familiar PHP and Laravel conventions.

View on GitHub
Deep Wiki
Context7

Getting Started

Step 0 is access, not code. The repo lives on Bitbucket and is not on Packagist, so nothing works until your machine and CI can authenticate. Add a Composer VCS entry and provision a read-only Bitbucket app password (or SSH key) scoped to this repo:

"repositories": [
  { "type": "vcs", "url": "[email protected]:eactive/integrated-content-bundle.git" }
]

Then composer require integrated/content-bundle — but pin to a commit SHA or tag immediately, and prefer mirroring the repo into your own org (or a private Satis proxy) so builds never depend on eactive's availability or every dev's credentials.

Read these four things before anything else, in this order:

  1. composer.json — require and autoload. This single file answers the only question that matters: is this a Symfony bundle (symfony/framework-bundle, symfony/twig-bundle, doctrine/orm deps, psr-4 under a Bundle namespace), a Laravel package (a ServiceProvider, illuminate/*), or framework-agnostic PHP? The -bundle suffix plus a Bitbucket host strongly suggests Symfony 2/3/4 era.
  2. The bundle/entry class — *Bundle.php with getContainerExtension(), or a *ServiceProvider.php. That tells you the runtime it targets.
  3. DependencyInjection/ + Resources/config/ — the config tree and service wiring are the actual API surface. Everything you can configure is declared in the extension.
  4. Entity/ (or Model/) + Resources/views/ — the content domain model (types, blocks, pages) and the Twig templates, which is where the "render" half of the description lives.

Your first use case — pick the honest one:

  • If your stack includes Symfony: register the bundle in config/bundles.php, import its config, add the Doctrine mapping, run the migrations, create one simple content type (e.g. a "hero" block), and render it through its Twig template on a page. That is the end-to-end smoke test.
  • If your stack is Laravel-only: do not try to install it into the Laravel app as step one. Composer will happily download the files, but no ServiceProvider will register, no routes/views/config will be wired, and you'll be debugging a stack that isn't there. Instead, stand up a throwaway Symfony skeleton (composer create-project symfony/skeleton), wire the bundle there, and make one content type render. Your goal in that spike is not "make it run in Laravel" — it is to learn the domain model and decide whether to port the model or wrap the package. Budget one week and treat a failed boot as a valid, cheap answer.

Only after that spike does a Laravel integration plan make sense — and it will almost certainly be "port the content model into Eloquent + Blade," not "install the bundle."

Implementation Patterns

Wrap it. This is the whole strategy. Put your own contracts in front of the package from day one and never let its types reach a controller, Blade view, or queued job:

interface ContentRepository {
    public function findBySlug(string $slug, string $locale): ?Content;
    public function blocksFor(Content $content): array;
}
interface ContentRenderer {
    public function render(Content $content): string;
}

The package becomes a replaceable adapter. This converts a private, undocumented dependency into a bounded swap if the vendor goes quiet — which, with zero dependents and no public tracker, you should assume will happen eventually.

Content-type-driven rendering. Expect the core workflow to be: an editor picks a block/content type in the admin surface → your code supplies the template for that type → the bundle composes the page. Day-to-day, a developer's job is defining that mapping and the templates, not editing stored content. Keep block templates in a predictable namespace with a fallback chain, so an unknown or new block type degrades to a neutral partial instead of a 500:

{% include [
    '@Content/blocks/' ~ block.type ~ '.html.twig',
    '@Content/blocks/_fallback.html.twig'
] with { block: block } only %}

Use only to keep block context isolated — it stops one block's variables leaking into another and makes blocks independently testable. If you port to Blade, mirror the same fallback logic with @includeFirst.

Cache rendered fragments, invalidate on write. Content rendering is read-heavy; do not re-walk the block tree per request. Render once and key the cache by content id + locale + a version/updated-at stamp. If the bundle owns its own cache layer (common in Symfony-era bundles), point it at your Redis rather than the filesystem — check its extension config for a cache pool/service setting before assuming.

Hook writes at the persistence boundary. In Symfony that's Doctrine lifecycle callbacks/event subscribers; in Laravel it's model events or an observer. Either way, invalidate the fragment cache there rather than in the admin controller — content also changes via imports, seeds, and console commands.

Localization. Assume content records are per-locale and you resolve locale in the repository, not the template. If the bundle has no locale concept, that's a schema change you own.

Admin surface. If the bundle ships its own admin controllers, decide early whether you adopt them or replace them with your app's resource CRUD (Filament/Nova/EasyAdmin). Adopting its admin means adopting its auth and routing assumptions; replacing it means the bundle is a renderer only — often the cleaner boundary.

Template override over forking. Symfony bundles support overriding templates by placing files under templates/bundles/<BundleName>/.... Prefer that, plus the config tree and tagged services, before you touch vendor code. Every line you fork is a line you re-merge.

Testing pattern that pays for itself: golden-file tests — render a fixture content tree and assert the exact output. That is your tripwire for a silent serialization or template change after an upgrade.

Gotchas and Tips

  • The framework mismatch is the headline gotcha. A Symfony -bundle in a Laravel app is not an install, it's a port. Its DI config, config tree, Doctrine mappings, and Twig templates have no runtime equivalent in Laravel's container/Eloquent/Blade stack. Confirm this in composer.json before you spend an hour on composer require.
  • Two ORMs in one process is a real cost. If the bundle owns Doctrine entities, you'll have Doctrine alongside Eloquent. Cross-ORM joins, transactions spanning two connections, and duplicated identity logic are all day-to-day friction. If you must run both, isolate it on a separate DB connection and treat the content store as external — reference it by ID, never by relationship.
  • Migrations you don't control. Namespace its tables, review every migration diff before deploy, and watch for ordering conflicts with your own migrations. Schema drift on an unowned package is silent until it corrupts content.
  • Template names and config keys are undocumented. Discover them with bin/console debug:container --tag=<tag>, debug:config <alias>, and debug:router. There is no Stack Overflow corpus for this package — the source is the documentation.
  • Editor-supplied HTML is an XSS vector. |raw in Twig or {!! !!} in Blade around content stored by editors is the classic mistake. Sanitize on save (HTMLPurifier or equivalent) and escape by default in every template.
  • Escaping and context. Block context objects passed into includes are easy to double-escape or accidentally dump with {{ block }}. Render leaf fields explicitly.
  • Pin and mirror. Never track a branch. Vendor the repo or use a Satis proxy, commit the composer.lock, and keep Composer credentials read-only and out of CI logs — rotating an expired Bitbucket app password should not be able to break a production build.
  • No release cadence means no BC guarantee. Establish the last-commit date and whether tags exist during qualification. If it's a moving branch, you now own the upgrade path; write a short internal README covering the dependency map, the adapter boundary, and the upgrade runbook, because onboarding otherwise happens by pairing only (expect 2–3 weeks before a new dev can safely change rendering).
  • Define an abandonment trigger now. Pre-agree "if the package blocks a framework/PHP upgrade for more than one sprint, we replace it behind the adapter." A private dependency without that trigger becomes a permanent tax on every future upgrade.
  • Prefer extension points, in this order: config tree → tagged services / event subscribers → template override → fork. Fork only with the license question answered in writing, and log the diff so re-merges are tractable.
  • Debugging a blank render usually means a template lookup missed (wrong namespace, wrong block type string) or the content wasn't hydrated because a mapping/config import was absent. Check the template resolution path and the container's config before you suspect the renderer.
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.
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo
bernskioldmedia/laravel-harvest
bernskiold/laravel-data-scrubber
bernskiold/laravel-currency-converter
bernskiold/laravel-campaign-monitor
bernskioldmedia/laravel-autotranslate
siberfx/telegram-bot
roy-sandip/laravel-view-extended
gregsphotography/site-builder-core
roy-sandip/laravel-view
anodyne/blade-fluentui-icons
webx-ui/module-catalog-collections