Weave Code
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

app-verk/block-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require app-verk/block-bundle
    

    Enable the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):

    AppVerk\BlockBundle\BlockBundle::class => ['all' => true],
    
  2. First Block Creation: Create a block class extending AbstractBlock:

    // src/Block/FirstBlock.php
    namespace App\Block;
    
    use AppVerk\BlockBundle\Block\AbstractBlock;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    
    class FirstBlock extends AbstractBlock {
        protected function configureOptions(OptionsResolver $resolver) {
            $resolver->setDefaults([
                'title' => 'Default Title',
                'template' => '@App/Block/first.html.twig'
            ]);
        }
    }
    
  3. Register as Service:

    # config/services.yaml
    services:
        App\Block\FirstBlock:
            public: true
            tags: ['block']
    
  4. First Render:

    {{ render_block('App\\Block\\FirstBlock', {
        'title': 'Custom Title'
    }) }}
    

First Use Case: Dynamic Sidebar

Create a block for a reusable sidebar component:

// src/Block/SidebarBlock.php
class SidebarBlock extends AbstractBlock {
    protected function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults([
            'items' => [],
            'template' => '@App/Block/sidebar.html.twig'
        ]);
    }
}

Render with:

{{ render_block('App\\Block\\SidebarBlock', {
    'items': [{'title': 'Item 1'}, {'title': 'Item 2'}]
}) }}

Implementation Patterns

Core Workflow

  1. Block Development:

    • Extend AbstractBlock for all custom blocks.
    • Override configureOptions() to define default settings.
    • Implement execute() for complex logic (e.g., DB queries, API calls).
  2. Twig Integration:

    • Use {{ render_block('Fully\\Qualified\\Block\\Class') }} for dynamic rendering.
    • Pass options as a hash (e.g., {'key': 'value'}).
  3. Dependency Injection:

    • Inject services (e.g., EntityManager, Twig) via constructor.
    • Example:
      public function __construct(EntityManagerInterface $em) {
          $this->em = $em;
      }
      

Advanced Patterns

  1. Block Inheritance: Create base blocks for shared functionality:

    class BaseContentBlock extends AbstractBlock {
        protected function configureOptions(OptionsResolver $resolver) {
            $resolver->setDefaults([
                'title' => '',
                'content' => '',
                'template' => '@App/Block/base_content.html.twig'
            ]);
        }
    }
    
  2. Dynamic Template Resolution: Override getTemplate() to resolve templates dynamically:

    public function getTemplate() {
        return $this->getSetting('template') ?: '@App/Block/default.html.twig';
    }
    
  3. Block Collections: Group blocks in a parent block for modularity:

    class PageBlock extends AbstractBlock {
        public function execute() {
            $blocks = [
                'header' => $this->renderBlock('HeaderBlock'),
                'content' => $this->renderBlock('ContentBlock'),
            ];
            return $this->renderResponse('@App/Block/page.html.twig', ['blocks' => $blocks]);
        }
    }
    
  4. Caching: Implement isCacheable() and getCacheKey() for static blocks:

    public function isCacheable() {
        return true;
    }
    
    public function getCacheKey() {
        return md5($this->getSetting('slug'));
    }
    

Integration Tips

  1. Symfony Forms: Use blocks to render forms dynamically:

    class LoginBlock extends AbstractBlock {
        public function execute() {
            $form = $this->createForm(LoginType::class);
            return $this->renderResponse('@App/Block/login.html.twig', ['form' => $form->createView()]);
        }
    }
    
  2. API Integration: Fetch remote data in execute():

    public function execute() {
        $data = json_decode(file_get_contents('https://api.example.com/data'), true);
        return $this->renderResponse('@App/Block/api.html.twig', ['data' => $data]);
    }
    
  3. Event Listeners: Trigger events in blocks for cross-cutting concerns:

    public function execute() {
        $this->dispatchEvent('block.pre_render', $this);
        // ...
    }
    
  4. Asset Management: Use blocks to manage CSS/JS:

    class AssetsBlock extends AbstractBlock {
        public function execute() {
            return $this->renderResponse('@App/Block/assets.html.twig', [
                'stylesheets' => $this->getSetting('stylesheets', []),
                'javascripts' => $this->getSetting('javascripts', [])
            ]);
        }
    }
    

Gotchas and Tips

Common Pitfalls

  1. Service Visibility:

    • Forgetting to set public: true for block services will cause render_block() to fail.
    • Fix: Ensure all block services are explicitly marked as public in services.yaml.
  2. Template Paths:

    • Twig templates must be resolvable by Symfony’s template loader. Use @Bundle/Controller/action syntax or full paths.
    • Fix: Verify template paths with {{ dump(render_block('BlockClass').template) }}.
  3. Circular Dependencies:

    • Blocks depending on each other can cause infinite loops if not handled carefully.
    • Fix: Use lazy loading or resolve dependencies in execute().
  4. Options Resolution:

    • Overriding configureOptions() without calling parent::configureOptions() breaks default settings.
    • Fix: Always chain to the parent method:
      protected function configureOptions(OptionsResolver $resolver) {
          parent::configureOptions($resolver);
          // Custom options
      }
      
  5. EntityManager Injection:

    • Forgetting to inject EntityManagerInterface in blocks that query the database.
    • Fix: Add it to the constructor and type-hint it.

Debugging Tips

  1. Block Output: Dump block settings in Twig for debugging:

    {{ dump(render_block('BlockClass').settings) }}
    
  2. Service Existence: Check if a block is registered as a service:

    php bin/console debug:container App\\Block\\BlockClass
    
  3. Template Errors: Use {{ render_block('BlockClass', {'template': 'custom_path'}) }} to test template paths.

  4. Event Debugging: Listen for block events to inspect execution flow:

    services:
        App\EventListener\BlockListener:
            tags:
                - { name: kernel.event_listener, event: block.pre_render, method: onBlockPreRender }
    

Configuration Quirks

  1. Default Template: The bundle does not enforce a default template. Always specify one in configureOptions():

    $resolver->setDefaults(['template' => '@App/Block/default.html.twig']);
    
  2. Options Merging: Options passed to render_block() override defaults but do not merge by default. Use OptionsResolver to handle merging:

    $resolver->setNormalizer('items', function($items, $options) {
        return array_merge($options['default_items'] ?? [], $items);
    });
    
  3. Block Aliases: The bundle does not support aliasing block classes out of the box. Use Symfony’s service aliases if needed:

    services:
        block.hello:
            alias: App\Block\HelloBlock
            public: true
    

Extension Points

  1. Custom Block Types: Extend AbstractBlock to create domain-specific block types (e.g., DatabaseBlock, ApiBlock).

  2. Block Storage: Persist block configurations to a database by implementing BlockInterface and adding a BlockRepository.

  3. Block Events: Dispatch custom events for pre/post-render hooks:

    use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
    
    class MyBlock extends AbstractBlock {
        public function __construct(EventDispatcherInterface $dispatcher) {
            $this->dispatcher = $dispatcher;
        }
    
        public function execute() {
            $this->dispatcher->dispatch(new BlockEvent($this), 'block.my_event');
            // ...
        }
    }
    
  4. Block Security: Add security checks in execute():

    public function execute() {
        if (!$this->isGranted('ROLE_ADMIN')) {
            throw new AccessDeniedException();
        }
        // ...
    
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity