Symfony2 Collection,子表单验证不起作用

时间:2016-06-29 15:45:14

标签: forms validation symfony

Symfony2.8项目 通过注释NOT YML进行子表单验证 没有实体或学说参与

主窗体通过注释确认。收集字段,子表单无法验证。无论您输入什么内容,当主表单字段有效时,子表单中的每个字段都将作为有效字段传递。

我在网上尝试了很多建议,

' error_bubbling',' cascade_validation'以及@Valid()标记。什么都行不通。

我已将var_dump(...)添加到symfony2代码库中的RangeValidator类,并且未创建/调用它。为了证明它没有被使用,我将一个子表单字段复制到主表单,然后调用框架的验证程序进行范围检查,它应该对子表单中的某些字段执行,而不是。

显然有更多的代码,包括客户端javascript,但下面是一个基本的代码片段(从我的代码中挖出了这个问题):

Main form:

class SubsetAdd extends AbstractType
{
    /**
     * @var string
     *
     * @Assert\NotBlank(
     *        message="Subset name should not be blank"
     * )
     * @Assert\Regex(
     *        pattern="/^[\w\s\d\:\_\-\+]{1,64}$/",
     *        message="Subset name should contain ..."
     * )
     */
    protected $subsetName;


    /**
     * @var string
     *
     * @Assert\Regex(
     *        pattern="/^[\d]{1,4}[Kk]{1}$/",
     *        message="Baud rate should be <n>K"
     * )
     */
    protected $baud;

    /**
     * @Assert\Valid()
     */
    protected $entries;


    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->setMethod('POST');

        $builder->add('subsetName',
            Type\TextType::class,
            array(
                'attr' => array(
                    'title' => 'Subset name string',
                ),
                'required' => true,
                'label' => 'Subset'
            )
        );
        $builder->add('baud', Type\ChoiceType::class, array(
            'label' => 'Baud',
            'attr' => array(
                'title' => 'Baud rate',
                ),
            'placeholder' => 'Select Baud',
            'required' => true,
            'choices' => array('9600'=>'9600','115200'=>'115200'),
            ));

        $builder->add('entries', Type\CollectionType::class, array(
            'label' => 'Entries',
            'type' => Module\EntryType::class,
            'allow_add' => true,
            'allow_delete' => true,
            'required' => true,
            'prototype' => true,
            'prototype_name' => 'entries__name__',
        ));

        if ($options['submit']) {
            // manual debugging aid.  normally client side ajax does the submit so no button required
            $builder->add('submit',Type\SubmitType::class);
        }
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setRequired(array(
            'submit',
        ));

        $resolver->setDefaults(array(
            'submit'=>false,
            'translation_domain' => 'SerialBundle-forms',
        ));
    }

    public function getDefaultOptions(array $options)
    {
        return array(
            'data_class' => __CLASS__,        // this class is the data object the form represents
        );

        return $options;
    }

    public function getName()
    {
        $cn=substr(__CLASS__,(strlen(__NAMESPACE__)>0?1+strlen(__NAMESPACE__):0));    // class name - namespace

        return strtolower(substr($cn,0,1)).substr($cn,1);    // lower case first letter
    }

    public function getBlockPrefix() {
        return $this->getName();
    }

    public function setSubsetName($name)
    {
        $this->subsetName = $name;
        return $this;
    }

    public function getSubsetName()
    {
        return $this->subsetName;
    }

    public function setBaud($baud)
    {
        $this->baud = $baud;
        return $this;
    }

    public function getBaud()
    {
        return $this->baud;
    }

    public function setEntries($entries) {
        $this->entries=$entries;
    }
    public function getEntries() {
        return $this->entries;
    }
}


Subform:

class EntryType extends AbstractType
{
    /**
     * @var string
     *
     * @Assert\Regex(
     *        pattern="/^[\dA-F]+$/",
     *        message="Ident should be hex value"
     * )
     * @Assert\Valid()
     */
    protected $ident;

    /**
     * @var integer
     *
     * @Assert\Range(
     *      min = 0,
     *      max = 64,
     *        minMessage="Start minimum value?",
     *        maxMessage="Start maximum value?"
     * )
     * @Assert\Valid()
     */
    protected $start;

    /**
     * @var integer
     *
     * @Assert\Range(
     *      min = 0,
     *      max = 64,
     *        minMessage="Length minimum value?",
     *        maxMessage="Lenght maximum value?"
     * )
     * @Assert\Valid()
     */
    protected $length;


    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->setMethod('POST');

        $builder->add('ident',
            Type\TextType::class,
            array(
                'attr' => array(
                    'title' => 'Ident value',
                ),
                'required' => true,
                'label' => 'Ident'
            )
        );

        $builder->add('start',
            Type\TextType::class,
            array(
                'attr' => array(
                    'title' => 'Start value',
                ),
                'required' => true,
                'label' => 'Start'
            )
        );

        $builder->add('length',
            Type\TextType::class,
            array(
                'attr' => array(
                    'title' => 'Length value',
                ),
                'required' => true,
                'label' => 'Length'
            )
        );
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setRequired(array(
        ));

        $resolver->setDefaults(array(
            'translation_domain' => 'SerialBundle-forms',
        ));
    }

    public function getDefaultOptions(array $options)
    {
        return array(
            'data_class' => __CLASS__,        // this class is the data object the form represents
        );

        return $options;
    }

    public function getName()
    {
        $cn=substr(__CLASS__,(strlen(__NAMESPACE__)>0?1+strlen(__NAMESPACE__):0));    // class name - namespace

        return strtolower(substr($cn,0,1)).substr($cn,1);    // lower case first letter
    }

    public function getBlockPrefix() {
        return $this->getName();
    }

    public function setIdent($id)
    {
        $this->ident = $id;

        return $this;
    }

    public function getIdent()
    {
        return $this->ident;
    }

    public function setStart($start)
    {
        $this->start = $start;

        return $this;
    }

    public function getStart()
    {
        return $this->start;
    }

    public function setLength($length)
    {
        $this->length = $length;

        return $this;
    }

    public function getLength()
    {
        return $this->length;
    }
}


Basic controller:

class SubsetsController extends Controller
{
    ...

    /**
     * @Route("/add", name="subsets-add")
     * @Method({"GET","POST"})
     */
    public function addFormAction(Request $request)
    {
        $subsetAdd=new ModuleForm\SubsetAdd();

        $options=array(
            'submit'=>false,
        );
        $form = $this->createForm(ModuleForm\SubsetAdd::class, $subsetAdd, $options);

        $form->handleRequest($request);

        if ($form->isSubmitted()) {        
            var_dump('Submitted');
            if ($form->isValid()) {
                var_dump('Valid');

                var_dump("<pre>");
                var_dump($subsetAdd->getEntries());
                var_dump("</pre>");
            }
        }

        return $this->render("SerialBundle:Subsets/form.subsets.html.twig', array(
            'anyerrors' => (($form->isSubmitted() && !$form->isValid())?true:false),
            'form' => $form->createView(),    // invoked after handlerequest
        ));
    }
}

1 个答案:

答案 0 :(得分:1)

如何使用'constraints'=&gt;新的有效()?

 $builder->add('entries', Type\CollectionType::class, array(
        'constraints' => new Valid(),
        'label' => 'Entries',
        'type' => Module\EntryType::class,
        'allow_add' => true,
        'allow_delete' => true,
        'required' => true,
        'prototype' => true,
        'prototype_name' => 'entries__name__',
  ));