PHP项目Symfony form与旋转验证

wen PHP项目 2

本文目录导读:

PHP项目Symfony form与旋转验证

  1. 创建表单类
  2. 实体类与验证约束
  3. 控制器中使用表单
  4. 自定义验证器
  5. 条件验证组
  6. 模板中显示表单和错误
  7. 自定义验证规则
  8. 表单事件订阅
  9. 配置 validation.yaml

我来详细解释 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 组件提供了强大的表单处理和数据验证功能,能够满足各种复杂的表单需求。

抱歉,评论功能暂时关闭!