本文目录导读:

我来详细介绍 Symfony Form 中的算术验证方法。
基础算术验证方法
使用内置约束
use Symfony\Component\Validator\Constraints as Assert;
class Product
{
#[Assert\Range(
min: 10,
max: 100,
notInRangeMessage: '数值必须在 {{ min }} 到 {{ max }} 之间',
)]
private float $price;
#[Assert\Positive(message: '数值必须为正数')]
#[Assert\LessThan(value: 1000)]
private float $quantity;
}
自定义算术验证器
// src/Validator/ArithmeticValidator.php
namespace App\Validator;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
class ArithmeticValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
if (!$constraint instanceof Arithmetic) {
throw new UnexpectedTypeException($constraint, Arithmetic::class);
}
if (null === $value || '' === $value) {
return;
}
// 自定义算术验证逻辑
if ($value < $constraint->min || $value > $constraint->max) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $value)
->setParameter('{{ min }}', $constraint->min)
->setParameter('{{ max }}', $constraint->max)
->addViolation();
}
}
}
// src/Validator/Arithmetic.php
namespace App\Validator;
use Symfony\Component\Validator\Constraint;
#[Attribute]
class Arithmetic extends Constraint
{
public string $message = '数值 {{ value }} 必须在 {{ min }} 到 {{ max }} 之间';
public float $min = 0;
public float $max = 100;
public function __construct(
?float $min = null,
?float $max = null,
?string $message = null,
?array $groups = null,
$payload = null
) {
parent::__construct($groups, $payload);
$this->min = $min ?? $this->min;
$this->max = $max ?? $this->max;
$this->message = $message ?? $this->message;
}
}
复杂算术验证示例
// src/Form/Type/OrderType.php
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints as Assert;
class OrderType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('quantity', NumberType::class, [
'label' => '数量',
'constraints' => [
new Assert\NotBlank(),
new Assert\Type(['type' => 'numeric', 'message' => '请输入有效的数字']),
]
])
->add('unitPrice', NumberType::class, [
'label' => '单价',
'constraints' => [
new Assert\NotBlank(),
new Assert\Positive(),
]
])
->add('discount', NumberType::class, [
'label' => '折扣率',
'constraints' => [
new Assert\Range([
'min' => 0,
'max' => 100,
'notInRangeMessage' => '折扣率必须在 {{ min }}% 到 {{ max }}% 之间',
])
]
])
->add('submit', SubmitType::class, ['label' => '提交订单']);
// 添加事件监听器进行复杂验证
$builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) {
$data = $event->getData();
$form = $event->getForm();
// 计算总价
$totalPrice = $data->getQuantity() * $data->getUnitPrice() * (1 - $data->getDiscount() / 100);
// 验证总价
if ($totalPrice < 0) {
$form->get('quantity')->addError(new FormError('订单总价不能为负数'));
}
if ($totalPrice > 10000) {
$form->addError(new FormError('订单总价不能超过 10,000 元'));
}
// 验证折扣合理性
if ($data->getDiscount() > 50 && $data->getQuantity() < 10) {
$form->get('discount')->addError(new FormError('小额订单折扣不能超过 50%'));
}
});
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Order::class,
]);
}
}
使用DTO进行高级验证
// src/DTO/ArithmeticDTO.php
namespace App\DTO;
use Symfony\Component\Validator\Constraints as Assert;
class ArithmeticDTO
{
#[Assert\NotBlank]
#[Assert\Type('float')]
private float $value;
#[Assert\NotBlank]
#[Assert\Type('float')]
#[Assert\GreaterThanOrEqual(0)]
private float $percentage;
#[Assert\Callback]
public function validateArithmetic(ExecutionContextInterface $context): void
{
// 检查百分比计算
$calculatedValue = $this->value * ($this->percentage / 100);
if ($calculatedValue > $this->value) {
$context->buildViolation('计算结果不能大于原始值')
->atPath('percentage')
->addViolation();
}
// 检查结果是否合理
if ($calculatedValue < 0) {
$context->buildViolation('计算结果不能为负数')
->atPath('value')
->addViolation();
}
}
}
在表单中使用Callback验证
// src/Form/Type/CalculationType.php
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
class CalculationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('x', NumberType::class)
->add('y', NumberType::class, [
'constraints' => [
new Callback(function ($y, ExecutionContextInterface $context) {
$form = $context->getRoot();
$x = $form->get('x')->getData();
// 验证除法
if ($y !== null && $y == 0 && $x !== null && $x != 0) {
$context->buildViolation('y 不能为零当 x 不为零时')
->addViolation();
}
// 验证百分比
if ($x !== null && $y !== null && $y > $x * 2) {
$context->buildViolation('y 不能超过 x 的两倍')
->addViolation();
}
})
]
]);
}
}
百分比验证示例
// src/Validator/PercentageValidator.php
namespace App\Validator;
class PercentageValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
if (null === $value || '' === $value) {
return;
}
// 限制百分比范围
if ($value < 0 || $value > 100) {
$this->context->buildViolation('百分比必须在 0 到 100 之间')
->setParameter('{{ value }}', $value)
->addViolation();
}
// 检查精度
$decimalPlaces = strlen(substr(strrchr($value, '.'), 1));
if ($decimalPlaces > 2) {
$this->context->buildViolation('百分比最多保留两位小数')
->addViolation();
}
}
}
使用示例
// 在控制器中使用
public function createOrder(Request $request): Response
{
$order = new Order();
$form = $this->createForm(OrderType::class, $order);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// 订单验证通过
$this->entityManager->persist($order);
$this->entityManager->flush();
return $this->redirectToRoute('order_success');
}
return $this->render('order/create.html.twig', [
'form' => $form->createView(),
]);
}
这些方法可以帮助你实现各种算术验证需求,从简单的范围验证到复杂的条件计算验证。