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


Symfony (2.7) -> Building a form -> pass a value from another field in the form to a custom Constraint

我想传递一些字段的值给另一个字段的自定义约束(->在自定义Validator中使用它)

带有一些字段的表单:

...
            ->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的自定义约束:

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

我怎样才能做到这一点?

注:我不使用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()"函数返回的选项。

我使用自定义约束做了类似的事情。我的检查一个字段大于另一个字段,请随意更改它以满足您的要求。

示例代码;

<?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]