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

Formflow Bundle Laravel Package

effiana/formflow-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require craue/formflow-bundle
    

    Enable the bundle in config/bundles.php (Symfony Flex) or AppKernel.php (legacy).

  2. First Use Case: Create a flow controller extending Craue\FormFlowBundle\Controller\FlowController:

    use Craue\FormFlowBundle\Controller\FlowController;
    use Craue\FormFlowBundle\Form\Flow\FormBuilderInterface;
    
    class VehicleFlowController extends FlowController
    {
        public function buildForm(FormBuilderInterface $builder)
        {
            $builder
                ->addStep('vehicle_type', VehicleTypeStep::class)
                ->addStep('vehicle_details', VehicleDetailsStep::class)
                ->addStep('confirmation', ConfirmationStep::class);
        }
    }
    
  3. Define Steps: Create a step class (e.g., VehicleTypeStep) implementing Craue\FormFlowBundle\Form\Flow\Step\StepInterface:

    use Craue\FormFlowBundle\Form\Flow\Step\StepInterface;
    use Symfony\Component\Form\FormBuilderInterface;
    
    class VehicleTypeStep implements StepInterface
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('type', ChoiceType::class, [
                'choices' => ['Car' => 'car', 'Truck' => 'truck'],
            ]);
        }
    
        public function getName()
        {
            return 'vehicle_type';
        }
    }
    
  4. Route the Flow:

    # config/routes.yaml
    vehicle_flow:
        path: /vehicle-flow
        controller: App\Controller\VehicleFlowController::newAction
    

Key Files to Review First

  • src/Form/Flow/Step/ – Step implementations.
  • src/Resources/config/services.xml – Bundle services.
  • demo/ (in repo) – Example flow structure.

Implementation Patterns

Core Workflow

  1. Step Definition:

    • Each step is a class implementing StepInterface with buildForm() and getName().
    • Use FormBuilderInterface to define fields (like Symfony forms).
    • Example:
      $builder->add('make', TextType::class, ['validation_groups' => ['step1']]);
      
  2. Flow Configuration:

    • Dynamic Steps: Use addStep() in buildForm() for linear flows.
    • Conditional Steps: Override getNextStep() in a step to skip steps:
      public function getNextStep($currentStepName, FlowInterface $flow)
      {
          if ($flow->getData('vehicle_type') === 'truck') {
              return 'confirmation'; // Skip details for trucks
          }
          return 'vehicle_details';
      }
      
  3. Data Handling:

    • Access submitted data via $flow->getData() in steps or controllers.
    • Persist data to a model in the final step:
      $vehicle = new Vehicle();
      $vehicle->setType($flow->getData('vehicle_type'));
      $em->persist($vehicle);
      
  4. Validation:

    • Use validation_groups per step:
      $builder->add('model', TextType::class, ['validation_groups' => ['step2']]);
      
    • Define groups in your entity (e.g., @Assert\All({"step1": {...}, "step2": {...}})).
  5. File Uploads:

    • Handle uploads like standard Symfony forms, but clear files on step reset:
      public function reset(FlowInterface $flow)
      {
          $flow->getData()->setUploadedFile(null);
      }
      

Integration Tips

  • Twig Templates: Use {{ form_start(form) }} in a template, but wrap steps in:
    {% for step in flow.steps %}
        {% if step.isCurrent %}
            {{ form_row(form[step.name]) }}
        {% endif %}
    {% endfor %}
    
  • CSRF Protection: The bundle handles CSRF automatically; no extra config needed.
  • Redirects (PRG): Enable in config/packages/craue_formflow.yaml:
    craue_formflow:
        prg: true
    

Gotchas and Tips

Pitfalls

  1. Step Naming Collisions:

    • Ensure getName() returns unique step names (e.g., vehicle_type vs. vehicleType).
    • Debug: Check flow->getSteps() for duplicates.
  2. Data Persistence:

    • Flow data is reset on navigation unless you persist it manually (e.g., to a session or DB).
    • Use FlowInterface::getData() to access current step data.
  3. Validation Groups:

    • Forgetting validation_groups causes all validators to run on every step.
    • Fix: Explicitly define groups per field or step.
  4. File Uploads:

    • Uploaded files are not auto-cleared when resetting the flow.
    • Override reset() in a step to handle cleanup:
      public function reset(FlowInterface $flow)
      {
          if ($flow->getData()->getUploadedFile()) {
              unlink($flow->getData()->getUploadedFile()->getPathname());
          }
      }
      
  5. Dynamic Steps:

    • Adding/removing steps at runtime requires reloading the flow:
      $flow = $this->get('craue_formflow.flow.vehicle_flow');
      $flow->addStep('new_step', NewStep::class);
      

Debugging Tips

  • Log Flow State:
    $this->get('logger')->debug('Current step:', ['step' => $flow->getCurrentStep()->getName()]);
    
  • Check Flow Data: Dump $flow->getData() to verify submitted values.
  • Validate Step Order: Use flow->getSteps() to confirm step sequence matches expectations.

Extension Points

  1. Custom Flow Events: Subscribe to events like craue_formflow.flow.submit:
    $eventDispatcher->addListener('craue_formflow.flow.submit', function (FlowEvent $event) {
        $flow = $event->getFlow();
        // Custom logic before submission
    });
    
  2. Override Flow Controller: Extend FlowController to modify default behavior (e.g., custom storage):
    class CustomFlowController extends FlowController
    {
        protected function getFlowStorage()
        {
            return new DoctrineFlowStorage($this->getDoctrine()->getManager());
        }
    }
    
  3. Add Step Metadata: Use setOption() in buildForm() to attach metadata:
    $builder->addStep('step1', Step1::class)->setOption('label', 'Custom Label');
    
    Access via $step->getOption('label') in templates.

Configuration Quirks

  • PRG Redirects: If prg: true causes infinite loops, ensure your submit route matches the flow’s getSubmitRoute().
  • Session Storage: Default storage is session-based. For stateless flows, implement FlowStorageInterface:
    craue_formflow:
        storage:
            class: App\Service\CustomFlowStorage
    
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.
cocosmos/filament-sticky-save-bar
patrickbussmann/oauth2-apple
3brs/enterprise-security-bundle
anousss007/vigilance
supportpal/eloquent-model
ardenexal/fhir-models
laravel-at/laravel-image-sanitize
romalytar/yammi-audit-log-laravel
ardenexal/fhir-validation
arshaviras/weather-widget
laravel-chronicle/core
sunchayn/nimbus
daikazu/eloquent-salesforce-objects
unseen-codes/chat
romalytar/yammi-jobs-monitoring-laravel
kisame76/filament-db-table-state
nqxcode/laravel-lucene-search
dpfx/laravel-livewire-wizards
workos/workos-php-laravel
sofa/laravel-global-scope