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

Block Bundle Laravel Package

enhavo/block-bundle

Enhavo Block Bundle is a subtree split of the open-source Enhavo CMS, built on the Symfony PHP framework. It provides flexible block components for managing complex data structures through a clean, usable interface. See the main repository for details.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is a read-only subtree split of the enhavo/enhavo monorepo. Treat the GitHub README as a pointer, not documentation: almost everything you need is in the source of the main repo and in the bundle's src/.

  1. Install via the monorepo, not alone. In a normal Enhavo application this bundle arrives as a dependency of enhavo/enhavo (or the relevant Enhavo meta-package). Requiring enhavo/block-bundle in isolation is only useful if you are deliberately assembling a subset of the CMS; otherwise you will fight missing sibling bundles (form, routing, asset, template bundles) all day.
  2. Register the bundle in config/bundles.php if it is not already registered:
    Enhavo\Bundle\BlockBundle\EnhavoBlockBundle::class => ['all' => true],
    
  3. Look at these files first, in this order:
    • src/EnhavoBlockBundle.php – what services/compiler passes it wires.
    • src/Resources/config/ – service definitions, tags, and any Configuration.php for the enhavo_block tree. This is the real "API surface" for enabling/disabling block types.
    • src/Form/Type/ – block types are Symfony form types; each one tells you the block's fields and, usually, its template/component name.
    • src/Entity/ (or src/Model/) – the block entities, the abstract base block, and how blocks are associated to pages/content nodes.
    • src/Resources/views/ – the render templates and their naming convention.
  4. First use case: attach a built-in text block to a page-like entity, render it in a template, and confirm it appears in the admin form. That single loop exercises the entity, the form type, the block manager, and the renderer — the four things you will touch every day.

Because the README is essentially a stub, budget an hour for source reading before your first commit. There are no published API docs for this split; the main repository's docs and test suite are your reference.

Implementation Patterns

The three-part block contract

In Enhavo, a block is almost always a triad:

  • Entity extending the bundle's abstract block class (persisted with Doctrine inheritance/discriminator mapping).
  • Form type extending the bundle's abstract block type, declaring fields and identifying the admin component/template.
  • Template rendering the entity, usually placed under a conventional path so the renderer can resolve it without configuration.

When adding a custom block, add all three and register the form type as a service. Copy an existing, simple block (text or picture) end-to-end rather than starting from scratch — the base classes carry required methods you will otherwise miss.

Building a custom block

// src/Entity/PromoBlock.php
class PromoBlock extends AbstractBlock
{
    private ?string $headline = null;
    private ?string $ctaUrl = null;
    // getters/setters
}
// src/Form/Type/PromoBlockType.php
class PromoBlockType extends AbstractBlockType
{
    public function getComponent(): string { return 'promo-block'; }
    public function getTemplate(): string { return '@App/blocks/promo.html.twig'; }
    public function getLabel(): string { return 'Promo block'; }

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->add('headline', TextType::class)
                ->add('ctaUrl', UrlType::class);
    }
}

Register the type and, if the bundle uses a tagged locator or a config map for blocks, add it there too (check Configuration.php — some Enhavo versions enumerate block types in enhavo_block.blocks). A block type that is registered as a service but absent from the config map will simply not appear in the admin picker.

Attaching blocks to content

Pages and other "blockable" entities in Enhavo typically implement a block-node interface and use a trait for getBlocks() / addBlock() with an ordered, one-to-many relation. If you are creating your own block-holding entity, reuse that interface and trait rather than inventing your own collection — the admin form types and renderer expect it.

Rendering

Rendering usually goes through the bundle's renderer service or a Twig helper, resolving the block to its template:

{% for block in page.blocks %}
    {{ block_render(block) }}
{% endfor %}

Exact helper naming varies by version; check the Twig extension in src/Twig/ before assuming. For one-off layouts, including the template directly ({% include block.template %}) works but bypasses the renderer's resolution, caching, and nested-block handling — prefer the renderer unless you have a reason not to.

Overriding built-in blocks

Two non-invasive extension points cover most day-to-day needs:

  • Template override: place a file at the standard Symfony bundle-override path (templates/bundles/EnhavoBlockBundle/...) to restyle an existing block without touching vendor code.
  • Form type extension: use a Symfony FormTypeExtension to add a field to an existing block type instead of forking the entity.

Gotchas and Tips

  • Read-only split. Never open PRs or issues against EnhavoBlockBundle; changes belong in enhavo/enhavo. The split repo history is regenerated, so local patches there will be lost.
  • Version alignment. A subtree split can drift from the monorepo. Pin this package to the exact version of the Enhavo core you run; a mismatch between enhavo/block-bundle and the sibling bundles manifests as missing services or "class not found" in the DI container, not as an obvious version error.
  • Silent blank output. If a block renders nothing, the template path in getTemplate() is the usual culprit. Use bin/console debug:twig and enable Twig's template hints in the profiler to see which path was actually attempted.
  • Doctrine inheritance. Blocks are stored polymorphically. Adding a block class means a new discriminator value and therefore a migration; renaming or removing one is worse. Plan block class names as if they were database columns.
  • Config map vs. service tag. It is easy to register a block type correctly and still not see it in the admin UI because it is absent from the enhavo_block configuration. When a block "doesn't exist", check both registration mechanisms.
  • Admin assets. Enhavo's admin is a JS component layer; the getComponent() value must correspond to a registered frontend component. A block that works in the frontend can still be broken in the editor if the component name is wrong.
  • Nested and reusable blocks. Blocks can be nested or shared. Be explicit about ownership (composition vs. reference) — a block referenced in two pages will show edits in both, which is sometimes desired and often a support ticket.
  • Caching. Rendered blocks are cacheable; if content edits appear stale, clear the application cache and check whether the renderer caches by block id without invalidation.
  • Debugging commands worth memorizing:
    bin/console debug:container --tag=<block tag>   # is my block type registered?
    bin/console config:dump-reference enhavo_block   # what options exist?
    bin/console doctrine:mapping:info                # discriminator sanity check
    
  • Testing. The main repository's tests are the best executable specification for this bundle; port the relevant block test case into your app when you add a custom block type.
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.
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json