Installation:
composer require a2lix/auto-form-bundle
Enable the bundle in config/bundles.php:
return [
// ...
A2lix\AutoFormBundle\A2lixAutoFormBundle::class => ['all' => true],
];
First Use Case:
Create a simple entity (e.g., src/Entity/User.php):
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class User
{
#[ORM\Id, ORM\GeneratedValue, ORM\Column]
private ?int $id = null;
#[ORM\Column]
private string $name;
#[ORM\Column]
private string $email;
}
Generate a form in a controller:
use A2lix\AutoFormBundle\Form\AutoType;
use Symfony\Component\HttpFoundation\Request;
public function new(Request $request): Response
{
$form = $this->createForm(AutoType::class, new User());
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($form->getData());
$entityManager->flush();
return $this->redirectToRoute('user_index');
}
return $this->render('user/new.html.twig', [
'form' => $form->createView(),
]);
}
Twig Template:
{{ form_start(form) }}
{{ form_widget(form) }}
<button type="submit">Save</button>
{{ form_end(form) }}
Dynamic Form Generation:
Use AutoType to auto-generate forms for any entity or DTO. The bundle infers field types, constraints, and labels from Doctrine annotations/attributes or PHP type hints.
$form = $this->createForm(AutoType::class, $entity, [
'fields' => ['name', 'email'], // Explicitly define fields
'allow_extra_fields' => false, // Disable extra fields
]);
Customization via Configuration: Override default behavior using YAML/XML or PHP:
# config/packages/a2lix_auto_form.yaml
a2lix_auto_form:
form_types:
App\Entity\User:
fields:
name:
type: Symfony\Component\Form\Extension\Core\Type\TextareaType
options:
attr: { class: 'large-input' }
Integration with Symfony Forms: Extend or replace form types dynamically:
use A2lix\AutoFormBundle\Form\AutoType;
use Symfony\Component\Form\FormBuilderInterface;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(\Symfony\Component\Form\FormEvents::PRE_SET_DATA, function ($event) {
$data = $event->getData();
if ($data instanceof User) {
$event->getForm()->add('custom_field', TextType::class);
}
});
}
Handling Collections: AutoForm supports embedded forms and collections:
$form = $this->createForm(AutoType::class, $entity, [
'collections' => [
'roles' => ['entry_type' => RoleType::class],
],
]);
Validation and Constraints:
Leverage Symfony’s validation system. AutoForm respects constraints defined in your entity (e.g., @Assert\Email):
#[ORM\Column]
#[Assert\Email]
private string $email;
Doctrine Integration: AutoForm works seamlessly with Doctrine entities. Ensure your entities are properly mapped (annotations/attributes or XML/YAML).
Translation:
Use A2lix\TranslationFormBundle for multilingual forms. AutoForm supports translation keys via translation_domain option:
$form = $this->createForm(AutoType::class, $entity, [
'translation_domain' => 'messages',
]);
Event Listeners: Attach listeners to modify form behavior dynamically:
$builder->addEventListener(FormEvents::PRE_SET_DATA, function ($event) {
$event->getForm()->add('dynamic_field', TextType::class);
});
Testing:
Test forms with AutoType using Symfony’s form component:
$formFactory = $this->get('form.factory');
$form = $formFactory->create(AutoType::class, new User());
$this->assertCount(2, $form->all());
Circular References:
AutoForm may fail with circular references (e.g., OneToMany/ManyToOne bidirectional associations). Use 'collections' or 'embedded' options carefully:
$form = $this->createForm(AutoType::class, $entity, [
'collections' => ['posts' => ['entry_options' => ['disabled' => true]]],
]);
Field Overrides: Overriding field types in config may not work as expected if the field is not explicitly listed. Always specify fields in the configuration:
a2lix_auto_form:
form_types:
App\Entity\User:
fields:
email: ~ # Explicitly include to override
Doctrine Proxy Issues:
AutoForm may not handle Doctrine proxies well. Use getData() carefully in tests or ensure entities are initialized:
$entity = $entityManager->getRepository(User::class)->find(1);
$entityManager->refresh($entity); // Ensure proxy is initialized
CSRF Token Mismatch: If using AJAX submissions, ensure the CSRF token is included. AutoForm respects Symfony’s default CSRF handling.
Performance with Large Forms: AutoForm generates forms dynamically, which can be slow for entities with many fields. Cache form definitions if needed:
$form = $this->createForm(AutoType::class, $entity, [
'cache_key' => 'user_form_' . $entity->getId(),
]);
Enable Debug Mode:
Set A2LIX_AUTO_FORM_DEBUG: true in .env to log form generation details:
A2LIX_AUTO_FORM_DEBUG=true
Check Generated HTML:
Use Twig’s form_widget with form_errors to debug:
{{ form_widget(form) }}
{% for error in form.errors %}
<div>{{ error.message }}</div>
{% endfor %}
Validate Entity Constraints: AutoForm respects Symfony’s validator. Test constraints separately:
$validator = $this->get('validator');
$errors = $validator->validate($entity);
$this->assertCount(0, $errors);
Custom Field Types: Create a custom form type and register it with AutoForm:
use A2lix\AutoFormBundle\Form\AutoType;
$form = $this->createForm(AutoType::class, $entity, [
'field_types' => [
'App\Entity\CustomFieldType' => CustomFormType::class,
],
]);
Dynamic Field Mapping:
Use field_mapping to customize how properties are mapped to fields:
a2lix_auto_form:
form_types:
App\Entity\User:
field_mapping:
full_name: ['name', 'surname'] # Combine properties
Event Subscribers:
Subscribe to AutoFormEvents to modify form generation:
use A2lix\AutoFormBundle\Event\AutoFormEvents;
use A2lix\AutoFormBundle\Event\AutoFormEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class CustomAutoFormSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
AutoFormEvents::PRE_BUILD => 'onPreBuild',
];
}
public function onPreBuild(AutoFormEvent $event)
{
$event->getFormBuilder()->add('custom_field', TextType::class);
}
}
Override Default Options:
Extend AutoType to change default behavior:
use A2lix\AutoFormBundle\Form\AutoType;
use Symfony\Component\Form\AbstractType;
class CustomAutoType extends AutoType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'allow_extra_fields' => false,
]);
}
}
Use with API Platform: AutoForm integrates well with
How can I help you explore Laravel packages today?