表单类型 #
一、内置表单类型 #
1.1 文本类型 #
php
<?php
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\SearchType;
use Symfony\Component\Form\Extension\Core\Type\UrlType;
use Symfony\Component\Form\Extension\Core\Type\TelType;
$builder
->add('name', TextType::class)
->add('email', EmailType::class)
->add('password', PasswordType::class)
->add('bio', TextareaType::class)
->add('search', SearchType::class)
->add('website', UrlType::class)
->add('phone', TelType::class)
;
1.2 数字类型 #
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;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\Extension\Core\Type\PercentType;
$builder
->add('quantity', IntegerType::class, [
'attr' => ['min' => 0],
])
->add('price', NumberType::class, [
'scale' => 2,
])
->add('rating', RangeType::class, [
'attr' => ['min' => 1, 'max' => 5],
])
->add('amount', MoneyType::class, [
'currency' => 'CNY',
])
->add('discount', PercentType::class, [
'scale' => 2,
])
;
1.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;
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
$builder
->add('eventDate', DateType::class, [
'widget' => 'single_text',
])
->add('startTime', DateTimeType::class, [
'widget' => 'single_text',
])
->add('openTime', TimeType::class, [
'widget' => 'choice',
])
->add('birthday', BirthdayType::class, [
'widget' => 'single_text',
])
;
1.4 选择类型 #
php
<?php
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CountryType;
use Symfony\Component\Form\Extension\Core\Type\CurrencyType;
use Symfony\Component\Form\Extension\Core\Type\LanguageType;
use Symfony\Component\Form\Extension\Core\Type\LocaleType;
use Symfony\Component\Form\Extension\Core\Type\TimezoneType;
$builder
->add('status', ChoiceType::class, [
'choices' => [
'Active' => 'active',
'Inactive' => 'inactive',
],
])
->add('country', CountryType::class)
->add('currency', CurrencyType::class)
->add('language', LanguageType::class)
->add('locale', LocaleType::class)
->add('timezone', TimezoneType::class)
;
1.5 其他类型 #
php
<?php
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\RadioType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\ColorType;
$builder
->add('agreeTerms', CheckboxType::class, [
'required' => true,
])
->add('gender', RadioType::class)
->add('avatar', FileType::class, [
'mapped' => false,
])
->add('token', HiddenType::class)
->add('themeColor', ColorType::class)
;
二、实体字段类型 #
2.1 EntityType #
php
<?php
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
$builder
->add('category', EntityType::class, [
'class' => Category::class,
'choice_label' => 'name',
'placeholder' => '选择分类',
'required' => true,
])
->add('tags', EntityType::class, [
'class' => Tag::class,
'choice_label' => 'name',
'multiple' => true,
'expanded' => true,
])
->add('author', EntityType::class, [
'class' => User::class,
'choice_label' => function (User $user) {
return $user->getFullName();
},
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.active = :active')
->setParameter('active', true)
->orderBy('u.name', 'ASC');
},
])
;
2.2 EntityType选项 #
php
<?php
$builder->add('product', EntityType::class, [
'class' => Product::class,
'choice_label' => 'name',
'choice_value' => 'id',
'choice_name' => 'slug',
'choice_attr' => function (Product $product) {
return ['data-price' => $product->getPrice()];
},
'group_by' => function (Product $product) {
return $product->getCategory()->getName();
},
'preferred_choices' => function (Product $product) {
return $product->isFeatured();
},
'placeholder' => '选择产品',
'required' => true,
'multiple' => false,
'expanded' => false,
]);
三、按钮类型 #
3.1 按钮类型 #
php
<?php
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\ResetType;
$builder
->add('save', SubmitType::class, [
'label' => '保存',
'attr' => ['class' => 'btn btn-primary'],
])
->add('saveAndContinue', SubmitType::class, [
'label' => '保存并继续',
])
->add('reset', ResetType::class, [
'label' => '重置',
])
->add('cancel', ButtonType::class, [
'label' => '取消',
'attr' => ['onclick' => 'history.back()'],
])
;
3.2 处理多个提交按钮 #
php
<?php
public function edit(Request $request, User $user): Response
{
$form = $this->createForm(UserType::class, $user);
$form->add('save', SubmitType::class, ['label' => '保存']);
$form->add('delete', SubmitType::class, ['label' => '删除']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if ($form->get('save')->isClicked()) {
$this->entityManager->flush();
$this->addFlash('success', '用户已更新');
} elseif ($form->get('delete')->isClicked()) {
$this->entityManager->remove($user);
$this->entityManager->flush();
$this->addFlash('success', '用户已删除');
}
return $this->redirectToRoute('app_user_list');
}
return $this->render('user/edit.html.twig', [
'form' => $form,
]);
}
四、表单集合 #
4.1 CollectionType #
php
<?php
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class OrderType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('items', CollectionType::class, [
'entry_type' => OrderItemType::class,
'entry_options' => ['label' => false],
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'prototype' => true,
'prototype_name' => '__name__',
])
;
}
}
4.2 子表单类型 #
php
<?php
class OrderItemType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('product', EntityType::class, [
'class' => Product::class,
'choice_label' => 'name',
])
->add('quantity', IntegerType::class, [
'attr' => ['min' => 1],
])
->add('price', NumberType::class, [
'scale' => 2,
])
;
}
}
4.3 渲染集合 #
twig
{{ form_start(form) }}
<h3>订单项目</h3>
<ul class="order-items" data-prototype="{{ form_widget(form.items.vars.prototype)|e('html_attr') }}">
{% for item in form.items %}
<li>{{ form_row(item) }}</li>
{% endfor %}
</ul>
<button type="button" class="add-item-link">添加项目</button>
<button type="submit">保存订单</button>
{{ form_end(form) }}
<script>
document.querySelector('.add-item-link').addEventListener('click', function() {
const list = document.querySelector('.order-items');
const prototype = list.dataset.prototype;
const index = list.children.length;
const newForm = prototype.replace(/__name__/g, index);
const li = document.createElement('li');
li.innerHTML = newForm;
list.appendChild(li);
});
</script>
五、表单继承 #
5.1 继承表单 #
php
<?php
class BaseUserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name')
->add('email')
;
}
}
class AdminUserType extends BaseUserType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
parent::buildForm($builder, $options);
$builder
->add('roles', ChoiceType::class, [
'multiple' => true,
'choices' => [
'Admin' => 'ROLE_ADMIN',
'Editor' => 'ROLE_EDITOR',
],
])
;
}
}
六、自定义表单类型 #
6.1 创建自定义类型 #
php
<?php
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class TagsType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'attr' => [
'class' => 'tags-input',
'data-role' => 'tagsinput',
],
]);
}
public function getParent(): string
{
return TextType::class;
}
}
6.2 注册自定义类型 #
yaml
# config/services.yaml
services:
App\Form\Type\TagsType:
tags: ['form.type']
6.3 使用自定义类型 #
php
<?php
use App\Form\Type\TagsType;
$builder->add('tags', TagsType::class);
七、数据转换器 #
7.1 创建数据转换器 #
php
<?php
namespace App\Form\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
class TagsTransformer implements DataTransformerInterface
{
public function transform($tags): string
{
if (null === $tags) {
return '';
}
return implode(', ', $tags);
}
public function reverseTransform($string): array
{
if (!$string) {
return [];
}
return array_map('trim', explode(',', $string));
}
}
7.2 使用数据转换器 #
php
<?php
use App\Form\DataTransformer\TagsTransformer;
class ArticleType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('title')
->add('tags', TextType::class)
;
$builder->get('tags')
->addModelTransformer(new TagsTransformer());
}
}
八、表单扩展 #
8.1 创建表单扩展 #
php
<?php
namespace App\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class TextTypeExtension extends AbstractTypeExtension
{
public static function getExtendedTypes(): iterable
{
return [TextType::class];
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'attr' => [
'class' => 'form-control',
],
]);
}
}
8.2 注册扩展 #
yaml
# config/services.yaml
services:
App\Form\Extension\TextTypeExtension:
tags: ['form.type_extension']
九、总结 #
本章学习了:
- 内置表单类型
- EntityType实体字段
- 按钮类型
- CollectionType集合
- 表单继承
- 自定义表单类型
- 数据转换器
- 表单扩展
下一章将学习 表单验证。
最后更新:2026-03-28