【问题标题】:Symfony2 form validator groups without entitiesSymfony2 没有实体的表单验证器组
【发布时间】:2012-12-11 11:12:14
【问题描述】:

我正在使用 Symfony2 表单组件来构建和验证表单。现在我需要基于单个字段值设置验证器组,不幸的是,似乎每个示例都基于实体 - 由于多种原因,我没有使用它。

示例: 如果 task 为空,则应删除所有约束验证器,但如果不是,则应使用默认的验证器集(或验证器组)。

换句话说,我想要实现的是使子表单成为可选的,但如果填充了关键字段,仍然会被验证。

谁能给我一个如何配置的例子?

<?php
namespace CoreBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Validator\Constraints as Assert;
use CoreBundle\Form\Type\ItemGroupOption;

class ItemGroup extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('title', 'text', array(
            'label' => 'Titel',
            'attr' => array('class' => 'span10 option_rename'),
            'required' => false
        ));
        $builder->add('max_selections', 'integer', array(
            'label' => 'Max tilvalg',
            'constraints' => array(new Assert\Type('int', array('groups' => array('TitleProvided')))),
            'attr' => array('data-default' => 0)
        ));
        $builder->add('allow_multiple', 'choice', array(
            'label' => 'Tillad flere valg',
            'constraints' => array(new Assert\Choice(array(0,1))),
            'choices'  => array(0 => 'Nej', 1 => 'Ja')
        ));
        $builder->add('enable_price', 'choice', array(
            'label' => 'Benyt pris',
            'constraints' => array(new Assert\Choice(array(0,1))),
            'choices'  => array(0 => 'Nej', 1 => 'Ja'),
            'attr' => array('class' => 'option_price')
        ));
        $builder->add('required', 'choice', array(
            'label' => 'Valg påkrævet',
            'constraints' => array(new Assert\Choice(array(0,1))),
            'choices'  => array(0 => 'Nej', 1 => 'Ja')
        ));
        $builder->add('options', 'collection', array(
            'type' => new ItemGroupOption(),
            'allow_add' => true,
            'allow_delete' => true,
            'by_reference' => false
            )
        );
        $builder->add('sort', 'hidden');
    }

    public function getName()
    {
        return 'item_group';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        global $app;

        $resolver->setDefaults(array(
            'validation_groups' => function(FormInterface $form) use ($app) {

                // Get submitted data
                $data = $form->getData();

                if (count($app['validator']->validateValue($data['title'], new Assert\NotBlank())) == 0) {
                    return array('TitleProvided');
                } else {
                    return false;
                }
            },
        ));
    }
}

【问题讨论】:

    标签: php forms validation symfony


    【解决方案1】:

    如果您使用的是 2.1,您可能需要查看 "Groups based on submitted data"

    更新

    在 Symfony 标准版提供的默认 AcmeDemoBundle 中使用演示联系页面 /demo/contact 的示例:

    带有条件验证组的表单类型:

    namespace Acme\DemoBundle\Form;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\Form\FormInterface;
    use Symfony\Component\OptionsResolver\OptionsResolverInterface;
    use Symfony\Component\Validator\Constraints as Assert;
    
    class ContactType extends AbstractType
    {
        // Inject the validator so we can use it in the closure
        /**
         * @var Validator
         */
        private $validator;
    
        /**
         * @param Validator $validator
         */
        public function __construct(Validator $validator)
        {
            $this->validator = $validator;
        }
    
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder->add('email', 'email');
            $builder->add('message', 'textarea', array(
                // Added a constraint that will be applied if an email is provided
                'constraints' => new Assert\NotBlank(array('groups' => array('EmailProvided'))),
            ));
        }
    
        public function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            // This is needed as the closure doesn't have access to $this
            $validator = $this->validator;
    
            $resolver->setDefaults(array(
                'validation_groups' => function(FormInterface $form) use ($validator) {
                    // Get submitted data
                    $data = $form->getData();
                    $email = $data['email'];
    
                    // If email field is filled it will not be blank
                    // Then we add a validation group so we can also check message field
                    if (count($validator->validateValue($email, new Assert\NotBlank())) == 0) {
                        return array('EmailProvided');
                    }
                },
            ));
        }
    
        public function getName()
        {
            return 'contact';
        }
    }
    

    别忘了在表单类型中注入validator服务:

    <?php
    
    namespace Acme\DemoBundle\Controller;
    
    //...
    
    class DemoController extends Controller
    {
        // ...
    
        public function contactAction()
        {
            $form = $this->get('form.factory')->create(new ContactType($this->get('validator')));
    
            // ...
        }
    }
    

    如您所见,只有在填充了 email 字段时才会触发对 message 字段的验证。

    使用差异工具找出差异。

    【讨论】:

    • 正如我在问题中明确指出的那样,我没有使用该示例使用的实体..
    • 使用实体不是强制性的。请参阅闭包示例。它根据表单中提交的数据返回验证组的名称。这意味着您可以使用$form-&gt;getData(); 的内容对其进行任何检查,并根据您的计算返回一个名称。
    • 我理解这个例子,但我不知道如何用一组匹配的约束来提供它以进行验证..
    • iamdto - 我一直在遵循您的指导方针,但我无法让它发挥作用。我已经更新了我在问题中的代码,它“有效”,通过不打扰,而且它总是使用它的约束。知道我做错了什么吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多