在实体外部使用 UniqueEntity 且不使用表单
Use UniqueEntity outside of entity and without forms
我需要验证用户传递的电子邮件:
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
约束抛出异常:
Warning: get_class()
expects parameter 1 to be object, string given
看起来像 ValidatorInterface::validate()
方法的第一个参数等待实体对象与 getEmail()
方法,但它看起来很难看。
是否有任何优雅的方法来验证仅将标量值传递给 ValidatorInterface::validate()
方法的字段的唯一性?
为此,我将在用户 class 注释中使用 @UniqueEntity(fields={"email"})。像这样:
/**
* @ORM\Entity()
* @ORM\Table(name="user")
* @UniqueEntity(fields={"email"})
*/
似乎没有内置的 Symfony 解决方案来做我想做的事,所以我按照 Jakub Matczak 建议创建了自定义约束。
更新: 当您发送表单来编辑您的实体时,此解决方案会引发验证错误。为避免此行为,您需要手动改进此约束。
限制条件:
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;
}
我需要验证用户传递的电子邮件:
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
约束抛出异常:
Warning:
get_class()
expects parameter 1 to be object, string given
看起来像 ValidatorInterface::validate()
方法的第一个参数等待实体对象与 getEmail()
方法,但它看起来很难看。
是否有任何优雅的方法来验证仅将标量值传递给 ValidatorInterface::validate()
方法的字段的唯一性?
为此,我将在用户 class 注释中使用 @UniqueEntity(fields={"email"})。像这样:
/**
* @ORM\Entity()
* @ORM\Table(name="user")
* @UniqueEntity(fields={"email"})
*/
似乎没有内置的 Symfony 解决方案来做我想做的事,所以我按照 Jakub Matczak 建议创建了自定义约束。
更新: 当您发送表单来编辑您的实体时,此解决方案会引发验证错误。为避免此行为,您需要手动改进此约束。
限制条件:
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;
}