Symfony 自定义表单类型中的双重验证错误

Symfony 自定义表单类型中的双重验证错误,symfony,symfony-forms,Symfony,Symfony Forms,我正在实现一个自定义表单类型,它提供一个自动完成字段来选择一个位置(国家、城市或地点)。表单类型创建两个字段,一个文本字段用于自动完成搜索输入,另一个隐藏字段用于保存选定位置的选定id 在文本字段中键入时,会进行服务器调用,并通过jquery自动完成显示结果。如果选择了位置,则所选位置的id将写入隐藏字段,而位置的名称将显示在文本字段中。在服务器上,我使用客户机转换器查找隐藏字段传递的id的实体。文本字段将被忽略 我的模型类定义了一个位置字段,该字段具有一个属性,用于写回使用NotNull验证约

我正在实现一个自定义表单类型,它提供一个自动完成字段来选择一个位置(国家、城市或地点)。表单类型创建两个字段,一个文本字段用于自动完成搜索输入,另一个隐藏字段用于保存选定位置的选定id

在文本字段中键入时,会进行服务器调用,并通过jquery自动完成显示结果。如果选择了位置,则所选位置的id将写入隐藏字段,而位置的名称将显示在文本字段中。在服务器上,我使用客户机转换器查找隐藏字段传递的id的实体。文本字段将被忽略

我的模型类定义了一个位置字段,该字段具有一个属性,用于写回使用NotNull验证约束注释的位置实体

到目前为止,一切正常,但如果我不选择位置,验证消息“此值不应为空。”将显示两次

该捆绑包是公共的,可以在my github repo中找到。相关的类是和和

现在,我将如何将表单类型集成到我的项目中。我添加了全部代码,对不起,太多了;)

在模型中,我将属性定义如下:

class JourneyCreate
{

    /**
     * @Assert\NotNull()
     * @Assert\Choice(choices = {"offer", "request"})
     */
    public $type;

    /**
     * @Assert\NotNull()
     * @Assert\Date()
     */
    public $date;

    /**
     * @Assert\NotNull()
     * @Assert\Time()
     */
    public $time;

    /**
     * @Assert\NotNull()
     *
     */
    public $start;

    /**
     * @Assert\NotNull()
     *
     */
    public $destination;


    public function buildJourney(User $owner)
    {
    switch($this->type)
    {
        case 'offer':
            $journey = new JourneyOffer();
            break;
        case 'request':
            $journey = new JourneyRequest();
            break;
        default:
            throw new \InvalidArgumentException('Invalid journey type');
    }

    $journey->setDate($this->date);
    $journey->setTime($this->time);

    $journey->addStation(new JourneyStation($this->start));
    $journey->addStation(new JourneyStation($this->destination));

    $journey->setOwner($owner);

    return $journey;
    }
}
    class JourneyCreateType extends BaseType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {

    $builder
        ->add('type','choice', array(
            'choices'   => array(
                'offer'   => 'Driver',
                'request' => 'Passanger',
            ),
            'empty_value'=>'',
            'multiple'  => false,
            'expanded'  => true,
        ))
        ->add('date','date',array(
            'widget' => 'single_text',
            'format' => $this->getDateFormat(\IntlDateFormatter::TRADITIONAL),
        ))
        ->add('time','time',array(
            'widget' => 'single_text',
        ))
        ->add('start','room13_geo_location')
        ->add('destination','room13_geo_location')
    ;

    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
    $resolver->setDefaults(array(
        'data_class' => 'Acme\DemoBundle\Form\Model\JourneyCreate',
    ));
    }


    public function getName()
    {
    return 'journey_create';
    }
}
在主窗体中,我添加了如下字段:

class JourneyCreate
{

    /**
     * @Assert\NotNull()
     * @Assert\Choice(choices = {"offer", "request"})
     */
    public $type;

    /**
     * @Assert\NotNull()
     * @Assert\Date()
     */
    public $date;

    /**
     * @Assert\NotNull()
     * @Assert\Time()
     */
    public $time;

    /**
     * @Assert\NotNull()
     *
     */
    public $start;

    /**
     * @Assert\NotNull()
     *
     */
    public $destination;


    public function buildJourney(User $owner)
    {
    switch($this->type)
    {
        case 'offer':
            $journey = new JourneyOffer();
            break;
        case 'request':
            $journey = new JourneyRequest();
            break;
        default:
            throw new \InvalidArgumentException('Invalid journey type');
    }

    $journey->setDate($this->date);
    $journey->setTime($this->time);

    $journey->addStation(new JourneyStation($this->start));
    $journey->addStation(new JourneyStation($this->destination));

    $journey->setOwner($owner);

    return $journey;
    }
}
    class JourneyCreateType extends BaseType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {

    $builder
        ->add('type','choice', array(
            'choices'   => array(
                'offer'   => 'Driver',
                'request' => 'Passanger',
            ),
            'empty_value'=>'',
            'multiple'  => false,
            'expanded'  => true,
        ))
        ->add('date','date',array(
            'widget' => 'single_text',
            'format' => $this->getDateFormat(\IntlDateFormatter::TRADITIONAL),
        ))
        ->add('time','time',array(
            'widget' => 'single_text',
        ))
        ->add('start','room13_geo_location')
        ->add('destination','room13_geo_location')
    ;

    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
    $resolver->setDefaults(array(
        'data_class' => 'Acme\DemoBundle\Form\Model\JourneyCreate',
    ));
    }


    public function getName()
    {
    return 'journey_create';
    }
}
以及控制器代码:

/**
* @Route("/create/{type}", defaults={"type" = null})
* @Template()
*/
public function createAction($type=null)
{

    if($type !== null && !in_array($type,array('request','offer')))
    {
        throw new NotFoundHttpException();
    }

    $journeyCreate = new JourneyCreate();
    $journeyCreate->type = $type;

    $form = $this->createForm(new JourneyCreateType(),$journeyCreate);

    if($this->isPost())
    {
        $form->bind($this->getRequest());

        if($form->isValid())
        {
          $journeyCreate = $form->getData();
          $journey = $journeyCreate->buildJourney($this->getCurrentUser());
          $this->persistAndFlush($journey);
          return $this->redirect($this->generateUrl('acme_demo_journey_edit',array('id'=>$journey->getId())));
        }
    }

    return array(
        'form'  => $form->createView(),
    );
}
最后,显示表单的模板代码:

{% block page_body %}
    <form class="form-horizontal" action="{{ path('acme_demo_journey_create') }}" method="post" novalidate>
    {{form_widget(form)}}
    <div class="form-actions">
        <button class="btn btn-primary" type="submit">{{'form.submit'|trans}}</button>
        <a href="{{path("acme_demo_journey_index")}}" class="btn">{{'form.cancel'|trans}}</a>
    </div>
    </form>
{% endblock %}
{%block page_body%}
{{form_widget(form)}
{{'form.submit'| trans}}
{%endblock%}

我的理论是,这可能是因为我使用了两个表单字段,但不知道如何解决这个问题。欢迎任何关于如何更优雅地解决这个问题的建议。

尽管这个问题看起来很复杂,但答案很简单,只需从小部件模板块中删除{{form_errors(form)}}。因为*form_row*块看起来像:

{% block form_row %}
{% spaceless %}
    <div class="form_row">
        {{ form_label(form) }}
        {{ form_errors(form) }}
        {{ form_widget(form) }}
    </div>
{% endspaceless %}
{% endblock form_row %}
{%block form_row%}
{%spaceless%}
{{form_标签(form)}
{{form_errors(form)}}
{{form_widget(form)}
{%endspaceless%}
{%endblock form_row%}

错误只输出了两次。

您的表单模板是什么样子的,您在做什么来触发验证?@fd8s0我添加了一些更详细的代码,但我认为这与自定义表单类型有关,因为问题也发生在其他表单(例如用户注册)中。