使用另一个表单值验证symfony2表单值

5
在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;
}
4个回答

12

您可以创建一个类约束验证器 (http://symfony.com/doc/master/cookbook/validation/custom_constraint.html#class-constraint-validator),通过这个验证器,您将得到对象本身。

首先,您需要创建一个约束类:

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
 */

Symfony 2.4在这一点上更加灵活。请查看此文章:http://symfony.com/blog/new-in-symfony-2-4-a-better-callback-constraint - Maxooo

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'));

        }

    });

这个要放在我的表格里面还是我的容器类型中? - Matt Welander
是的,或者您可以为字段组合创建一个单独的表单类型,并将其包含在您的表单中。 - Thomas K

1
这可以通过使用 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)
}

这将把错误与特定的输入字段关联起来。

0

看起来你想验证整个实体而不仅仅是一个字段。你可以使用class constraint validator来实现这一点。现在validate函数将实体作为第一个参数,你可以使用所有实体字段。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接