6

我需要验证用户传递的电子邮件:

private function validate($value): bool
{
    $violations = $this->validator->validate($value, [
        new Assert\NotBlank(),
        new Assert\Email(),
        new UniqueEntity([
            'entityClass' => User::class,
            'fields' => 'email',
        ])
    ]);

    return count($violations) === 0;
}

但是UniqueEntity约束抛出异常:

警告:get_class()期望参数 1 是对象,给定字符串

似乎ValidatorInterface::validate()方法的第一个参数正在等待带有getEmail()方法的实体对象,但它看起来很难看。

是否有任何优雅的方法来验证仅将标量值传递给ValidatorInterface::validate()方法的字段的唯一性?

4

2 回答 2

8

似乎没有内置的 Symfony 解决方案来做我想做的事,所以我按照Jakub Matczak 的建议创建了自定义约束。

UPD:当您发送表单以编辑您的实体时,此解决方案会引发验证错误。为避免此行为,您需要手动改进此约束。

约束:

namespace AppBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

class UniqueValueInEntity extends Constraint
{
    public $message = 'This value is already used.';
    public $entityClass;
    public $field;

    public function getRequiredOptions()
    {
        return ['entityClass', 'field'];
    }

    public function getTargets()
    {
        return self::PROPERTY_CONSTRAINT;
    }

    public function validatedBy()
    {
        return get_class($this).'Validator';
    }
} 

验证器:

namespace AppBundle\Validator\Constraints;

use Doctrine\ORM\EntityManager;
use InvalidArgumentException;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class UniqueValueInEntityValidator extends ConstraintValidator
{
    /**
     * @var EntityManager
     */
    private $em;

    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public function validate($value, Constraint $constraint)
    {
        $entityRepository = $this->em->getRepository($constraint->entityClass);

        if (!is_scalar($constraint->field)) {
            throw new InvalidArgumentException('"field" parameter should be any scalar type');
        }

        $searchResults = $entityRepository->findBy([
            $constraint->field => $value
        ]);

        if (count($searchResults) > 0) {
            $this->context->buildViolation($constraint->message)
                ->addViolation();
        }
    }
}

服务:

services:
    app.validator.unique_value_in_entity:
        class: AppBundle\Validator\Constraints\UniqueValueInEntityValidator
        arguments: ['@doctrine.orm.entity_manager']
        tags:
            - { name: validator.constraint_validator }

使用示例:

private function validate($value): bool
{
    $violations = $this->validator->validate($value, [
        new Assert\NotBlank(),
        new Assert\Email(),
        new UniqueValueInEntity([
            'entityClass' => User::class,
            'field' => 'email',
        ])
    ]);

    return count($violations) === 0;
}
于 2017-05-26T12:13:09.003 回答
-1

对于这个建议,我会在用户类注释中使用 @UniqueEntity(fields={"email"}) 。这种方式:

/**
 * @ORM\Entity()
 * @ORM\Table(name="user")
 * @UniqueEntity(fields={"email"})
 */
于 2017-05-26T11:27:07.153 回答