在Symfony2中,我使用自定义约束来验证表单上的一些数据,但是我想知道是否可以从表单中引入一个值来用于验证另一个值?
这是我的约束......
<?php
// src\BizTV\ContainerManagementBundle\Validator\Constraints\ContainerExists.php
namespace BizTV\ContainerManagementBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class ContainerExists extends Constraint
{
public $message = 'Namnet är upptaget, vänligen välj ett annat.';
public function validatedBy()
{
return 'containerExists';
}
}
我的验证员......
<?php
// src\BizTV\ContainerManagementBundle\Validator\Constraints\ContainerExistsValidator.php
namespace BizTV\ContainerManagementBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
use Doctrine\ORM\EntityManager as EntityManager;
class ContainerExistsValidator extends ConstraintValidator
{
private $container;
private $em;
public function __construct(Container $container, EntityManager $em) {
$this->container = $container;
$this->em = $em;
}
public function isValid($value, Constraint $constraint)
{
$em = $this->em;
$container = $this->container;
$company = $this->container->get('security.context')->getToken()->getUser()->getCompany();
//Fetch entities with same name
$repository = $em->getRepository('BizTVContainerManagementBundle:Container');
$query = $repository->createQueryBuilder('c')
->where('c.company = :company')
->setParameter('company', $company)
->orderBy('c.name', 'ASC')
->getQuery();
$containers = $query->getResult();
foreach ($containers as $g) {
if ($g->getName() == $value) {
$this->setMessage('Namnet '.$value.' är upptaget, vänligen välj ett annat', array('%string%' => $value));
return false;
}
}
return true;
}
}
通过服务使用......
services:
biztv.validator.containerExists:
class: BizTV\ContainerManagementBundle\Validator\Constraints\ContainerExistsValidator
arguments: ['@service_container', '@doctrine.orm.entity_manager']
tags:
- { name: validator.constraint_validator, alias: containerExists }
以下是我将这样的方式应用到我的实体......
<?php
namespace BizTV\ContainerManagementBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use BizTV\ContainerManagementBundle\Validator\Constraints as BizTVAssert;
use BizTV\UserBundle\Entity\User as user;
use BizTV\ContainerManagementBundle\Entity\Container as Container;
/**
* BizTV\ContainerManagementBundle\Entity\Container
*
* @ORM\Table(name="container")
* @ORM\Entity
*/
class Container
{
/**
* @var integer $id
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var string $name
* @Assert\NotBlank(message = "Du måste ange ett namn")
* @BizTVAssert\ContainerExists
* @ORM\Column(name="name", type="string", length=255, nullable=true)
*/
private $name;
在我的验证器中,我希望能够完成这样的事情
public function isValid($FORM->OTHERVALUE, $value, Constraint $constraint)
{
$em = $this->em;
$container = $this->container;
$company = $this->container->get('security.context')->getToken()->getUser()->getCompany();
//Fetch entities with same name
$repository = $em->getRepository('BizTVContainerManagementBundle:Container');
$query = $repository->createQueryBuilder('c')
->where('c.company = :company')
->setParameter('company', $company)
->orderBy('c.name', 'ASC')
->getQuery();
$containers = $query->getResult();
if ($g->getName() == $FORM->OTHERVALUE) {
$this->setMessage('Namnet '.$value.' är upptaget, vänligen välj ett annat', array('%string%' => $value));
return false;
}
return true;
}
答案 0 :(得分:12)
您可以创建一个类约束验证器(http://symfony.com/doc/master/cookbook/validation/custom_constraint.html#class-constraint-validator),然后使用它来获取对象本身。
首先,您需要创建一个Constraint类:
class ContainerExists extends Constraint
{
public $message = 'Namnet är upptaget, vänligen välj ett annat.';
public function validatedBy()
{
return 'containerExists';
}
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
}
之后创建验证器本身,您可以访问该对象,而不仅仅是单个属性。
class ContainerExistsValidator extends ConstraintValidator {
private $em;
private $security_context;
public function __construct(EntityManager $entityManager, $security_context) {
$this->security_context = $security_context;
$this->em = $entityManager;
}
public function validate($object, Constraint $constraint) {
// do whatever you want with the object, and if something is wrong add a violation
$this->context->addViolation($constraint->message, array('%string%' => 'something'));
}
}
}
然后创建服务以访问实体管理器和东西:
validator.container_exists:
class: YourBundleName\Validator\Constraints\ContainerExistsValidator
arguments: ["@doctrine.orm.entity_manager", "@security.context"]
tags:
- { name: validator.constraint_validator, alias: containerExists }
在这种情况下,因为类约束验证器应用于类本身,而不是属性,您需要将以下注释添加到类中。
use YourBundleName\Validator\Constraints as BackendAssert;
/**
* @BackendAssert\ContainerExists
*/
答案 1 :(得分:3)
这可能不是您正在寻找的答案,但一种可能的解决方法是使用表单事件进行验证:
$builder->addEventListener(FormEvents::POST_BIND, function (DataEvent $event) {
$form = $event->getForm();
// You can access all form values with $form['value']
if ($form['name'] == $form['OTHERVALUE']) {
$form['name']->addError(new FormError('Your Message'));
}
});
答案 2 :(得分:0)
您希望验证整个实体而不是仅一个字段。您可以使用class constraint validator。现在validate
函数将实体作为第一个参数,您可以使用所有实体字段。
答案 3 :(得分:0)
这可以通过 Assert \ Callback 来完成。在回调中,您可以访问表单值,并可以使用其他值执行检查。这是一个通用的解决方案:
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
public static function authenticate($val1, ExecutionContextInterface $context, $payload)
{
$testVal = null;
$root = $context->getRoot();
if ($root instanceof \Symfony\Component\Form\Form) {
$testVal = $root->getViewData()['testVal'];
if ($testVal < 5){
$context->buildViolation('Please enter a larger value')
->atPath('val1')
->addViolation()
;
}
}
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('val1', TextType::class, [
'constraints' => [
new Assert\Callback([$this, 'authenticate']) //this calls the method above
]
])
->add('testVal', TextType::class)
}
这会将错误与特定输入字段相关联。