Symfony(2.7) - >构建表单 - >将表单中另一个字段的值传递给自定义约束

时间:2016-10-12 11:10:23

标签: php symfony symfony-forms

我想将某个字段的值传递给另一个字段的自定义约束( - >在自定义验证程序中使用它)

表格包含一些字段:

...
            ->add('BsaKey', new \app\...\fieldTypes\RadioButtonType(), [
                'choices' => [
                    ...
                ],
                'expanded' => true,
                'multiple' => false,
                ...
            ])
            ->add('MeteringCodes', 'collection', [
                'type' => new \app\...\formTypes\MeteringCodeType(),
                'allow_add' => true,
                'label' => false,
                'options' => ['label' => $this->lang->get('MeteringCode.Caption')],
                'constraints' => new \app\...\validators\NoIdenticMeteringCodes()
            ])
...

现在我需要将BsaKey的值传递给MeteringCodeType的自定义Constraint:

    class MeteringCodeType extends \Symfony\Component\Form\AbstractType
    {
        public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options)
        {
            $builder->add('meteringCode', 'text', [
                  '...' => '...',
                  'constraints' => new \app\...\MeteringCodeConstraint(['param' => 'VALUE_OF_BsaKey'])
            ]);
        }
    }

我怎样才能实现这个目标?

P.S。我不是整个Symfony,只是一些独立的组件......

编辑:

谢谢,我找到了解决方案:

class MeteringCodeValidator extends \Symfony\Component\Validator\ConstraintValidator
{
    public function validate($value, \Symfony\Component\Validator\Constraint $constraint)
    {
       $BsaKey = $this->context->getRoot()->get('BsaKey')->getData();
       ...
    }
}

似乎独立于“getTargets()”函数返回的选项。

1 个答案:

答案 0 :(得分:0)

我使用custom constraint做了类似的事情。 我检查一个字段比另一个字段大,可以随意根据您的要求进行更改。

示例代码;

<?php
// src/AppBundle/Validator/Constraints/FieldCompare.php
namespace AppBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class FieldCompare extends Constraint
{
    /**
     * Error Message
     * @access public
     * @var string - with placeholders [field1,field2]
     */
    public $message = 'Field field2 must be greater than field1 ';

    /**
     * Form fields
     * @access public
     * @var array 
     */
    public $fields = array();

    /**
     * Class accessors (getters) for the fields.
     * @access public
     * @var array
     */
    public $properties = array();

    /**
     * Error Path
     * @var string 
     */
    public $errorPath;

    public function __construct($options = null)
    {
        parent::__construct($options);

        // check fields is an array
        if (!is_array($this->fields) && !is_string($this->fields)) {
            throw new UnexpectedTypeException($this->fields, 'array');
        }

        // make sure there are two of them
        if (2 != count($this->fields)) {
            throw new ConstraintDefinitionException("Two fields must be specified.");
        }

        // make sure they are strings
        foreach ($this->fields as $f) {
            if (null !== $this->errorPath && !is_int()) {
                throw new UnexpectedTypeException($this->errorPath, 'integer or null');
            }
        }
    }

    /**
     * getTargets()
     * 
     * Set traget (so can be used against the class).
     * @access public
     * @return type
     */
    public function getTargets()
    {
        return self::CLASS_CONSTRAINT;
    }
}

<?php
// src/AppBundle/Validator/Constraints/FieldCompareValidator.php
namespace AppBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class FieldCompareValidator extends ConstraintValidator {

    public function validate($protocol, Constraint $constraint)
    {
        $fields = (array) $constraint->fields;
        $properties = (array) $constraint->properties;

        if ($protocol->$properties[0]() >= $protocol->$properties[1]()) {
            $this->context->addViolationAt($fields[1], $constraint->message, 
                    array(
                        'field1' => $this->prettyField($fields[0]), 
                        'field2' => $this->prettyField($fields[1])
                    ), null);
        }
    }

    private function prettyField($field)
    {
        if (strstr($field, '_')) {
            $pretty = str_replace('_', ' ', $field);
        } else {
            // is camelCase
            $converted = preg_replace('/(?!^)[[:upper:]]+/',' \0', $field);
            if (is_array($converted)) {
                $pretty = implode(' ', $converted);
            } else {
                $pretty = $converted;
            }
        }
        return ucwords($pretty);
    }
}

以下是我如何使用验证器(yaml格式);

AppBundle\Model\Foo:
    constraints:
        - AppBundle\Validator\Constraints\FieldCompare:
            fields: [min_lead_time, max_lead_time]
            properties: [getminLeadtime, getmaxLeadtime]
            groups: [add]