symfony/form
Symfony Form Component helps you build, validate, and process reusable HTML forms with rich field types, data mapping, and CSRF protection. Integrates cleanly with HttpFoundation, Validator, and Twig, but can be used standalone in any PHP app.
Installation:
composer require symfony/form
Laravel developers typically use this via the Symfony Form Component (often bundled with Laravel's HTTP foundation).
First Use Case: Create a simple form in a controller:
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
public function createForm(FormBuilderInterface $builder)
{
return $builder
->add('name', TextType::class)
->add('save', SubmitType::class)
->getForm();
}
Rendering the Form: Use Laravel's Blade templating with Symfony's form rendering:
// In your controller
$form = $this->createForm($builder);
return view('form.example', ['form' => $form->createView()]);
<!-- In Blade (form.example.blade.php) -->
{{ $form->start() }}
{{ $form->widget }}
{{ $form->end() }}
Handling Submission:
public function handleSubmit(Request $request)
{
$form = $this->createForm($builder);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
// Process data...
}
}
Extend built-in types or create custom ones:
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class CustomType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('custom_field', TextType::class);
}
}
Convert between form data and domain objects:
use Symfony\Component\Form\DataTransformerInterface;
class UserToStringTransformer implements DataTransformerInterface
{
public function transform($user)
{
return $user ? $user->getFullName() : '';
}
public function reverseTransform($name)
{
// Logic to find user by name
}
}
Combine with Laravel's validation or Symfony's Validator:
use Symfony\Component\Validator\Constraints as Assert;
$builder->add('email', EmailType::class, [
'constraints' => [new Assert\NotBlank(), new Assert\Email()]
]);
Handle dynamic fields (e.g., nested forms):
$builder->add('tags', CollectionType::class, [
'entry_type' => TextType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
]);
Use events for custom logic:
$form->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$data = $event->getData();
// Pre-process data
});
Use Laravel's FormRequest with Symfony forms:
use Illuminate\Http\Request;
use Symfony\Component\Form\FormFactoryInterface;
public function __construct(FormFactoryInterface $formFactory)
{
$this->formFactory = $formFactory;
}
public function store(Request $request)
{
$form = $this->formFactory->createBuilder()
->add('title', TextType::class)
->getForm();
$form->handleRequest($request);
// ...
}
CSRF Protection:
Ensure CSRF tokens are included in forms (Laravel handles this via @csrf in Blade or Symfony\Bridge\Twig\Extension\FormExtension).
Data Binding:
by_reference: false for collections to avoid shared references.handle_missing_data: true (v8.1+).Validation Errors:
$form->getErrors() or $form->get('field')->getErrors().$form->reset().Session Contamination:
Avoid non-serializable objects in form data (use PRE_SET_DATA listeners to sanitize).
Collection Indices:
Mismatched indices in collections (e.g., tags[0][name] vs tags[1][name]) can cause data loss. Use allow_add: true and prototype: true for dynamic forms.
dd($form->getData(), $form->getErrors(true));
$form->submit($request->request->all());
debug: true mode.AbstractType or use FormTypeExtensionInterface for built-in types.DataTransformerInterface for complex mappings.FormEvents (e.g., PRE_SUBMIT, POST_SUBMIT) for custom logic.Constraint classes or Laravel's validation rules via constraints option.Symfony\Component\Form\FormInterface in Laravel's FormRequest for seamless integration.config/app.php:
'view' => [
'composer' => [
'form' => \Symfony\Bridge\Twig\Extension\FormExtension::class,
],
],
How can I help you explore Laravel packages today?