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

Expanded Collection Bundle Laravel Package

abdielcs/expanded-collection-bundle

Symfony 2/3 bundle that renders entity collections as expanded selectable lists (checkboxes). Provides form types extending EntityType, supports OneToMany and ManyToMany relations, configurable displayed fields, and includes a Bootstrap 3 theme example.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require abdielcs/expanded-collection-bundle
    

    Add to AppKernel.php:

    new Abdielcs\ExpandedCollectionBundle\AbdielcsExpandedCollectionBundle(),
    
  2. First Use Case: Replace a standard EntityType field in your form with ExpandedEntityType for a OneToMany or ManyToMany relationship. Example:

    use Abdielcs\ExpandedCollectionBundle\Form\Type\ExpandedEntityType;
    
    $builder->add('tags', ExpandedEntityType::class, [
        'class' => Tag::class,
        'property' => 'name', // Display property
        'expanded' => true,
        'multiple' => true,
        'query_builder' => function (EntityRepository $er) {
            return $er->createQueryBuilder('t')->where('t.active = :active')
                ->setParameter('active', true);
        },
    ]);
    
  3. Template Integration: Override the default template (optional) by copying: vendor/abdielcs/expanded-collection-bundle/Resources/views/Form/expanded_entity_widget.html.twig to templates/Form/expanded_entity_widget.html.twig.


Implementation Patterns

Common Workflows

  1. Basic Expanded Checkbox List: Use ExpandedEntityType for OneToMany or ManyToMany fields where you want a checkbox-based UI instead of a dropdown.

    $builder->add('authors', ExpandedEntityType::class, [
        'class' => Author::class,
        'property' => 'fullName', // Custom getter/method
        'expanded' => true,
        'multiple' => true,
    ]);
    
  2. Dynamic Query Building: Filter entities dynamically using query_builder:

    'query_builder' => function (EntityRepository $er) {
        return $er->createQueryBuilder('e')
            ->where('e.status = :status')
            ->setParameter('status', 'published');
    },
    
  3. Custom Field Rendering: Configure which properties/methods to display and their order:

    'properties' => [
        'name',          // Simple property
        'getFormattedDate', // Custom method
        'price' => ['label' => 'Cost', 'format' => 'currency'], // Custom label + formatting
    ],
    
  4. Bootstrap 3 Integration: Extend the default template to use Bootstrap classes:

    {% extends '::expanded_entity_widget.html.twig' %}
    {% block expanded_entity_widget %}
        <div class="form-group">
            <div class="checkbox">
                {% for child in form.children %}
                    <label>
                        <input type="checkbox" {{ child.vars.value ? 'checked' : '' }}
                               name="{{ form.name }}[]"
                               value="{{ child.vars.value }}">
                        {{ child.vars.data.name }}
                    </label>
                {% endfor %}
            </div>
        </div>
    {% endblock %}
    
  5. Validation and Data Binding: The bundle handles validation and data binding automatically. Ensure your entity methods (e.g., getFormattedDate()) are public and return the expected type.


Gotchas and Tips

Pitfalls

  1. Deprecated Symfony Version:

    • The bundle was last updated in 2016 for Symfony 2/3. Test thoroughly in Symfony 4+ (may require compatibility layers or forks).
    • Workaround: Use a wrapper like symfony/flex or manually patch dependencies.
  2. Template Overrides:

    • Overriding templates requires exact block names (expanded_entity_widget). Misspelling blocks breaks rendering.
    • Debug Tip: Check var/dump(form.vars) in Twig to inspect the rendered data structure.
  3. Query Builder Conflicts:

    • If query_builder is not set, the bundle falls back to the default repository findAll(). For large datasets, always define a query builder to avoid performance issues.
    • Gotcha: Custom DQL in query_builder must return the same entity class as specified in class.
  4. Property vs. Method Ambiguity:

    • The property option expects a public getter method (e.g., getName()) or a direct property (e.g., name). Using a non-existent method throws a PropertyAccessException.
    • Fix: Verify properties/methods exist in your entity with:
      $reflection = new ReflectionClass(YourEntity::class);
      var_dump($reflection->getProperties(), $reflection->getMethods());
      
  5. Bootstrap CSS/JS Dependencies:

    • The bundle’s Bootstrap 3 example assumes you have bootstrap.css loaded. Without it, checkboxes may render incorrectly.
    • Tip: Include Bootstrap via:
      {{ encore_entry_link_tags('app') }} {# if using Webpack Encore #}
      
      or manually:
      <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
      

Debugging Tips

  1. Form Variable Inspection: Dump form variables in Twig to debug rendering:

    {{ dump(form.vars) }}
    

    Look for data, value, and full_name keys.

  2. Symfony Profiler: Use the Profiler to inspect form submissions and entity hydration:

    • Enable profiler in config/packages/dev/debug.yaml:
      framework:
          profiler: { only_exceptions: false }
      
    • Check the Form tab for submitted data.
  3. Entity Hydration Issues: If selected values aren’t saved, ensure:

    • The target entity has a proper setter (e.g., addAuthor(Author $author) for OneToMany).
    • The form field is marked as multiple: true for collections.

Extension Points

  1. Custom Twig Extensions: Extend the bundle’s Twig logic by creating a custom extension:

    // src/Twig/ExpandedCollectionExtension.php
    class ExpandedCollectionExtension extends \Twig_Extension
    {
        public function getFunctions()
        {
            return [
                new \Twig_SimpleFunction('custom_expanded_render', [$this, 'renderCustom']),
            ];
        }
    
        public function renderCustom(FormView $form, array $options)
        {
            // Custom logic here
            return new \Twig_Markup($html);
        }
    }
    

    Register in services.yaml:

    services:
        App\Twig\ExpandedCollectionExtension:
            tags: ['twig.extension']
    
  2. Event Listeners: Hook into form events to modify behavior:

    // src/EventListener/ExpandedCollectionListener.php
    class ExpandedCollectionListener
    {
        public function onPreSetData(FormEvent $event)
        {
            $data = $event->getData();
            if ($data instanceof YourEntity) {
                // Modify data before binding
            }
        }
    }
    

    Register in services.yaml:

    services:
        App\EventListener\ExpandedCollectionListener:
            tags:
                - { name: kernel.event_listener, event: form.pre_set_data, method: onPreSetData }
    
  3. Dynamic Property Mapping: For dynamic property rendering, use a compiler pass to generate getter methods at runtime (advanced):

    // src/DependencyInjection/Compiler/ExpandedPropertyPass.php
    class ExpandedPropertyPass implements CompilerPassInterface
    {
        public function process(ContainerBuilder $container)
        {
            $definition = $container->findDefinition('abdielcs_expanded_collection.templating.helper');
            $definition->addMethodCall('setDynamicProperties', [
                [$this->getDynamicProperties($container)]
            ]);
        }
    }
    
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle