本文目录导读:

我来详细介绍 Symfony Form 组件和自定义表单类型的使用。
基础表单类型
常用内置类型
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\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
// 基本表单构建
$form = $this->createFormBuilder()
->add('name', TextType::class, [
'label' => '用户名',
'attr' => ['class' => 'form-control'],
'required' => true
])
->add('email', EmailType::class)
->add('password', PasswordType::class)
->add('gender', ChoiceType::class, [
'choices' => [
'男' => 'male',
'女' => 'female'
]
])
->add('birthday', DateType::class, [
'widget' => 'single_text'
])
->add('avatar', FileType::class)
->add('submit', SubmitType::class, ['label' => '提交'])
->getForm();
自定义表单类型
创建自定义类型类
// src/Form/Type/AddressType.php
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AddressType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('street', TextType::class, [
'label' => '街道'
])
->add('city', TextType::class, [
'label' => '城市'
])
->add('province', ChoiceType::class, [
'label' => '省份',
'choices' => [
'北京' => 'beijing',
'上海' => 'shanghai',
'广东' => 'guangdong',
]
])
->add('postalCode', TextType::class, [
'label' => '邮政编码'
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => null, // 可绑定实体类
'label' => false
]);
}
}
复杂自定义类型
// src/Form/Type/ContactInfoType.php
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TelType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints as Assert;
class ContactInfoType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('emails', CollectionType::class, [
'entry_type' => EmailType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'entry_options' => [
'attr' => ['class' => 'email-input'],
'constraints' => [
new Assert\Email()
]
]
])
->add('phones', CollectionType::class, [
'entry_type' => TelType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true
]);
}
}
数据绑定自定义类型
创建DTO类
// src/DTO/UserRegistrationDTO.php
namespace App\DTO;
use Symfony\Component\Validator\Constraints as Assert;
class UserRegistrationDTO
{
#[Assert\NotBlank]
#[Assert\Length(min: 2, max: 50)]
private string $username;
#[Assert\NotBlank]
#[Assert\Email]
private string $email;
#[Assert\NotBlank]
#[Assert\Length(min: 6)]
private string $password;
private AddressDTO $address;
// Getters and Setters
public function getUsername(): string
{
return $this->username;
}
public function setUsername(string $username): void
{
$this->username = $username;
}
// ... 其他getters/setters
}
绑定DTO到表单
// src/Form/Type/UserRegistrationType.php
namespace App\Form\Type;
use App\DTO\UserRegistrationDTO;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class UserRegistrationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('username', TextType::class, [
'label' => '用户名'
])
->add('email', EmailType::class)
->add('password', RepeatedType::class, [
'type' => PasswordType::class,
'first_options' => ['label' => '密码'],
'second_options' => ['label' => '确认密码'],
'invalid_message' => '密码不匹配'
])
->add('address', AddressType::class, [
'label' => '地址信息'
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => UserRegistrationDTO::class,
'validation_groups' => ['Default', 'registration']
]);
}
}
扩展内置类型
创建更具体类型的扩展
// src/Form/Type/PhoneNumberType.php
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
class PhoneNumberType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'country_code' => '+86',
'attr' => [
'pattern' => '[0-9]{11}',
'maxlength' => 11
]
]);
$resolver->setAllowedTypes('country_code', 'string');
}
public function buildView(FormView $view, FormInterface $form, array $options): void
{
$view->vars['country_code'] = $options['country_code'];
}
public function getParent(): string
{
return TextType::class;
}
}
带AJAX的自定义类型
// src/Form/Type/AjaxSelectType.php
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AjaxSelectType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'ajax_url' => null,
'placeholder' => '请选择...',
'multiple' => false
]);
$resolver->setRequired(['ajax_url']);
}
public function buildView(FormView $view, FormInterface $form, array $options): void
{
$view->vars['ajax_url'] = $options['ajax_url'];
$view->vars['placeholder'] = $options['placeholder'];
$view->vars['multiple'] = $options['multiple'];
}
public function getParent(): string
{
return HiddenType::class;
}
public function getBlockPrefix(): string
{
return 'ajax_select';
}
}
表单主题与渲染
Twig模板主题
{# templates/form/fields.html.twig #}
{% block ajax_select_widget %}
<div class="ajax-select" data-url="{{ ajax_url }}">
<select
id="{{ id }}"
name="{{ full_name }}"
{% if multiple %}multiple="multiple"{% endif %}
class="ajax-select-input"
data-placeholder="{{ placeholder }}">
<option value="{{ value }}">{{ value_label|default(placeholder) }}</option>
</select>
</div>
{% endblock %}
{% block phone_number_widget %}
<div class="input-group">
<span class="input-group-addon">{{ country_code }}</span>
<input
type="tel"
id="{{ id }}"
name="{{ full_name }}"
value="{{ value }}"
class="phone-input"
{{ block('widget_attributes') }}
/>
</div>
{% endblock %}
注册自定义渲染
# config/packages/twig.yaml
twig:
form_themes:
- 'form/fields.html.twig'
实际使用示例
Controller中使用
// src/Controller/RegistrationController.php
namespace App\Controller;
use App\DTO\UserRegistrationDTO;
use App\Form\Type\UserRegistrationType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class RegistrationController extends AbstractController
{
public function register(Request $request): Response
{
$userDTO = new UserRegistrationDTO();
$form = $this->createForm(UserRegistrationType::class, $userDTO);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// 处理注册逻辑
$userData = $form->getData();
// 获取地址数据
$address = $userData->getAddress();
// 保存到数据库等操作
// $this->userService->register($userData);
$this->addFlash('success', '注册成功!');
return $this->redirectToRoute('home');
}
return $this->render('registration/register.html.twig', [
'form' => $form->createView()
]);
}
}
Twig模板
{# templates/registration/register.html.twig #}
{% extends 'base.html.twig' %}
{% block body %}
<div class="container mt-5">
<h1>用户注册</h1>
{{ form_start(form, {'attr': {'novalidate': 'novalidate'}}) }}
<div class="row">
<div class="col-md-6">
{{ form_row(form.username) }}
{{ form_row(form.email) }}
</div>
<div class="col-md-6">
{{ form_row(form.password.first) }}
{{ form_row(form.password.second) }}
</div>
</div>
<div class="address-section">
<h3>地址信息</h3>
{{ form_row(form.address.street) }}
<div class="row">
<div class="col-md-6">
{{ form_row(form.address.city) }}
</div>
<div class="col-md-6">
{{ form_row(form.address.province) }}
</div>
</div>
{{ form_row(form.address.postalCode) }}
</div>
{{ form_end(form) }}
</div>
{% endblock %}
高级功能
事件监听器
// src/Form/EventListener/AddCityFieldListener.php
namespace App\Form\EventListener;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class AddCityFieldListener implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
FormEvents::PRE_SET_DATA => 'onPreSetData',
FormEvents::PRE_SUBMIT => 'onPreSubmit',
];
}
public function onPreSetData(FormEvent $event): void
{
$form = $event->getForm();
$data = $event->getData();
$province = $data ? $data->getProvince() : null;
$this->addCityField($form, $province);
}
public function onPreSubmit(FormEvent $event): void
{
$form = $event->getForm();
$data = $event->getData();
$province = $data['province'] ?? null;
$this->addCityField($form, $province);
}
private function addCityField($form, $province): void
{
$cities = $this->getCitiesForProvince($province);
$form->add('city', ChoiceType::class, [
'choices' => $cities,
'placeholder' => '请选择城市'
]);
}
}
这些示例展示了 Symfony Form 组件和自定义类型的各种用法,你可以根据具体需求进行调整和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播