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.
Installation:
composer require acseo/dynamic-form-bundle (prefer stable version over dev-master).config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3).php bin/console debug:container acseo_dynamic_form.Quick Test:
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()]);
}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_errors(form) }}
{{ form_end(form) }}
First Use Case:
editProfileForm).Array-Based Form Definitions:
config/forms/profile.yml):
profile_form:
fields:
bio:
type: textarea
options:
label: 'About Me'
attr: { rows: 5 }
constraints: [['Length', { max: 500 }]]
$formArray = $this->getParameter('dynamic_forms.profile_form');
$form = $factory->create('profile', $data, $formArray);
Dynamic Form Handling:
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()]);
}
Reusable Components:
money, date) or create custom ones by implementing ACSEO\Bundle\DynamicFormBundle\Form\Type\AbstractType.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();
}
}
Validation & Constraints:
'email' => [
'type' => 'email',
'constraints' => [
['NotBlank'],
['Email'],
['Callback', ['callback' => [$validator, 'customCheck']]]
]
]
Twig Integration:
{% 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 %}
Type Mismatches:
type keys in your array match registered form types (e.g., text, entity, money). Use php bin/console debug:form to list available types.type: 'text' as a fallback.Constraint Syntax:
[['NotBlank']]), not strings or single arrays.php bin/console debug:validator to check constraint formats.Provider Configuration:
acseo_dynamic_form.provider in services.yaml:
services:
App\Provider\DatabaseFormProvider:
tags:
- { name: acseo_dynamic_form.provider, priority: 10 }
CSRF & Form Theming:
{{ form_start(form) }} with csrf_token() or csrf_protection: true in options.form_theme: ['@ACSEODynamicForm/form.html.twig'] in your Twig templates for consistent styling.Performance:
$formArray = $cache->get('form_definition_' . $name, function() use ($provider) {
return $provider->getFormDefinition($name);
});
Dump Form Data:
dump($form->getData());
dump($form->getErrors(true)); // Deep errors
Check Registered Types:
php bin/console debug:container acseo_dynamic_form.type.registry
Validate Schema:
Use Symfony’s Validator to test constraints before rendering:
$validator = $this->get('validator');
$errors = $validator->validate($data, $constraintsFromArray($formArray));
Custom Form Types:
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]);
}
}
services.yaml:
services:
App\Form\Type\CustomType:
tags:
- { name: acseo_dynamic_form.type, type: 'custom' }
Override Default Templates:
vendor/acseo/dynamic-form-bundle/Resources/views/ to templates/bundles/acseodynamicform/ to customize rendering.Event Listeners:
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']);
}
);
How can I help you explore Laravel packages today?