Install the Bundle
composer require asmitta-01/formflow-bundle
Enable in config/bundles.php:
Asmitta\FormFlowBundle\AsmittaFormFlowBundle::class => ['all' => true],
Create a Flow Class
Extend FormFlow and define steps in loadStepsConfig():
// src/Form/UserFlow.php
class UserFlow extends FormFlow {
protected function loadStepsConfig(): array {
return [
['label' => 'Step 1', 'form_type' => UserType::class],
['label' => 'Step 2', 'form_type' => UserType::class],
];
}
}
Register as a Service
# config/services.yaml
services:
App\Form\UserFlow:
parent: asmitta.form.flow
Controller Integration Inject the flow and handle steps:
public function handleFlow(UserFlow $flow) {
$user = new User();
$flow->bind($user);
$form = $flow->createForm();
if ($flow->isValid($form)) {
$flow->saveCurrentStepData($form);
if ($flow->nextStep()) {
$form = $flow->createForm(); // Next step
} else {
$flow->reset(); // Done
}
}
return $this->render('template.html.twig', ['form' => $form->createView()]);
}
Template Use the provided buttons template:
{% include '@AsmittaFormFlow/FormFlow/buttons.html.twig' %}
Conditional Field Loading
Use flow_step option in buildForm() to dynamically add fields per step:
public function buildForm(FormBuilderInterface $builder, array $options) {
switch ($options['flow_step']) {
case 1: $builder->add('email'); break;
case 2: $builder->add('address'); break;
}
}
Data Persistence Save step data to session:
$flow->saveCurrentStepData($form);
$stepData = $flow->getStepData(1); // Retrieve later
Validation & Navigation Validate before proceeding:
if ($flow->isValid($form)) {
if ($flow->nextStep()) {
$form = $flow->createForm(); // Auto-refreshes step
}
}
HTTP_UNPROCESSABLE_ENTITY:
return $this->render(..., [], new Response(422));
getStepData():
$user->setFirstName($flow->getStepData(1)['first_name']);
{% include '@AsmittaFormFlow/FormFlow/buttons.html.twig' with {
asmitta_formflow_button_class_next: 'btn btn-primary'
} %}
Session Dependence
$flow->reset() after completion.reset() to avoid stale data.Turbo Conflicts
422 as shown above.Field Mapping
mapped: false) require manual handling via getStepData().Service Registration
parent: asmitta.form.flow in services.yaml will break DI.$flow->getStepData($step) to inspect saved values.loadStepsConfig() returns an array of steps with label and form_type.Custom Flow Logic
Override FormFlow methods like nextStep() or isValid() for custom behavior.
Event Listeners
Dispatch events (e.g., flow.step.change) via Symfony’s event system for cross-cutting concerns.
Template Overrides
Extend the default buttons template (@AsmittaFormFlow/FormFlow/buttons.html.twig) in your theme.
Validation Groups
Use validation_groups in UserType to validate only relevant fields per step:
$builder->add('email', ..., ['validation_groups' => ['step1']]);
How can I help you explore Laravel packages today?