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

Dynamic Form Bundle Laravel Package

acseo/dynamic-form-bundle

Symfony bundle to build dynamic forms from PHP arrays. Define fields, options (label/help/picto/data), constraints (NotBlank, Length, etc.) and render via a form provider. Includes install steps, bundle enablement, and controller example.

View on GitHub
Deep Wiki
Context7

Getting Started

First Steps

  1. Installation:

    • Run composer require acseo/dynamic-form-bundle (prefer stable version over dev-master).
    • Enable the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3).
    • Verify the bundle loads via php bin/console debug:container acseo_dynamic_form.
  2. Quick Test:

    • Create a minimal controller action to render a form from an array definition:
      use ACSEO\Bundle\DynamicFormBundle\Form\DynamicFormFactory;
      
      public function testFormAction(DynamicFormFactory $factory)
      {
          $formArray = [
              'username' => [
                  'type' => 'text',
                  'options' => ['label' => 'Username'],
                  'constraints' => [['NotBlank']]
              ]
          ];
          $form = $factory->createNamed('test_form', null, $formArray);
          return $this->render('form/test.html.twig', ['form' => $form->createView()]);
      }
      
    • Use Twig template:
      {{ form_start(form) }}
          {{ form_widget(form) }}
          {{ form_errors(form) }}
      {{ form_end(form) }}
      
  3. First Use Case:

    • Admin Panel: Dynamically generate forms for CRUD operations (e.g., editProfileForm).
    • User Input: Collect structured data (e.g., surveys, settings) without hardcoding form classes.

Implementation Patterns

Core Workflows

  1. Array-Based Form Definitions:

    • Store form schemas in YAML/JSON (e.g., config/forms/profile.yml):
      profile_form:
          fields:
              bio:
                  type: textarea
                  options:
                      label: 'About Me'
                      attr: { rows: 5 }
                  constraints: [['Length', { max: 500 }]]
      
    • Load via service:
      $formArray = $this->getParameter('dynamic_forms.profile_form');
      $form = $factory->create('profile', $data, $formArray);
      
  2. Dynamic Form Handling:

    • Submitting Data:
      public function submitAction(Request $request, DynamicFormFactory $factory)
      {
          $formArray = [...] // Your schema;
          $form = $factory->create('dynamic_form', null, $formArray);
          $form->handleRequest($request);
          if ($form->isSubmitted() && $form->isValid()) {
              $data = $form->getData();
              // Process $data (e.g., save to DB)
          }
          return $this->render('form/submit.html.twig', ['form' => $form->createView()]);
      }
      
  3. Reusable Components:

    • Form Types: Extend existing types (e.g., money, date) or create custom ones by implementing ACSEO\Bundle\DynamicFormBundle\Form\Type\AbstractType.
    • Providers: Use the DynamicFormProviderInterface to fetch schemas from databases/APIs:
      class DatabaseFormProvider implements DynamicFormProviderInterface
      {
          public function getFormDefinition($name): array
          {
              return $this->entityManager->getRepository(FormSchema::class)
                  ->findOneBy(['name' => $name])->getDefinition();
          }
      }
      
  4. Validation & Constraints:

    • Leverage Symfony’s validation constraints directly in the array:
      'email' => [
          'type' => 'email',
          'constraints' => [
              ['NotBlank'],
              ['Email'],
              ['Callback', ['callback' => [$validator, 'customCheck']]]
          ]
      ]
      
  5. Twig Integration:

    • Access form fields dynamically:
      {% for field in form %}
          <div class="form-group">
              {{ form_label(field) }}
              {{ form_widget(field) }}
              {% if field.errors|length > 0 %}
                  <div class="alert alert-danger">
                      {% for error in field.errors %}
                          {{ error.message }}
                      {% endfor %}
                  </div>
              {% endif %}
          </div>
      {% endfor %}
      

Gotchas and Tips

Common Pitfalls

  1. Type Mismatches:

    • Ensure type keys in your array match registered form types (e.g., text, entity, money). Use php bin/console debug:form to list available types.
    • Fix: Extend the bundle’s type registry or use type: 'text' as a fallback.
  2. Constraint Syntax:

    • Constraints must be arrays of arrays (e.g., [['NotBlank']]), not strings or single arrays.
    • Fix: Validate with php bin/console debug:validator to check constraint formats.
  3. Provider Configuration:

    • If using a custom provider, ensure it’s tagged as acseo_dynamic_form.provider in services.yaml:
      services:
          App\Provider\DatabaseFormProvider:
              tags:
                  - { name: acseo_dynamic_form.provider, priority: 10 }
      
  4. CSRF & Form Theming:

    • Dynamic forms require {{ form_start(form) }} with csrf_token() or csrf_protection: true in options.
    • Tip: Use form_theme: ['@ACSEODynamicForm/form.html.twig'] in your Twig templates for consistent styling.
  5. Performance:

    • Avoid loading large form schemas on every request. Cache definitions:
      $formArray = $cache->get('form_definition_' . $name, function() use ($provider) {
          return $provider->getFormDefinition($name);
      });
      

Debugging Tips

  1. Dump Form Data:

    dump($form->getData());
    dump($form->getErrors(true)); // Deep errors
    
  2. Check Registered Types:

    php bin/console debug:container acseo_dynamic_form.type.registry
    
  3. Validate Schema: Use Symfony’s Validator to test constraints before rendering:

    $validator = $this->get('validator');
    $errors = $validator->validate($data, $constraintsFromArray($formArray));
    

Extension Points

  1. Custom Form Types:

    • Create a new type class:
      namespace App\Form\Type;
      use ACSEO\Bundle\DynamicFormBundle\Form\Type\AbstractType;
      
      class CustomType extends AbstractType
      {
          public function getParent()
          {
              return 'text'; // Extend existing type
          }
          public function configureOptions(OptionsResolver $resolver)
          {
              $resolver->setDefaults(['custom_option' => true]);
          }
      }
      
    • Register it in services.yaml:
      services:
          App\Form\Type\CustomType:
              tags:
                  - { name: acseo_dynamic_form.type, type: 'custom' }
      
  2. Override Default Templates:

    • Copy vendor/acseo/dynamic-form-bundle/Resources/views/ to templates/bundles/acseodynamicform/ to customize rendering.
  3. Event Listeners:

    • Subscribe to acseo_dynamic_form.form.pre_set_data or acseo_dynamic_form.form.post_bind to modify form behavior:
      $eventDispatcher->addListener(
          'acseo_dynamic_form.form.pre_set_data',
          function (FormEvent $event) {
              $event->setData(['default_value' => 'modified']);
          }
      );
      
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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui