本文目录导读:

我来详细解释 Symfony Form 组件与验证功能的使用方法。
创建表单类
// src/Form/UserType.php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints as Assert;
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('username', TextType::class, [
'label' => '用户名',
'attr' => [
'placeholder' => '请输入用户名',
'class' => 'form-control'
]
])
->add('email', EmailType::class, [
'label' => '邮箱',
'attr' => ['placeholder' => '请输入邮箱']
])
->add('password', PasswordType::class, [
'label' => '密码',
'attr' => ['placeholder' => '请输入密码']
])
->add('submit', SubmitType::class, [
'label' => '提交',
'attr' => ['class' => 'btn btn-primary']
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => User::class,
'validation_groups' => ['Default', 'registration']
]);
}
}
实体类与验证约束
// src/Entity/User.php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity]
class User
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 50)]
#[Assert\NotBlank(message: '用户名不能为空')]
#[Assert\Length(
min: 3,
max: 50,
minMessage: '用户名至少{{ limit }}个字符',
maxMessage: '用户名最多{{ limit }}个字符'
)]
#[Assert\Regex(
pattern: '/^[a-zA-Z0-9_]+$/',
message: '用户名只能包含字母、数字和下划线'
)]
private ?string $username = null;
#[ORM\Column(length: 180, unique: true)]
#[Assert\NotBlank(message: '邮箱不能为空')]
#[Assert\Email(message: '请输入有效的邮箱地址')]
private ?string $email = null;
#[ORM\Column(length: 255)]
#[Assert\NotBlank(message: '密码不能为空')]
#[Assert\Length(
min: 8,
max: 255,
minMessage: '密码至少{{ limit }}个字符'
)]
#[Assert\Regex(
pattern: '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/',
message: '密码必须包含大小写字母和数字'
)]
private ?string $password = null;
// Getters and Setters
public function getId(): ?int { return $this->id; }
public function getUsername(): ?string { return $this->username; }
public function setUsername(string $username): self { $this->username = $username; return $this; }
public function getEmail(): ?string { return $this->email; }
public function setEmail(string $email): self { $this->email = $email; return $this; }
public function getPassword(): ?string { return $this->password; }
public function setPassword(string $password): self { $this->password = $password; return $this; }
}
控制器中使用表单
// src/Controller/UserController.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;
use Symfony\Component\Routing\Annotation\Route;
class UserController extends AbstractController
{
#[Route('/user/new', name: 'user_new')]
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();
$this->addFlash('success', '用户创建成功!');
return $this->redirectToRoute('user_list');
}
return $this->render('user/new.html.twig', [
'form' => $form->createView(),
]);
}
#[Route('/user/{id}/edit', name: 'user_edit')]
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();
$this->addFlash('success', '用户信息已更新!');
return $this->redirectToRoute('user_list');
}
return $this->render('user/edit.html.twig', [
'form' => $form->createView(),
'user' => $user
]);
}
}
自定义验证器
// src/Validator/Constraints/UniqueUser.php
namespace App\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
#[\Attribute]
class UniqueUser extends Constraint
{
public string $message = '该用户名已被使用';
public function validatedBy(): string
{
return static::class.'Validator';
}
}
// src/Validator/Constraints/UniqueUserValidator.php
namespace App\Validator\Constraints;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class UniqueUserValidator extends ConstraintValidator
{
private EntityManagerInterface $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function validate($value, Constraint $constraint): void
{
if (!$constraint instanceof UniqueUser) {
return;
}
$existingUser = $this->entityManager
->getRepository(User::class)
->findOneBy(['username' => $value]);
if ($existingUser) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $value)
->addViolation();
}
}
}
条件验证组
// 在实体中使用验证组
#[ORM\Entity]
class UserRegistration
{
#[Assert\NotBlank(groups: ['registration'])]
#[Assert\Length(min: 3, groups: ['registration'])]
private ?string $username = null;
#[Assert\NotBlank(groups: ['profile'])]
#[Assert\Length(min: 2, groups: ['profile'])]
private ?string $fullName = null;
}
// 在表单中指定验证组
$form = $this->createForm(UserRegistrationType::class, $user, [
'validation_groups' => ['registration', 'Default']
]);
模板中显示表单和错误
{# templates/user/new.html.twig #}
{% extends 'base.html.twig' %}
{% block body %}
<div class="container mt-5">
<h1>创建新用户</h1>
{{ form_start(form, {'attr': {'class': 'needs-validation', 'novalidate': 'novalidate'}}) }}
{% if form_errors(form) %}
<div class="alert alert-danger">
{{ form_errors(form) }}
</div>
{% endif %}
<div class="mb-3">
{{ form_label(form.username, null, {'label_attr': {'class': 'form-label'}}) }}
{{ form_widget(form.username, {'attr': {'class': 'form-control'}}) }}
{% if form_errors(form.username) %}
<div class="invalid-feedback d-block">
{{ form_errors(form.username) }}
</div>
{% endif %}
{{ form_help(form.username) }}
</div>
<div class="mb-3">
{{ form_label(form.email, null, {'label_attr': {'class': 'form-label'}}) }}
{{ form_widget(form.email, {'attr': {'class': 'form-control'}}) }}
{% if form_errors(form.email) %}
<div class="invalid-feedback d-block">
{{ form_errors(form.email) }}
</div>
{% endif %}
</div>
<div class="mb-3">
{{ form_label(form.password, null, {'label_attr': {'class': 'form-label'}}) }}
{{ form_widget(form.password, {'attr': {'class': 'form-control'}}) }}
{% if form_errors(form.password) %}
<div class="invalid-feedback d-block">
{{ form_errors(form.password) }}
</div>
{% endif %}
</div>
{{ form_rest(form) }}
<button type="submit" class="btn btn-primary">提交</button>
{{ form_end(form) }}
</div>
{% endblock %}
自定义验证规则
// 使用回调验证
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
#[Assert\Callback]
public function validate(ExecutionContextInterface $context): void
{
if ($this->password === $this->username) {
$context->buildViolation('密码不能与用户名相同')
->atPath('password')
->addViolation();
}
}
表单事件订阅
// 动态修改表单
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$data = $event->getData();
$form = $event->getForm();
if (isset($data['userType']) && $data['userType'] === 'admin') {
$form->add('adminCode', TextType::class);
}
});
配置 validation.yaml
# config/packages/validator.yaml
framework:
validation:
enabled: true
email_validation_mode: html5
mapping:
paths:
- '%kernel.project_dir%/config/validator/validation.yaml'
Symfony Form 和 Validation 组件提供了强大的表单处理和数据验证功能,能够满足各种复杂的表单需求。