Installation:
composer require b2pweb/bdf-form-bundle
Register the bundle in config/bundles.php:
Bdf\Form\Bundle\FormBundle::class => ['all' => true],
Enable Auto-Configuration:
Add this to config/services.yaml:
services:
_defaults:
autowire: true
autoconfigure: true
App\Form\: resource: './src/Form/*'
First Use Case:
Create a simple form class (src/Form/MyForm.php):
namespace App\Form;
use Bdf\Form\Custom\CustomForm;
use Bdf\Form\Aggregate\FormBuilderInterface;
class MyForm extends CustomForm
{
protected function configure(FormBuilderInterface $builder): void
{
$builder->addText('name', 'Name');
}
}
Use in Controller:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class MyController extends AbstractController
{
public function handle(Request $request)
{
$form = $this->container->get(MyForm::class);
if (!$form->submit($request->request->all())->valid()) {
return new Response('Invalid form');
}
return new Response('Success: ' . $form->value()['name']);
}
}
Form Dependencies: Inject services directly into form constructors (autowired by Symfony).
class MyForm extends CustomForm
{
public function __construct(private MyService $service, ?FormBuilderInterface $builder = null)
{
parent::__construct($builder);
}
}
Builder Patterns:
Use the FormBuilderInterface to dynamically add fields:
protected function configure(FormBuilderInterface $builder): void
{
$builder
->addText('email', 'Email')
->addSubmit('submit', 'Submit');
}
Automatic Form Submission:
Use the #[SubmitForm] attribute to auto-inject and validate forms:
public function submitForm(#[SubmitForm] MyForm $form)
{
$data = $form->value(); // Validated data
}
DTO Binding: Bind form values directly to DTOs:
public function save(#[SubmitForm(form: MyForm::class)] MyDto $dto)
{
$this->service->save($dto);
}
Enable Attributes:
Install b2pweb/bdf-form-attribute and configure in config/packages/form.yaml:
form:
attributes:
compile: true
configuratorClassPrefix: 'GeneratedForm\'
configuratorBasePath: '%kernel.build_dir%/form'
Declare Forms with Attributes:
#[Form]
class MyAttributeForm
{
#[Text('Name')]
public string $name;
#[Submit('Submit')]
public string $submit;
}
Manual Validation:
if (!$form->submit($data)->valid()) {
throw new \RuntimeException($form->error());
}
Automatic Validation with Resolver:
#[SubmitForm(validate: true)] // Throws InvalidFormException on failure
CSRF Protection:
Ensure framework.csrf_protection.enabled: true in config/packages/framework.yaml for secure forms.
Circular Dependencies: Avoid circular dependencies between forms and services. Use interfaces or lazy-loading where needed.
Attribute Compilation:
compile: false in dev/form.yaml to avoid regeneration issues.compile: true for performance.Form Builder Injection:
Always pass ?FormBuilderInterface $builder = null in constructors to maintain compatibility with the parent class.
Form Errors:
Use $form->error() to get detailed validation errors (e.g., for logging or UI feedback).
Generated Code (Attributes):
Clear the cache (php bin/console cache:clear) after changing attribute configurations.
Dependency Issues:
If autowiring fails, explicitly define services in services.yaml:
App\Form\MyForm:
arguments:
$service: '@my_service'
Custom Field Types:
Extend Bdf\Form\Field\FieldInterface to create reusable field types.
Form Events:
Use Symfony’s event system to hook into form lifecycle (e.g., PRE_SUBMIT, POST_SUBMIT).
Dynamic Forms:
Override configure() to build forms dynamically based on runtime logic (e.g., user roles).
Testing:
Mock FormBuilderInterface in tests:
$builder = $this->createMock(FormBuilderInterface::class);
$form = new MyForm($builder);
How can I help you explore Laravel packages today?