表单基础 #
一、表单概述 #
1.1 表单组件 #
Symfony表单组件提供完整的表单处理功能:
text
┌─────────────────────────────────────────────────────┐
│ 表单组件功能 │
├─────────────────────────────────────────────────────┤
│ • 表单创建和配置 │
│ • 自动渲染HTML │
│ • 数据绑定和转换 │
│ • 验证和错误处理 │
│ • CSRF保护 │
│ • 文件上传处理 │
└─────────────────────────────────────────────────────┘
1.2 安装表单组件 #
bash
# 安装表单组件
composer require form validator
# 安装Maker Bundle(用于生成表单)
composer require --dev maker
二、创建表单 #
2.1 使用Maker创建表单 #
bash
# 创建表单类
php bin/console make:form UserType User
# 输出
created: src/Form/UserType.php
2.2 表单类定义 #
php
<?php
namespace App\Form;
use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name')
->add('email')
->add('active')
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}
2.3 控制器中使用表单 #
php
<?php
namespace App\Controller;
use App\Entity\User;
use App\Form\UserType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class UserController extends AbstractController
{
public function new(Request $request, EntityManagerInterface $entityManager): Response
{
$user = new User();
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->persist($user);
$entityManager->flush();
return $this->redirectToRoute('app_user_list');
}
return $this->render('user/new.html.twig', [
'form' => $form,
]);
}
public function edit(Request $request, User $user, EntityManagerInterface $entityManager): Response
{
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->flush();
return $this->redirectToRoute('app_user_list');
}
return $this->render('user/edit.html.twig', [
'form' => $form,
'user' => $user,
]);
}
}
三、渲染表单 #
3.1 基本渲染 #
twig
{# templates/user/new.html.twig #}
{% extends 'base.html.twig' %}
{% block title %}创建用户{% endblock %}
{% block body %}
<h1>创建用户</h1>
{{ form_start(form) }}
{{ form_widget(form) }}
<button type="submit">保存</button>
{{ form_end(form) }}
{% endblock %}
3.2 表单函数 #
twig
{# 完整表单渲染 #}
{{ form(form) }}
{# 分步渲染 #}
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_row(form.name) }}
{{ form_row(form.email) }}
{{ form_row(form.active) }}
<button type="submit">保存</button>
{{ form_end(form) }}
{# 更细粒度控制 #}
{{ form_start(form, {'attr': {'class': 'form'}}) }}
<div class="form-group">
{{ form_label(form.name, '用户名') }}
{{ form_widget(form.name, {'attr': {'class': 'form-control'}}) }}
{{ form_errors(form.name) }}
</div>
<div class="form-group">
{{ form_label(form.email) }}
{{ form_widget(form.email) }}
{{ form_help(form.email) }}
{{ form_errors(form.email) }}
</div>
<button type="submit" class="btn btn-primary">保存</button>
{{ form_end(form) }}
3.3 表单函数说明 #
| 函数 | 说明 |
|---|---|
| form() | 渲染完整表单 |
| form_start() | 渲染表单开始标签 |
| form_end() | 渲染表单结束标签 |
| form_row() | 渲染一行(label + widget + errors) |
| form_label() | 渲染标签 |
| form_widget() | 渲染控件 |
| form_errors() | 渲染错误信息 |
| form_help() | 渲染帮助文本 |
四、表单字段 #
4.1 文本字段 #
php
<?php
$builder
->add('name', TextType::class, [
'label' => '用户名',
'required' => true,
'attr' => [
'placeholder' => '请输入用户名',
'class' => 'form-control',
],
])
->add('email', EmailType::class, [
'label' => '邮箱',
'help' => '请输入有效的邮箱地址',
])
->add('password', PasswordType::class, [
'label' => '密码',
'always_empty' => false,
])
->add('bio', TextareaType::class, [
'label' => '个人简介',
'required' => false,
'attr' => ['rows' => 5],
])
;
4.2 选择字段 #
php
<?php
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
$builder
->add('status', ChoiceType::class, [
'choices' => [
'活跃' => 'active',
'禁用' => 'inactive',
'待审核' => 'pending',
],
'placeholder' => '请选择状态',
])
->add('roles', ChoiceType::class, [
'choices' => [
'管理员' => 'ROLE_ADMIN',
'编辑' => 'ROLE_EDITOR',
'用户' => 'ROLE_USER',
],
'multiple' => true,
'expanded' => true,
])
->add('gender', ChoiceType::class, [
'choices' => [
'男' => 'male',
'女' => 'female',
],
'expanded' => true,
])
;
4.3 日期时间字段 #
php
<?php
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\TimeType;
$builder
->add('birthday', DateType::class, [
'widget' => 'single_text',
'format' => 'yyyy-MM-dd',
'years' => range(date('Y') - 100, date('Y')),
])
->add('publishedAt', DateTimeType::class, [
'widget' => 'single_text',
'html5' => true,
])
->add('openTime', TimeType::class, [
'widget' => 'choice',
'hours' => range(8, 20),
])
;
4.4 数字字段 #
php
<?php
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\RangeType;
$builder
->add('quantity', IntegerType::class, [
'attr' => ['min' => 1, 'max' => 100],
])
->add('price', NumberType::class, [
'scale' => 2,
'attr' => ['step' => '0.01'],
])
->add('rating', RangeType::class, [
'attr' => [
'min' => 1,
'max' => 5,
],
])
;
4.5 文件上传 #
php
<?php
use Symfony\Component\Form\Extension\Core\Type\FileType;
$builder
->add('avatar', FileType::class, [
'label' => '头像',
'mapped' => false,
'required' => false,
'constraints' => [
new File([
'maxSize' => '2M',
'mimeTypes' => [
'image/jpeg',
'image/png',
],
'mimeTypesMessage' => '请上传有效的图片文件',
]),
],
])
;
五、表单选项 #
5.1 常用选项 #
php
<?php
$builder->add('name', TextType::class, [
'label' => '用户名',
'label_attr' => ['class' => 'form-label'],
'required' => true,
'disabled' => false,
'attr' => [
'class' => 'form-control',
'placeholder' => '请输入用户名',
'maxlength' => 100,
],
'help' => '用户名长度为2-100个字符',
'help_attr' => ['class' => 'form-text'],
'data' => '默认值',
'empty_data' => '',
'trim' => true,
'mapped' => true,
'row_attr' => ['class' => 'form-group'],
]);
5.2 表单级选项 #
php
<?php
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => User::class,
'csrf_protection' => true,
'csrf_field_name' => '_token',
'csrf_token_id' => 'user_item',
'attr' => ['class' => 'user-form'],
'method' => 'POST',
'action' => '/user/new',
'validation_groups' => ['Default', 'registration'],
]);
}
六、表单处理 #
6.1 处理流程 #
php
<?php
public function new(Request $request, EntityManagerInterface $entityManager): Response
{
$user = new User();
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$entityManager->persist($user);
$entityManager->flush();
$this->addFlash('success', '用户创建成功');
return $this->redirectToRoute('app_user_list');
}
$this->addFlash('error', '表单验证失败');
}
return $this->render('user/new.html.twig', [
'form' => $form,
]);
}
6.2 获取表单数据 #
php
<?php
public function submit(Request $request): Response
{
$form = $this->createForm(UserType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user = $form->getData();
$name = $form->get('name')->getData();
$email = $form->get('email')->getData();
$allData = $form->all();
$extraField = $form->get('extra_field')?->getData();
}
}
6.3 手动提交表单 #
php
<?php
public function manualSubmit(): Response
{
$user = new User();
$form = $this->createForm(UserType::class, $user);
$form->submit([
'name' => 'John Doe',
'email' => 'john@example.com',
'active' => true,
]);
if ($form->isValid()) {
// 处理数据
}
}
七、表单主题 #
7.1 使用Bootstrap主题 #
yaml
# config/packages/twig.yaml
twig:
form_themes: ['bootstrap_5_layout.html.twig']
7.2 自定义表单主题 #
twig
{# templates/form/fields.html.twig #}
{% block text_widget %}
<input type="text" {{ block('widget_attributes') }} value="{{ value }}" class="custom-input">
{% endblock %}
{% block textarea_widget %}
<textarea {{ block('widget_attributes') }} class="custom-textarea">{{ value }}</textarea>
{% endblock %}
{% block form_row %}
<div class="form-group mb-3">
{{ form_label(form) }}
{{ form_widget(form) }}
{{ form_errors(form) }}
{% if help is defined %}
<small class="form-text text-muted">{{ help }}</small>
{% endif %}
</div>
{% endblock %}
7.3 应用自定义主题 #
twig
{# 在模板中应用 #}
{% form_theme form 'form/fields.html.twig' %}
{{ form(form) }}
八、CSRF保护 #
8.1 自动CSRF保护 #
php
<?php
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'csrf_protection' => true,
'csrf_field_name' => '_token',
'csrf_token_id' => 'user_form',
]);
}
8.2 禁用CSRF保护 #
php
<?php
$form = $this->createForm(UserType::class, $user, [
'csrf_protection' => false,
]);
九、表单事件 #
9.1 表单事件监听 #
php
<?php
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name')
->add('email')
;
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$user = $event->getData();
$form = $event->getForm();
if ($user && $user->getId()) {
$form->add('active', CheckboxType::class, [
'required' => false,
]);
}
});
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
$user = $event->getData();
if ($user->getName()) {
$user->setName(ucfirst($user->getName()));
}
});
}
}
十、总结 #
本章学习了:
- 表单组件概述
- 创建表单类
- 控制器中使用表单
- 渲染表单
- 表单字段类型
- 表单选项配置
- 表单处理流程
- 表单主题
- CSRF保护
- 表单事件
下一章将学习 表单类型。
最后更新:2026-03-28